blob: 49735c8710226db70c113d23c29804d354e239bd [file] [log] [blame]
Austin Schuh0bd410a2023-11-05 12:38:12 -08001#!/usr/bin/python3
2
3import contextlib
4import datetime
5import pathlib
6import subprocess
7import shlex
8import os
9import sys
10
11REQUIRED_DEPS = ["debootstrap"]
12
13ROOTFS_FOLDER = "/tmp/rootfs"
14
15
16@contextlib.contextmanager
17def scoped_bind_mount(partition):
18 """Bind mounts a folder from the host into the rootfs."""
19 result = subprocess.run(
20 ["sudo", "mount", "--bind", partition, f"{ROOTFS_FOLDER}/{partition}"],
21 check=True)
22
23 try:
24 yield partition
25 finally:
26 subprocess.run(["sudo", "umount", f"{ROOTFS_FOLDER}/{partition}"],
27 check=True)
28
29
30def check_required_deps(deps):
31 """Checks if the provided list of dependencies is installed."""
32 missing_deps = []
33 for dep in deps:
34 result = subprocess.run(["dpkg-query", "-W", "-f='${Status}'", dep],
35 check=True,
36 stdout=subprocess.PIPE)
37
38 if "install ok installed" not in result.stdout.decode('utf-8'):
39 missing_deps.append(dep)
40
41 if len(missing_deps) > 0:
42 print("Missing dependencies, please install:")
43 print("sudo apt-get install", " ".join(missing_deps))
44 return True
45
46 return False
47
48
49def target_unescaped(cmd):
50 """Runs a command as root with bash -c cmd, ie without escaping."""
51 subprocess.run([
52 "sudo", "chroot", "--userspec=0:0", f"{ROOTFS_FOLDER}", "/bin/bash",
53 "-c", cmd
54 ],
55 check=True)
56
57
58def target(cmd):
59 """Runs a command as root with escaping."""
60 target_unescaped(shlex.join([shlex.quote(c) for c in cmd]))
61
62
63def copyfile(owner, permissions, file):
64 """Copies a file from contents/{file} with the provided owner and permissions."""
65 print("copyfile", owner, permissions, file)
66 subprocess.run(
67 ["sudo", "cp", f"contents/{file}", f"{ROOTFS_FOLDER}/{file}"],
68 check=True)
69 subprocess.run(["sudo", "chmod", permissions, f"{ROOTFS_FOLDER}/{file}"],
70 check=True)
71 target(["chown", owner, f"/{file}"])
72
73
74def target_symlink(owner, permissions, link_target, linkname):
75 full_linkname = f"{ROOTFS_FOLDER}/{linkname}"
76 print(link_target)
77 print(full_linkname)
78 if not os.path.exists(full_linkname):
79 target(["ln", "-s", link_target, linkname])
80
81 assert (pathlib.Path(full_linkname).is_symlink())
82
83 target(["chown", owner, linkname])
84 target(["chmod", permissions, linkname])
85
86
87def target_mkdir(owner_group, permissions, folder):
88 """Creates a directory recursively with the provided permissions and ownership."""
89 print("target_mkdir", owner_group, permissions, folder)
90 owner, group = owner_group.split('.')
91 target(
92 ["install", "-d", "-m", permissions, "-o", owner, "-g", group, folder])
93
94
95def main():
96 if check_required_deps(REQUIRED_DEPS):
97 return 1
98
99 new_image = not os.path.exists(ROOTFS_FOLDER)
100 if new_image:
101 os.mkdir(ROOTFS_FOLDER)
102
103 if new_image:
104 subprocess.run([
105 "sudo", "debootstrap", "--no-check-gpg", "bookworm", ROOTFS_FOLDER,
106 "http://deb.debian.org/debian/"
107 ],
108 check=True)
109
110 if not os.path.exists(
111 f"{ROOTFS_FOLDER}/etc/apt/sources.list.d/bullseye-backports.list"):
112 copyfile("root.root", "644",
113 "etc/apt/sources.list.d/bullseye-backports.list")
114 target(["apt-get", "update"])
115
116 with scoped_bind_mount("/dev") as _:
117 with scoped_bind_mount("/proc") as _:
118 target([
119 "apt-get",
120 "-y",
121 "install",
122 "libopencv-calib3d406",
123 "libopencv-contrib406",
124 "libopencv-core406",
125 "libopencv-features2d406",
126 "libopencv-flann406",
127 "libopencv-highgui406",
128 "libopencv-imgcodecs406",
129 "libopencv-imgproc406",
130 "libopencv-ml406",
131 "libopencv-objdetect406",
132 "libopencv-photo406",
133 "libopencv-shape406",
134 "libopencv-stitching406",
135 "libopencv-superres406",
136 "libopencv-video406",
137 "libopencv-videoio406",
138 "libopencv-videostab406",
139 "libopencv-viz406",
140 "libv4l-dev",
141 "libc6-dev",
142 "libstdc++-12-dev",
143 "nvidia-cuda-dev",
144 "nvidia-cuda-toolkit",
145 ])
146
147 target_mkdir("root.root", "755", "usr/lib/cuda/bin")
148 target_symlink("root.root", "555", "../../../bin/fatbinary",
149 "usr/lib/cuda/bin/x86_64-unknown-linux-gnu-fatbinary")
150
151 target(["apt-get", "clean"])
152
153 target(["ldconfig"])
154
155 tarball = datetime.date.today().strftime(
156 f"{os.getcwd()}/%Y-%m-%d-bookworm-amd64-nvidia-rootfs.tar")
157 print(tarball)
158
159 subprocess.run([
160 "sudo",
161 "tar",
162 "--exclude=./usr/share/ca-certificates",
163 "--exclude=./usr/src",
164 "--exclude=./usr/lib/mesa-diverted",
165 "--exclude=./usr/bin/X11",
166 "--exclude=./usr/lib/systemd/system/system-systemd*cryptsetup.slice",
167 "--exclude=./dev",
Austin Schuh1fc0d482023-12-24 14:40:34 -0800168 "--exclude=./usr/include/cub",
169 "--exclude=./usr/include/nv",
170 "--exclude=./usr/include/thrust",
171 "--exclude=./usr/include/cuda",
Austin Schuh0bd410a2023-11-05 12:38:12 -0800172 "-cf",
173 tarball,
174 ".",
175 ],
176 cwd=ROOTFS_FOLDER,
177 check=True)
178
179 subprocess.run(["sha256sum", tarball], check=True)
180
181 return 0
182
183
184if __name__ == '__main__':
185 sys.exit(main())