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