2 * Copyright (c) 2019-2022 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * This code uses concepts and configuration based on 'synth', by
8 * John R. Marino <draco@marino.st>, which was written in ada.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
20 * 3. Neither the name of The DragonFly Project nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific, prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static void domount(worker_t
*work
, int type
,
40 const char *spath
, const char *dpath
,
41 const char *discretefmt
);
42 static void dounmount(worker_t
*work
, const char *rpath
);
43 static void makeDiscreteCopies(const char *spath
, const char *discretefmt
);
46 * Called by the frontend to create a template which will be cpdup'd
49 * Template must have been previously destroyed. Errors are fatal
52 DoCreateTemplate(int force
)
57 const char *reason
= "";
63 asprintf(&goodbuf
, "%s/.template.good", BuildBase
);
66 * Conditionally create the template and discrete copies of certain
67 * directories if we think we are missing things.
70 reason
= " (Asked to force template creation)";
74 asprintf(&buf
, "%s/Template", BuildBase
);
75 if (stat(buf
, &st
) < 0) {
77 reason
= " (Template file missing)";
82 * Check to see if the worker count changed and some
83 * template dirs are missing or out of date, and also if
84 * a new world was installed (via /bin/ls mtime).
86 asprintf(&buf
, "%s/bin/ls", SystemPath
);
87 if (stat(buf
, &st
) < 0)
88 dfatal_errno("Unable to locate %s", buf
);
90 ls_mtime
= st
.st_mtime
;
92 for (n
= 0; n
< MaxWorkers
; ++n
) {
93 asprintf(&buf
, "%s/bin.%03d/ls", BuildBase
, n
);
94 if (stat(buf
, &st
) < 0 || st
.st_mtime
!= ls_mtime
) {
96 reason
= " (/bin/ls mtime mismatch)";
101 if (stat(goodbuf
, &st
) < 0) {
103 reason
= " (.template.good file missing)";
107 dlog(DLOG_ALL
, "Check Template: %s%s\n",
108 (force
? "Must-Create" : "Good"),
112 * Create the template
115 remove(goodbuf
); /* ignore exit code */
118 asprintf(&buf
, "%s/mktemplate %s %s/Template",
119 SCRIPTPATH(SCRIPTDIR
), SystemPath
, BuildBase
);
122 dfatal("Command failed: %s\n", buf
);
123 dlog(DLOG_ALL
| DLOG_FILTER
,
124 "Template - rc=%d running %s\n", rc
, buf
);
128 * Make discrete copies of certain extremely heavily used
129 * but small directories.
131 makeDiscreteCopies("$/bin", "/bin.%03d");
132 makeDiscreteCopies("$/lib", "/lib.%03d");
133 makeDiscreteCopies("$/libexec", "/libexec.%03d");
134 makeDiscreteCopies("$/usr/bin", "/usr.bin.%03d");
137 * Mark the template good... ah, do a sync() to really
138 * be sure that it can't get corrupted.
141 fd
= open(goodbuf
, O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
142 dassert_errno(fd
>= 0, "could not create %s", goodbuf
);
145 dlog(DLOG_ALL
| DLOG_FILTER
, "Template - done\n");
153 DoDestroyTemplate(void)
161 * NOTE: rm -rf safety, use a fixed name 'Template' to ensure we
162 * do not accidently blow something up.
164 asprintf(&path
, "%s/Template", BuildBase
);
165 if (stat(path
, &st
) == 0) {
166 asprintf(&buf
, "chflags -R noschg %s; /bin/rm -rf %s",
170 dfatal("Command failed: %s (ignored)\n", buf
);
177 * Called by the worker support thread to install a new worker
178 * filesystem topology.
181 DoWorkerMounts(worker_t
*work
)
187 * Generate required mounts, domount() will mkdir() the target
188 * directory if necessary and prefix spath with SystemPath if
191 setNumaDomain(work
->index
);
192 domount(work
, TMPFS_RW
, "dummy", "", NULL
);
193 asprintf(&buf
, "%s/usr", work
->basedir
);
194 if (mkdir(buf
, 0755) != 0) {
195 fprintf(stderr
, "Command failed: mkdir %s\n", buf
);
200 domount(work
, NULLFS_RO
, "$/boot", "/boot", NULL
);
201 domount(work
, TMPFS_RW
, "dummy", "/boot/modules.local", NULL
);
202 domount(work
, DEVFS_RW
, "dummy", "/dev", NULL
);
203 domount(work
, PROCFS_RO
, "dummy", "/proc", NULL
);
204 domount(work
, NULLFS_RO
, "$/bin", "/bin", "/bin.%03d");
205 domount(work
, NULLFS_RO
, "$/sbin", "/sbin", NULL
);
206 domount(work
, NULLFS_RO
, "$/lib", "/lib", "/lib.%03d");
207 domount(work
, NULLFS_RO
, "$/libexec", "/libexec", "/libexec.%03d");
208 domount(work
, NULLFS_RO
, "$/usr/bin", "/usr/bin", "/usr.bin.%03d");
209 domount(work
, NULLFS_RO
, "$/usr/include", "/usr/include", NULL
);
210 domount(work
, NULLFS_RO
, "$/usr/lib", "/usr/lib", NULL
);
211 domount(work
, NULLFS_RO
, "$/usr/libdata", "/usr/libdata", NULL
);
212 domount(work
, NULLFS_RO
, "$/usr/libexec", "/usr/libexec", NULL
);
213 domount(work
, NULLFS_RO
, "$/usr/sbin", "/usr/sbin", NULL
);
214 domount(work
, NULLFS_RO
, "$/usr/share", "/usr/share", NULL
);
215 domount(work
, TMPFS_RW_MED
, "dummy", "/usr/local", NULL
);
216 domount(work
, NULLFS_RO
, "$/usr/games", "/usr/games", NULL
);
218 domount(work
, NULLFS_RO
, "$/usr/src", "/usr/src", NULL
);
219 domount(work
, NULLFS_RO
, DPortsPath
, "/xports", NULL
);
220 domount(work
, NULLFS_RW
, OptionsPath
, "/options", NULL
);
221 domount(work
, NULLFS_RW
, PackagesPath
, "/packages", NULL
);
222 domount(work
, NULLFS_RW
, DistFilesPath
, "/distfiles", NULL
);
223 domount(work
, TMPFS_RW_BIG
, "dummy", "/construction", NULL
);
225 domount(work
, NULLFS_RW
, CCachePath
, "/ccache", NULL
);
228 * NOTE: Uses blah/. to prevent cp from creating 'Template' under
229 * work->basedir. We want to start with the content.
231 asprintf(&buf
, "cp -Rp %s/Template/. %s", BuildBase
, work
->basedir
);
234 fprintf(stderr
, "Command failed: %s\n", buf
);
236 snprintf(work
->status
, sizeof(work
->status
),
237 "Template copy failed");
244 * Called by the worker support thread to remove a worker
245 * filesystem topology.
247 * NOTE: No need to conditionalize UseUsrSrc, it doesn't hurt to
248 * issue the umount() if it isn't mounted and it ensures that
249 * everything is unmounted properly on cleanup if the state
253 DoWorkerUnmounts(worker_t
*work
)
257 setNumaDomain(work
->index
);
258 work
->mount_error
= 0;
259 for (retries
= 0; retries
< 10; ++retries
) {
260 dounmount(work
, "/proc");
261 dounmount(work
, "/dev");
262 dounmount(work
, "/usr/src");
263 dounmount(work
, "/usr/games");
264 dounmount(work
, "/boot/modules.local");
265 dounmount(work
, "/boot");
266 dounmount(work
, "/usr/local");
267 dounmount(work
, "/construction");
268 dounmount(work
, "/ccache"); /* in case of config change */
269 dounmount(work
, "/distfiles");
270 dounmount(work
, "/packages");
271 dounmount(work
, "/options");
272 dounmount(work
, "/xports");
273 dounmount(work
, "/usr/share");
274 dounmount(work
, "/usr/sbin");
275 dounmount(work
, "/usr/libexec");
276 dounmount(work
, "/usr/libdata");
277 dounmount(work
, "/usr/lib");
278 dounmount(work
, "/usr/include");
279 dounmount(work
, "/usr/bin");
280 dounmount(work
, "/libexec");
281 dounmount(work
, "/lib");
282 dounmount(work
, "/sbin");
283 dounmount(work
, "/bin");
285 if (work
->mount_error
== 0)
288 work
->mount_error
= 0;
290 if (work
->mount_error
) {
292 snprintf(work
->status
, sizeof(work
->status
),
293 "Unable to unmount slot");
300 domount(worker_t
*work
, int type
, const char *spath
, const char *dpath
,
301 const char *discretefmt
)
314 * Make target directory if necessary. This must occur in-order
315 * since directories may have to be created under prior mounts
318 asprintf(&buf
, "%s%s", work
->basedir
, dpath
);
319 if (stat(buf
, &st
) != 0) {
320 if (mkdir(buf
, 0755) != 0) {
321 fprintf(stderr
, "Command failed: mkdir %s\n", buf
);
328 * Setup for mount arguments
330 rwstr
= (type
& MOUNT_TYPE_RW
) ? "rw" : "ro";
334 switch(type
& MOUNT_TYPE_MASK
) {
335 case MOUNT_TYPE_TMPFS
:
337 * When creating a tmpfs filesystem, make sure the big ones
338 * requested are big enough for the worst-case dport (which
339 * is usually chromium). If debugging is turned on, its even
340 * worse. You'd better have enough swap!
342 debug
= getbuildenv("WITH_DEBUG");
344 if (type
& MOUNT_TYPE_BIG
)
345 optstr
= debug
? " -o size=128g" : " -o size=64g";
346 else if (type
& MOUNT_TYPE_MED
)
347 optstr
= debug
? " -o size=32g" : " -o size=16g";
349 optstr
= " -o size=16g";
351 case MOUNT_TYPE_NULLFS
:
352 #if defined(__DragonFly__)
358 case MOUNT_TYPE_DEVFS
:
361 case MOUNT_TYPE_PROCFS
:
365 dfatal("Illegal mount type: %08x", type
);
375 asprintf(&tmp
, discretefmt
, work
->index
);
378 if (spath
[0] == '$') {
381 if (strcmp(sbase
, "/") == 0)
388 asprintf(&buf
, "%s%s -t %s -o %s %s%s %s%s",
389 MOUNT_BINARY
, optstr
, typestr
, rwstr
,
390 sbase
, spath
, work
->basedir
, dpath
);
393 fprintf(stderr
, "Command failed: %s\n", buf
);
403 dounmount(worker_t
*work
, const char *rpath
)
407 asprintf(&buf
, "%s%s", work
->basedir
, rpath
);
408 if (unmount(buf
, 0) < 0) {
410 case EPERM
: /* This is probably fatal later on in mount */
411 case ENOENT
: /* Expected if mount already gone */
412 case EINVAL
: /* Expected if mount already gone (maybe) */
415 fprintf(stderr
, "Cannot umount %s (%s)\n",
416 buf
, strerror(errno
));
426 makeDiscreteCopies(const char *spath
, const char *discretefmt
)
435 for (i
= 0; i
< MaxWorkers
; ++i
) {
437 if (spath
[0] == '$') {
438 if (strcmp(SystemPath
, "/") == 0)
439 asprintf(&src
, "%s%s",
440 SystemPath
+ 1, spath
+ 1);
442 asprintf(&src
, "%s%s",
443 SystemPath
, spath
+ 1);
447 asprintf(&buf
, discretefmt
, i
);
448 asprintf(&dst
, "%s%s", BuildBase
, buf
);
451 if (stat(dst
, &st
) < 0) {
452 if (mkdir(dst
, 0555) < 0) {
453 dlog(DLOG_ALL
, "Template - mkdir %s failed\n",
455 dfatal_errno("Cannot mkdir %s:", dst
);
458 asprintf(&buf
, "chflags -R noschg %s; "
463 dlog(DLOG_ALL
| DLOG_FILTER
,
464 "Template - rc=%d running %s\n", rc
, buf
);
466 dfatal("Command failed: %s", buf
);