aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/sort.py91
1 files changed, 56 insertions, 35 deletions
diff --git a/contrib/sort.py b/contrib/sort.py
index 6f21370ec..638f14516 100755
--- a/contrib/sort.py
+++ b/contrib/sort.py
@@ -2,48 +2,61 @@
2# This file is part of Firejail project 2# This file is part of Firejail project
3# Copyright (C) 2014-2022 Firejail Authors 3# Copyright (C) 2014-2022 Firejail Authors
4# License GPL v2 4# License GPL v2
5"""
6Sort the items of multi-item options in profiles, the following options are supported:
7 private-bin, private-etc, private-lib, caps.drop, caps.keep, seccomp.drop, seccomp.drop, protocol
8 5
9Usage: 6# Requirements:
10 $ ./sort.py /path/to/profile [ /path/to/profile2 /path/to/profile3 ... ] 7# python >= 3.6
8from os import path
9from sys import argv, exit as sys_exit, stderr
10
11__doc__ = f"""\
12Sort the arguments of commands in profiles.
13
14Usage: {path.basename(argv[0])} [/path/to/profile ...]
15
16The following commands are supported:
17
18 private-bin, private-etc, private-lib, caps.drop, caps.keep, seccomp.drop,
19 seccomp.drop, protocol
20
21Note that this is only applicable to commands that support multiple arguments.
22
11Keep in mind that this will overwrite your profile(s). 23Keep in mind that this will overwrite your profile(s).
12 24
13Examples: 25Examples:
14 $ ./sort.py MyAwesomeProfile.profile 26 $ {argv[0]} MyAwesomeProfile.profile
15 $ ./sort.py new_profile.profile second_new_profile.profile 27 $ {argv[0]} new_profile.profile second_new_profile.profile
16 $ ./sort.py ~/.config/firejail/*.{profile,inc,local} 28 $ {argv[0]} ~/.config/firejail/*.{{profile,inc,local}}
17 $ sudo ./sort.py /etc/firejail/*.{profile,inc,local} 29 $ sudo {argv[0]} /etc/firejail/*.{{profile,inc,local}}
18 30
19Exit-Codes: 31Exit Codes:
20 0: No Error; No Profile Fixed. 32 0: Success: No profiles needed fixing.
21 1: Error, one or more profiles were not processed correctly. 33 1: Error: One or more profiles could not be processed correctly.
22 101: No Error; One or more profile were fixed. 34 2: Error: Missing arguments.
35 101: Info: One or more profiles were fixed.
23""" 36"""
24 37
25# Requirements:
26# python >= 3.6
27from sys import argv, exit as sys_exit
28
29 38
30def sort_alphabetical(raw_items): 39def sort_alphabetical(original_items):
31 items = raw_items.split(",") 40 items = original_items.split(",")
32 items.sort(key=lambda s: s.casefold()) 41 items.sort(key=str.casefold)
33 return ",".join(items) 42 return ",".join(items)
34 43
35 44
36def sort_protocol(protocols): 45def sort_protocol(original_protocols):
37 """sort the given protocols into this scheme: unix,inet,inet6,netlink,packet,bluetooth""" 46 """
47 Sort the given protocols into the following order:
48
49 unix,inet,inet6,netlink,packet,bluetooth
50 """
38 51
39 # shortcut for common protocol lines 52 # shortcut for common protocol lines
40 if protocols in ("unix", "unix,inet,inet6"): 53 if original_protocols in ("unix", "unix,inet,inet6"):
41 return protocols 54 return original_protocols
42 55
43 fixed_protocols = "" 56 fixed_protocols = ""
44 for protocol in ("unix", "inet", "inet6", "netlink", "packet", "bluetooth"): 57 for protocol in ("unix", "inet", "inet6", "netlink", "packet", "bluetooth"):
45 for prefix in ("", "-", "+", "="): 58 for prefix in ("", "-", "+", "="):
46 if f",{prefix}{protocol}," in f",{protocols},": 59 if f",{prefix}{protocol}," in f",{original_protocols},":
47 fixed_protocols += f"{prefix}{protocol}," 60 fixed_protocols += f"{prefix}{protocol},"
48 return fixed_protocols[:-1] 61 return fixed_protocols[:-1]
49 62
@@ -53,7 +66,7 @@ def fix_profile(filename):
53 lines = profile.read().split("\n") 66 lines = profile.read().split("\n")
54 was_fixed = False 67 was_fixed = False
55 fixed_profile = [] 68 fixed_profile = []
56 for lineno, line in enumerate(lines): 69 for lineno, line in enumerate(lines, 1):
57 if line[:12] in ("private-bin ", "private-etc ", "private-lib "): 70 if line[:12] in ("private-bin ", "private-etc ", "private-lib "):
58 fixed_line = f"{line[:12]}{sort_alphabetical(line[12:])}" 71 fixed_line = f"{line[:12]}{sort_alphabetical(line[12:])}"
59 elif line[:13] in ("seccomp.drop ", "seccomp.keep "): 72 elif line[:13] in ("seccomp.drop ", "seccomp.keep "):
@@ -69,8 +82,8 @@ def fix_profile(filename):
69 if fixed_line != line: 82 if fixed_line != line:
70 was_fixed = True 83 was_fixed = True
71 print( 84 print(
72 f"{filename}:{lineno + 1}:-{line}\n" 85 f"{filename}:{lineno}:-{line}\n"
73 f"{filename}:{lineno + 1}:+{fixed_line}" 86 f"{filename}:{lineno}:+{fixed_line}"
74 ) 87 )
75 fixed_profile.append(fixed_line) 88 fixed_profile.append(fixed_line)
76 if was_fixed: 89 if was_fixed:
@@ -84,22 +97,30 @@ def fix_profile(filename):
84 97
85 98
86def main(args): 99def main(args):
100 if len(args) < 1:
101 print(__doc__, file=stderr)
102 return 2
103
104 print(f"sort.py: checking {len(args)} profile(s)...")
105
87 exit_code = 0 106 exit_code = 0
88 print(f"sort.py: checking {len(args)} {'profiles' if len(args) != 1 else 'profile'}...")
89 for filename in args: 107 for filename in args:
90 try: 108 try:
91 if exit_code not in (1, 101): 109 if exit_code not in (1, 101):
92 exit_code = fix_profile(filename) 110 exit_code = fix_profile(filename)
93 else: 111 else:
94 fix_profile(filename) 112 fix_profile(filename)
95 except FileNotFoundError: 113 except FileNotFoundError as err:
96 print(f"[ Error ] Can't find `{filename}'") 114 print(f"[ Error ] {err}", file=stderr)
97 exit_code = 1 115 exit_code = 1
98 except PermissionError: 116 except PermissionError as err:
99 print(f"[ Error ] Can't read/write `{filename}'") 117 print(f"[ Error ] {err}", file=stderr)
100 exit_code = 1 118 exit_code = 1
101 except Exception as err: 119 except Exception as err:
102 print(f"[ Error ] An error occurred while processing `{filename}': {err}") 120 print(
121 f"[ Error ] An error occurred while processing '{filename}': {err}",
122 file=stderr,
123 )
103 exit_code = 1 124 exit_code = 1
104 return exit_code 125 return exit_code
105 126