blob: e25f3b4f8f069748ade9c866a6461ddcca7e9ffa [file] [log] [blame]
Jörg Thalheim3e67e5c2017-05-01 02:26:56 +02001#!/usr/bin/env python3
Zbigniew Jędrzejewski-Szmek35df7442017-11-18 17:32:46 +01002# SPDX-License-Identifier: LGPL-2.1+
Dan Streetmand001ac22017-02-10 15:27:18 -05003
Jörg Thalheim3e67e5c2017-05-01 02:26:56 +02004OUTFILE_HEADER = """#!/usr/bin/env python3
Zbigniew Jędrzejewski-Szmek35df7442017-11-18 17:32:46 +01005# SPDX-License-Identifier: LGPL-2.1+
Dan Streetmand001ac22017-02-10 15:27:18 -05006#
7# create-sys-script.py
8#
9# (C) 2017 Canonical Ltd.
10# Author: Dan Streetman <dan.streetman@canonical.com>
11#
12# systemd is free software; you can redistribute it and/or modify it
13# under the terms of the GNU Lesser General Public License as published by
14# the Free Software Foundation; either version 2.1 of the License, or
15# (at your option) any later version.
16#
17# systemd is distributed in the hope that it will be useful, but
18# WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20# Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with systemd; If not, see <http://www.gnu.org/licenses/>.
24#
25"""
26
27# Use this only to (re-)create the test/sys-script.py script,
28# after adding or modifying anything in the test/sys/ directory
29
30
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020031import os, sys
32import stat
33import tempfile
34import filecmp
35import subprocess
Dan Streetmand001ac22017-02-10 15:27:18 -050036
Dan Streetmand001ac22017-02-10 15:27:18 -050037OUTFILE_MODE = 0o775
38
39OUTFILE_FUNCS = r"""
40import os, sys
Zbigniew Jędrzejewski-Szmek0bca7952017-09-29 12:28:25 +020041import shutil
Dan Streetmand001ac22017-02-10 15:27:18 -050042
43def d(path, mode):
44 os.mkdir(path, mode)
45
46def l(path, src):
47 os.symlink(src, path)
48
49def f(path, mode, contents):
50 with open(path, "wb") as f:
51 f.write(contents)
52 os.chmod(path, mode)
Dan Streetmand001ac22017-02-10 15:27:18 -050053"""
54
55OUTFILE_MAIN = """
56if len(sys.argv) < 2:
57 exit("Usage: {} <target dir>".format(sys.argv[0]))
58
59if not os.path.isdir(sys.argv[1]):
60 exit("Target dir {} not found".format(sys.argv[1]))
61
62os.chdir(sys.argv[1])
63
Zbigniew Jędrzejewski-Szmek0bca7952017-09-29 12:28:25 +020064if os.path.exists('sys'):
65 shutil.rmtree('sys')
Dan Streetmand001ac22017-02-10 15:27:18 -050066"""
67
68
69def handle_dir(outfile, path):
70 m = os.lstat(path).st_mode & 0o777
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020071 outfile.write(f"d('{path}', {m:#o})\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050072
73
74def handle_link(outfile, path):
75 src = os.readlink(path)
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020076 outfile.write(f"l('{path}', '{src}')\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050077
78
79def escape_single_quotes(b):
80 # remove the b'' wrapping each line repr
81 r = repr(b)[2:-1]
82 # python escapes all ' only if there are ' and " in the string
83 if '"' not in r:
84 r = r.replace("'", r"\'")
85 # return line with all ' escaped
86 return r
87
88
89def handle_file(outfile, path):
90 m = os.lstat(path).st_mode & 0o777
91 with open(path, "rb") as f:
92 b = f.read()
93 if b.count(b"\n") > 1:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020094 r = "\n".join( escape_single_quotes(l) for l in b.split(b"\n") )
95 r = f"b'''{r}'''"
Dan Streetmand001ac22017-02-10 15:27:18 -050096 else:
97 r = repr(b)
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +020098 outfile.write(f"f('{path}', {m:#o}, {r})\n")
Dan Streetmand001ac22017-02-10 15:27:18 -050099
100
101def process_sysdir(outfile):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200102 for (dirpath, dirnames, filenames) in os.walk('sys'):
Dan Streetmand001ac22017-02-10 15:27:18 -0500103 handle_dir(outfile, dirpath)
104 for d in dirnames:
105 path = os.path.join(dirpath, d)
106 if stat.S_ISLNK(os.lstat(path).st_mode):
107 handle_link(outfile, path)
108 for f in filenames:
109 path = os.path.join(dirpath, f)
110 mode = os.lstat(path).st_mode
111 if stat.S_ISLNK(mode):
112 handle_link(outfile, path)
113 elif stat.S_ISREG(mode):
114 handle_file(outfile, path)
115
116
117def verify_dir(tmpd, path_a):
118 path_b = os.path.join(tmpd, path_a)
119 mode_a = os.lstat(path_a).st_mode
120 mode_b = os.lstat(path_b).st_mode
121 if not stat.S_ISDIR(mode_b):
122 raise Exception("Not directory")
123 if (mode_a & 0o777) != (mode_b & 0o777):
124 raise Exception("Permissions mismatch")
125
126
127def verify_link(tmpd, path_a):
128 path_b = os.path.join(tmpd, path_a)
129 if not stat.S_ISLNK(os.lstat(path_b).st_mode):
130 raise Exception("Not symlink")
131 if os.readlink(path_a) != os.readlink(path_b):
132 raise Exception("Symlink dest mismatch")
133
134
135def verify_file(tmpd, path_a):
136 path_b = os.path.join(tmpd, path_a)
137 mode_a = os.lstat(path_a).st_mode
138 mode_b = os.lstat(path_b).st_mode
139 if not stat.S_ISREG(mode_b):
140 raise Exception("Not file")
141 if (mode_a & 0o777) != (mode_b & 0o777):
142 raise Exception("Permissions mismatch")
143 if not filecmp.cmp(path_a, path_b, shallow=False):
144 raise Exception("File contents mismatch")
145
146
147def verify_script(tmpd):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200148 any = False
Dan Streetmand001ac22017-02-10 15:27:18 -0500149 for (dirpath, dirnames, filenames) in os.walk("sys"):
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200150 any = True
Dan Streetmand001ac22017-02-10 15:27:18 -0500151 try:
152 path = dirpath
153 verify_dir(tmpd, path)
154 for d in dirnames:
155 path = os.path.join(dirpath, d)
156 if stat.S_ISLNK(os.lstat(path).st_mode):
157 verify_link(tmpd, path)
158 for f in filenames:
159 path = os.path.join(dirpath, f)
160 mode = os.lstat(path).st_mode
161 if stat.S_ISLNK(mode):
162 verify_link(tmpd, path)
163 elif stat.S_ISREG(mode):
164 verify_file(tmpd, path)
165 except Exception:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200166 print(f'FAIL on "{path}"', file=sys.stderr)
Dan Streetmand001ac22017-02-10 15:27:18 -0500167 raise
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200168 if not any:
169 exit('Nothing found!')
Dan Streetmand001ac22017-02-10 15:27:18 -0500170
171if __name__ == "__main__":
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200172 if len(sys.argv) < 2:
173 exit('Usage: create-sys-script.py /path/to/test/')
Dan Streetmand001ac22017-02-10 15:27:18 -0500174
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200175 outfile = os.path.abspath(os.path.dirname(sys.argv[0]) + '/sys-script.py')
176 print(f'Creating {outfile} using contents of {sys.argv[1]}/sys')
Dan Streetmand001ac22017-02-10 15:27:18 -0500177
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200178 os.chdir(sys.argv[1])
Dan Streetmand001ac22017-02-10 15:27:18 -0500179
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200180 with open(outfile, "w") as f:
181 os.chmod(outfile, OUTFILE_MODE)
182 f.write(OUTFILE_HEADER.replace(os.path.basename(sys.argv[0]),
183 os.path.basename(outfile)))
Dan Streetmand001ac22017-02-10 15:27:18 -0500184 f.write(OUTFILE_FUNCS)
185 f.write(OUTFILE_MAIN)
186 process_sysdir(f)
187
188 with tempfile.TemporaryDirectory() as tmpd:
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200189 print(f'Recreating sys/ using {outfile} at {tmpd}')
190 subprocess.check_call([outfile, tmpd])
Dan Streetmand001ac22017-02-10 15:27:18 -0500191 verify_script(tmpd)
192
Zbigniew Jędrzejewski-Szmek227ef9b2017-09-29 12:27:21 +0200193 print(f'Verification successful, {outfile} is correct')