mirror of
https://github.com/systemd/systemd
synced 2024-07-09 04:26:06 +00:00
227ef9bc38
The script wasn't apparently used since the switch to meson, because it required the sys subdirectory to be present in the same subdirectory where the output script is located. Let's use f-strings to make the whole thing more readable. Add some extra checks.
189 lines
5.4 KiB
Python
Executable File
189 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
OUTFILE_HEADER = """#!/usr/bin/env python3
|
|
#
|
|
# create-sys-script.py
|
|
#
|
|
# (C) 2017 Canonical Ltd.
|
|
# Author: Dan Streetman <dan.streetman@canonical.com>
|
|
#
|
|
# systemd is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU Lesser General Public License as published by
|
|
# the Free Software Foundation; either version 2.1 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# systemd is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
"""
|
|
|
|
# Use this only to (re-)create the test/sys-script.py script,
|
|
# after adding or modifying anything in the test/sys/ directory
|
|
|
|
|
|
import os, sys
|
|
import stat
|
|
import tempfile
|
|
import filecmp
|
|
import subprocess
|
|
|
|
OUTFILE_MODE = 0o775
|
|
|
|
OUTFILE_FUNCS = r"""
|
|
import os, sys
|
|
|
|
def d(path, mode):
|
|
os.mkdir(path, mode)
|
|
|
|
def l(path, src):
|
|
os.symlink(src, path)
|
|
|
|
def f(path, mode, contents):
|
|
with open(path, "wb") as f:
|
|
f.write(contents)
|
|
os.chmod(path, mode)
|
|
"""
|
|
|
|
OUTFILE_MAIN = """
|
|
if len(sys.argv) < 2:
|
|
exit("Usage: {} <target dir>".format(sys.argv[0]))
|
|
|
|
if not os.path.isdir(sys.argv[1]):
|
|
exit("Target dir {} not found".format(sys.argv[1]))
|
|
|
|
os.chdir(sys.argv[1])
|
|
|
|
"""
|
|
|
|
|
|
def handle_dir(outfile, path):
|
|
m = os.lstat(path).st_mode & 0o777
|
|
outfile.write(f"d('{path}', {m:#o})\n")
|
|
|
|
|
|
def handle_link(outfile, path):
|
|
src = os.readlink(path)
|
|
outfile.write(f"l('{path}', '{src}')\n")
|
|
|
|
|
|
def escape_single_quotes(b):
|
|
# remove the b'' wrapping each line repr
|
|
r = repr(b)[2:-1]
|
|
# python escapes all ' only if there are ' and " in the string
|
|
if '"' not in r:
|
|
r = r.replace("'", r"\'")
|
|
# return line with all ' escaped
|
|
return r
|
|
|
|
|
|
def handle_file(outfile, path):
|
|
m = os.lstat(path).st_mode & 0o777
|
|
with open(path, "rb") as f:
|
|
b = f.read()
|
|
if b.count(b"\n") > 1:
|
|
r = "\n".join( escape_single_quotes(l) for l in b.split(b"\n") )
|
|
r = f"b'''{r}'''"
|
|
else:
|
|
r = repr(b)
|
|
outfile.write(f"f('{path}', {m:#o}, {r})\n")
|
|
|
|
|
|
def process_sysdir(outfile):
|
|
for (dirpath, dirnames, filenames) in os.walk('sys'):
|
|
handle_dir(outfile, dirpath)
|
|
for d in dirnames:
|
|
path = os.path.join(dirpath, d)
|
|
if stat.S_ISLNK(os.lstat(path).st_mode):
|
|
handle_link(outfile, path)
|
|
for f in filenames:
|
|
path = os.path.join(dirpath, f)
|
|
mode = os.lstat(path).st_mode
|
|
if stat.S_ISLNK(mode):
|
|
handle_link(outfile, path)
|
|
elif stat.S_ISREG(mode):
|
|
handle_file(outfile, path)
|
|
|
|
|
|
def verify_dir(tmpd, path_a):
|
|
path_b = os.path.join(tmpd, path_a)
|
|
mode_a = os.lstat(path_a).st_mode
|
|
mode_b = os.lstat(path_b).st_mode
|
|
if not stat.S_ISDIR(mode_b):
|
|
raise Exception("Not directory")
|
|
if (mode_a & 0o777) != (mode_b & 0o777):
|
|
raise Exception("Permissions mismatch")
|
|
|
|
|
|
def verify_link(tmpd, path_a):
|
|
path_b = os.path.join(tmpd, path_a)
|
|
if not stat.S_ISLNK(os.lstat(path_b).st_mode):
|
|
raise Exception("Not symlink")
|
|
if os.readlink(path_a) != os.readlink(path_b):
|
|
raise Exception("Symlink dest mismatch")
|
|
|
|
|
|
def verify_file(tmpd, path_a):
|
|
path_b = os.path.join(tmpd, path_a)
|
|
mode_a = os.lstat(path_a).st_mode
|
|
mode_b = os.lstat(path_b).st_mode
|
|
if not stat.S_ISREG(mode_b):
|
|
raise Exception("Not file")
|
|
if (mode_a & 0o777) != (mode_b & 0o777):
|
|
raise Exception("Permissions mismatch")
|
|
if not filecmp.cmp(path_a, path_b, shallow=False):
|
|
raise Exception("File contents mismatch")
|
|
|
|
|
|
def verify_script(tmpd):
|
|
any = False
|
|
for (dirpath, dirnames, filenames) in os.walk("sys"):
|
|
any = True
|
|
try:
|
|
path = dirpath
|
|
verify_dir(tmpd, path)
|
|
for d in dirnames:
|
|
path = os.path.join(dirpath, d)
|
|
if stat.S_ISLNK(os.lstat(path).st_mode):
|
|
verify_link(tmpd, path)
|
|
for f in filenames:
|
|
path = os.path.join(dirpath, f)
|
|
mode = os.lstat(path).st_mode
|
|
if stat.S_ISLNK(mode):
|
|
verify_link(tmpd, path)
|
|
elif stat.S_ISREG(mode):
|
|
verify_file(tmpd, path)
|
|
except Exception:
|
|
print(f'FAIL on "{path}"', file=sys.stderr)
|
|
raise
|
|
if not any:
|
|
exit('Nothing found!')
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
exit('Usage: create-sys-script.py /path/to/test/')
|
|
|
|
outfile = os.path.abspath(os.path.dirname(sys.argv[0]) + '/sys-script.py')
|
|
print(f'Creating {outfile} using contents of {sys.argv[1]}/sys')
|
|
|
|
os.chdir(sys.argv[1])
|
|
|
|
with open(outfile, "w") as f:
|
|
os.chmod(outfile, OUTFILE_MODE)
|
|
f.write(OUTFILE_HEADER.replace(os.path.basename(sys.argv[0]),
|
|
os.path.basename(outfile)))
|
|
f.write(OUTFILE_FUNCS)
|
|
f.write(OUTFILE_MAIN)
|
|
process_sysdir(f)
|
|
|
|
with tempfile.TemporaryDirectory() as tmpd:
|
|
print(f'Recreating sys/ using {outfile} at {tmpd}')
|
|
subprocess.check_call([outfile, tmpd])
|
|
verify_script(tmpd)
|
|
|
|
print(f'Verification successful, {outfile} is correct')
|