blob: 24a00f7a93c9e96edc1c170b8865725fd043079d [file] [log] [blame]
Jörg Thalheim3e67e5c2017-05-01 02:26:56 +02001#!/usr/bin/env python3
Dan Streetmand001ac22017-02-10 15:27:18 -05002
Jörg Thalheim3e67e5c2017-05-01 02:26:56 +02003OUTFILE_HEADER = """#!/usr/bin/env python3
Dan Streetmand001ac22017-02-10 15:27:18 -05004#
5# create-sys-script.py
6#
7# (C) 2017 Canonical Ltd.
8# Author: Dan Streetman <dan.streetman@canonical.com>
9#
10# systemd is free software; you can redistribute it and/or modify it
11# under the terms of the GNU Lesser General Public License as published by
12# the Free Software Foundation; either version 2.1 of the License, or
13# (at your option) any later version.
14#
15# systemd is distributed in the hope that it will be useful, but
16# WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18# Lesser General Public License for more details.
19#
20# You should have received a copy of the GNU Lesser General Public License
21# along with systemd; If not, see <http://www.gnu.org/licenses/>.
22#
23"""
24
25# Use this only to (re-)create the test/sys-script.py script,
26# after adding or modifying anything in the test/sys/ directory
27
28
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020029import os, sys
30import stat
31import tempfile
32import filecmp
33import subprocess
Dan Streetmand001ac22017-02-10 15:27:18 -050034
Dan Streetmand001ac22017-02-10 15:27:18 -050035OUTFILE_MODE = 0o775
36
37OUTFILE_FUNCS = r"""
38import os, sys
39
40def d(path, mode):
41 os.mkdir(path, mode)
42
43def l(path, src):
44 os.symlink(src, path)
45
46def f(path, mode, contents):
47 with open(path, "wb") as f:
48 f.write(contents)
49 os.chmod(path, mode)
Dan Streetmand001ac22017-02-10 15:27:18 -050050"""
51
52OUTFILE_MAIN = """
53if len(sys.argv) < 2:
54 exit("Usage: {} <target dir>".format(sys.argv[0]))
55
56if not os.path.isdir(sys.argv[1]):
57 exit("Target dir {} not found".format(sys.argv[1]))
58
59os.chdir(sys.argv[1])
60
61"""
62
63
64def handle_dir(outfile, path):
65 m = os.lstat(path).st_mode & 0o777
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020066 outfile.write(f"d('{path}', {m:#o})\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050067
68
69def handle_link(outfile, path):
70 src = os.readlink(path)
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020071 outfile.write(f"l('{path}', '{src}')\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050072
73
74def escape_single_quotes(b):
75 # remove the b'' wrapping each line repr
76 r = repr(b)[2:-1]
77 # python escapes all ' only if there are ' and " in the string
78 if '"' not in r:
79 r = r.replace("'", r"\'")
80 # return line with all ' escaped
81 return r
82
83
84def handle_file(outfile, path):
85 m = os.lstat(path).st_mode & 0o777
86 with open(path, "rb") as f:
87 b = f.read()
88 if b.count(b"\n") > 1:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020089 r = "\n".join( escape_single_quotes(l) for l in b.split(b"\n") )
90 r = f"b'''{r}'''"
Dan Streetmand001ac22017-02-10 15:27:18 -050091 else:
92 r = repr(b)
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020093 outfile.write(f"f('{path}', {m:#o}, {r})\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050094
95
96def process_sysdir(outfile):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020097 for (dirpath, dirnames, filenames) in os.walk('sys'):
Dan Streetmand001ac22017-02-10 15:27:18 -050098 handle_dir(outfile, dirpath)
99 for d in dirnames:
100 path = os.path.join(dirpath, d)
101 if stat.S_ISLNK(os.lstat(path).st_mode):
102 handle_link(outfile, path)
103 for f in filenames:
104 path = os.path.join(dirpath, f)
105 mode = os.lstat(path).st_mode
106 if stat.S_ISLNK(mode):
107 handle_link(outfile, path)
108 elif stat.S_ISREG(mode):
109 handle_file(outfile, path)
110
111
112def verify_dir(tmpd, path_a):
113 path_b = os.path.join(tmpd, path_a)
114 mode_a = os.lstat(path_a).st_mode
115 mode_b = os.lstat(path_b).st_mode
116 if not stat.S_ISDIR(mode_b):
117 raise Exception("Not directory")
118 if (mode_a & 0o777) != (mode_b & 0o777):
119 raise Exception("Permissions mismatch")
120
121
122def verify_link(tmpd, path_a):
123 path_b = os.path.join(tmpd, path_a)
124 if not stat.S_ISLNK(os.lstat(path_b).st_mode):
125 raise Exception("Not symlink")
126 if os.readlink(path_a) != os.readlink(path_b):
127 raise Exception("Symlink dest mismatch")
128
129
130def verify_file(tmpd, path_a):
131 path_b = os.path.join(tmpd, path_a)
132 mode_a = os.lstat(path_a).st_mode
133 mode_b = os.lstat(path_b).st_mode
134 if not stat.S_ISREG(mode_b):
135 raise Exception("Not file")
136 if (mode_a & 0o777) != (mode_b & 0o777):
137 raise Exception("Permissions mismatch")
138 if not filecmp.cmp(path_a, path_b, shallow=False):
139 raise Exception("File contents mismatch")
140
141
142def verify_script(tmpd):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200143 any = False
Dan Streetmand001ac22017-02-10 15:27:18 -0500144 for (dirpath, dirnames, filenames) in os.walk("sys"):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200145 any = True
Dan Streetmand001ac22017-02-10 15:27:18 -0500146 try:
147 path = dirpath
148 verify_dir(tmpd, path)
149 for d in dirnames:
150 path = os.path.join(dirpath, d)
151 if stat.S_ISLNK(os.lstat(path).st_mode):
152 verify_link(tmpd, path)
153 for f in filenames:
154 path = os.path.join(dirpath, f)
155 mode = os.lstat(path).st_mode
156 if stat.S_ISLNK(mode):
157 verify_link(tmpd, path)
158 elif stat.S_ISREG(mode):
159 verify_file(tmpd, path)
160 except Exception:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200161 print(f'FAIL on "{path}"', file=sys.stderr)
Dan Streetmand001ac22017-02-10 15:27:18 -0500162 raise
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200163 if not any:
164 exit('Nothing found!')
Dan Streetmand001ac22017-02-10 15:27:18 -0500165
166if __name__ == "__main__":
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200167 if len(sys.argv) < 2:
168 exit('Usage: create-sys-script.py /path/to/test/')
Dan Streetmand001ac22017-02-10 15:27:18 -0500169
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200170 outfile = os.path.abspath(os.path.dirname(sys.argv[0]) + '/sys-script.py')
171 print(f'Creating {outfile} using contents of {sys.argv[1]}/sys')
Dan Streetmand001ac22017-02-10 15:27:18 -0500172
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200173 os.chdir(sys.argv[1])
Dan Streetmand001ac22017-02-10 15:27:18 -0500174
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200175 with open(outfile, "w") as f:
176 os.chmod(outfile, OUTFILE_MODE)
177 f.write(OUTFILE_HEADER.replace(os.path.basename(sys.argv[0]),
178 os.path.basename(outfile)))
Dan Streetmand001ac22017-02-10 15:27:18 -0500179 f.write(OUTFILE_FUNCS)
180 f.write(OUTFILE_MAIN)
181 process_sysdir(f)
182
183 with tempfile.TemporaryDirectory() as tmpd:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200184 print(f'Recreating sys/ using {outfile} at {tmpd}')
185 subprocess.check_call([outfile, tmpd])
Dan Streetmand001ac22017-02-10 15:27:18 -0500186 verify_script(tmpd)
187
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200188 print(f'Verification successful, {outfile} is correct')