#include "dsynth.h"
static void domount(worker_t *work, int type,
const char *spath, const char *dpath,
const char *discretefmt);
static void dounmount(worker_t *work, const char *rpath);
static void makeDiscreteCopies(const char *spath, const char *discretefmt);
int
DoCreateTemplate(int force)
{
struct stat st;
char *goodbuf;
char *buf;
const char *reason = "";
int rc;
int fd;
int n;
rc = 0;
asprintf(&goodbuf, "%s/.template.good", BuildBase);
if (force == 1)
reason = " (Asked to force template creation)";
if (force == 0) {
time_t ls_mtime;
asprintf(&buf, "%s/Template", BuildBase);
if (stat(buf, &st) < 0) {
force = 1;
reason = " (Template file missing)";
}
free(buf);
asprintf(&buf, "%s/bin/ls", SystemPath);
if (stat(buf, &st) < 0)
dfatal_errno("Unable to locate %s", buf);
free(buf);
ls_mtime = st.st_mtime;
for (n = 0; n < MaxWorkers; ++n) {
asprintf(&buf, "%s/bin.%03d/ls", BuildBase, n);
if (stat(buf, &st) < 0 || st.st_mtime != ls_mtime) {
force = 1;
reason = " (/bin/ls mtime mismatch)";
}
free(buf);
}
if (stat(goodbuf, &st) < 0) {
force = 1;
reason = " (.template.good file missing)";
}
}
dlog(DLOG_ALL, "Check Template: %s%s\n",
(force ? "Must-Create" : "Good"),
reason);
if (force) {
remove(goodbuf);
rc = 0;
asprintf(&buf, "%s/mktemplate %s %s/Template",
SCRIPTPATH(SCRIPTDIR), SystemPath, BuildBase);
rc = system(buf);
if (rc)
dfatal("Command failed: %s\n", buf);
dlog(DLOG_ALL | DLOG_FILTER,
"Template - rc=%d running %s\n", rc, buf);
free(buf);
makeDiscreteCopies("$/bin", "/bin.%03d");
makeDiscreteCopies("$/lib", "/lib.%03d");
makeDiscreteCopies("$/libexec", "/libexec.%03d");
makeDiscreteCopies("$/usr/bin", "/usr.bin.%03d");
sync();
fd = open(goodbuf, O_RDWR|O_CREAT|O_TRUNC, 0644);
dassert_errno(fd >= 0, "could not create %s", goodbuf);
close(fd);
dlog(DLOG_ALL | DLOG_FILTER, "Template - done\n");
}
free(goodbuf);
return force;
}
void
DoDestroyTemplate(void)
{
struct stat st;
char *path;
char *buf;
int rc;
asprintf(&path, "%s/Template", BuildBase);
if (stat(path, &st) == 0) {
asprintf(&buf, "chflags -R noschg %s; /bin/rm -rf %s",
path, path);
rc = system(buf);
if (rc)
dfatal("Command failed: %s (ignored)\n", buf);
free(buf);
}
free(path);
}
void
DoWorkerMounts(worker_t *work)
{
char *buf;
int rc;
setNumaDomain(work->index);
domount(work, TMPFS_RW, "dummy", "", NULL);
asprintf(&buf, "%s/usr", work->basedir);
if (mkdir(buf, 0755) != 0) {
fprintf(stderr, "Command failed: mkdir %s\n", buf);
++work->mount_error;
}
free(buf);
asprintf(&buf, "%s/usr/packages", work->basedir);
if (mkdir(buf, 0755) != 0) {
fprintf(stderr, "Command failed: mkdir %s\n", buf);
++work->mount_error;
}
free(buf);
domount(work, TMPFS_RW, "dummy", "/boot", NULL);
asprintf(&buf, "%s/boot/modules.local", work->basedir);
if (mkdir(buf, 0755) != 0) {
fprintf(stderr, "Command failed: mkdir %s\n", buf);
++work->mount_error;
}
free(buf);
domount(work, DEVFS_RW, "dummy", "/dev", NULL);
domount(work, PROCFS_RO, "dummy", "/proc", NULL);
domount(work, NULLFS_RO, "$/bin", "/bin", "/bin.%03d");
domount(work, NULLFS_RO, "$/sbin", "/sbin", NULL);
domount(work, NULLFS_RO, "$/lib", "/lib", "/lib.%03d");
domount(work, NULLFS_RO, "$/libexec", "/libexec", "/libexec.%03d");
domount(work, NULLFS_RO, "$/usr/bin", "/usr/bin", "/usr.bin.%03d");
domount(work, NULLFS_RO, "$/usr/include", "/usr/include", NULL);
domount(work, NULLFS_RO, "$/usr/lib", "/usr/lib", NULL);
domount(work, NULLFS_RO, "$/usr/libdata", "/usr/libdata", NULL);
domount(work, NULLFS_RO, "$/usr/libexec", "/usr/libexec", NULL);
domount(work, NULLFS_RO, "$/usr/sbin", "/usr/sbin", NULL);
domount(work, NULLFS_RO, "$/usr/share", "/usr/share", NULL);
domount(work, TMPFS_RW_MED, "dummy", "/usr/local", NULL);
domount(work, NULLFS_RO, "$/usr/games", "/usr/games", NULL);
if (UseUsrSrc)
domount(work, NULLFS_RO, "$/usr/src", "/usr/src", NULL);
domount(work, NULLFS_RO, DPortsPath, "/xports", NULL);
if (DFlyPortsBaseOpt) {
char *pdfly;
asprintf(&pdfly, "%s/dragonfly", DPortsPath);
domount(work, NULLFS_RO, pdfly, "/xports/dragonfly", NULL);
free(pdfly);
}
domount(work, NULLFS_RW, OptionsPath, "/options", NULL);
domount(work, NULLFS_RW, PackagesPath, "/packages", NULL);
domount(work, NULLFS_RW, DistFilesPath, "/distfiles", NULL);
domount(work, TMPFS_RW_BIG, "dummy", "/construction", NULL);
if (UseCCache)
domount(work, NULLFS_RW, CCachePath, "/ccache", NULL);
asprintf(&buf, "cp -Rp %s/Template/. %s", BuildBase, work->basedir);
rc = system(buf);
if (rc) {
fprintf(stderr, "Command failed: %s\n", buf);
++work->accum_error;
snprintf(work->status, sizeof(work->status),
"Template copy failed");
}
free(buf);
setNumaDomain(-1);
}
void
DoWorkerUnmounts(worker_t *work)
{
int retries;
setNumaDomain(work->index);
work->mount_error = 0;
for (retries = 0; retries < 10; ++retries) {
dounmount(work, "/proc");
dounmount(work, "/dev");
dounmount(work, "/usr/src");
dounmount(work, "/usr/games");
dounmount(work, "/boot");
dounmount(work, "/usr/local");
dounmount(work, "/construction");
dounmount(work, "/ccache");
dounmount(work, "/distfiles");
dounmount(work, "/packages");
dounmount(work, "/options");
if (DFlyPortsBaseOpt)
dounmount(work, "/xports/dragonfly");
dounmount(work, "/xports");
dounmount(work, "/usr/share");
dounmount(work, "/usr/sbin");
dounmount(work, "/usr/libexec");
dounmount(work, "/usr/libdata");
dounmount(work, "/usr/lib");
dounmount(work, "/usr/include");
dounmount(work, "/usr/bin");
dounmount(work, "/libexec");
dounmount(work, "/lib");
dounmount(work, "/sbin");
dounmount(work, "/bin");
dounmount(work, "");
if (work->mount_error == 0)
break;
sleep(5);
work->mount_error = 0;
}
if (work->mount_error) {
++work->accum_error;
snprintf(work->status, sizeof(work->status),
"Unable to unmount slot");
}
setNumaDomain(-1);
}
static
void
domount(worker_t *work, int type, const char *spath, const char *dpath,
const char *discretefmt)
{
const char *sbase;
const char *rwstr;
const char *optstr;
const char *typestr;
const char *debug;
struct stat st;
char *buf;
char *tmp;
int rc;
asprintf(&buf, "%s%s", work->basedir, dpath);
if (stat(buf, &st) != 0) {
if (mkdir(buf, 0755) != 0) {
fprintf(stderr, "Command failed: mkdir %s\n", buf);
++work->mount_error;
}
}
free(buf);
rwstr = (type & MOUNT_TYPE_RW) ? "rw" : "ro";
optstr = "";
typestr = "";
switch(type & MOUNT_TYPE_MASK) {
case MOUNT_TYPE_TMPFS:
debug = getbuildenv("WITH_DEBUG");
typestr = "tmpfs";
if (type & MOUNT_TYPE_BIG)
optstr = debug ? " -o size=128g" : " -o size=64g";
else if (type & MOUNT_TYPE_MED)
optstr = debug ? " -o size=32g" : " -o size=16g";
else
optstr = " -o size=16g";
break;
case MOUNT_TYPE_NULLFS:
#if defined(__DragonFly__)
typestr = "null";
#else
typestr = "nullfs";
#endif
break;
case MOUNT_TYPE_DEVFS:
typestr = "devfs";
break;
case MOUNT_TYPE_PROCFS:
typestr = "procfs";
break;
default:
dfatal("Illegal mount type: %08x", type);
break;
}
if (discretefmt) {
sbase = BuildBase;
asprintf(&tmp, discretefmt, work->index);
spath = tmp;
} else {
if (spath[0] == '$') {
++spath;
sbase = SystemPath;
if (strcmp(sbase, "/") == 0)
++sbase;
} else {
sbase = "";
}
tmp = NULL;
}
asprintf(&buf, "%s%s -t %s -o %s %s%s %s%s",
MOUNT_BINARY, optstr, typestr, rwstr,
sbase, spath, work->basedir, dpath);
rc = system(buf);
if (rc) {
fprintf(stderr, "Command failed: %s\n", buf);
++work->mount_error;
}
free(buf);
if (tmp)
free(tmp);
}
static
void
dounmount(worker_t *work, const char *rpath)
{
char *buf;
asprintf(&buf, "%s%s", work->basedir, rpath);
if (unmount(buf, 0) < 0) {
switch(errno) {
case EPERM:
case ENOENT:
case EINVAL:
break;
default:
fprintf(stderr, "Cannot umount %s (%s)\n",
buf, strerror(errno));
++work->mount_error;
break;
}
}
free(buf);
}
static
void
makeDiscreteCopies(const char *spath, const char *discretefmt)
{
char *src;
char *dst;
char *buf;
struct stat st;
int i;
int rc;
for (i = 0; i < MaxWorkers; ++i) {
setNumaDomain(i);
if (spath[0] == '$') {
if (strcmp(SystemPath, "/") == 0)
asprintf(&src, "%s%s",
SystemPath + 1, spath + 1);
else
asprintf(&src, "%s%s",
SystemPath, spath + 1);
} else {
src = strdup(spath);
}
asprintf(&buf, discretefmt, i);
asprintf(&dst, "%s%s", BuildBase, buf);
free(buf);
if (stat(dst, &st) < 0) {
if (mkdir(dst, 0555) < 0) {
dlog(DLOG_ALL, "Template - mkdir %s failed\n",
dst);
dfatal_errno("Cannot mkdir %s:", dst);
}
}
asprintf(&buf, "chflags -R noschg %s; "
"rm -rf %s; "
"cp -Rp %s/. %s",
dst, dst, src, dst);
rc = system(buf);
dlog(DLOG_ALL | DLOG_FILTER,
"Template - rc=%d running %s\n", rc, buf);
if (rc)
dfatal("Command failed: %s", buf);
free(buf);
free(src);
free(dst);
setNumaDomain(-1);
}
}