/** * Build supermin appliance from C<supermin_path> to * F<$TMPDIR/.guestfs-$UID>. * * Returns: C<0> = built or C<-1> = error (aborts launch). */ static int build_supermin_appliance (guestfs_h *g, const char *supermin_path, char **kernel, char **initrd, char **appliance) { CLEANUP_FREE char *cachedir = NULL, *lockfile = NULL, *appliancedir = NULL; cachedir = guestfs_int_lazy_make_supermin_appliance_dir (g); if (cachedir == NULL) return -1; appliancedir = safe_asprintf (g, "%s/appliance.d", cachedir); lockfile = safe_asprintf (g, "%s/lock", cachedir); debug (g, "begin building supermin appliance"); /* Build the appliance if it needs to be built. */ debug (g, "run supermin"); if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1) return -1; debug (g, "finished building supermin appliance"); /* Return the appliance filenames. */ *kernel = safe_asprintf (g, "%s/kernel", appliancedir); *initrd = safe_asprintf (g, "%s/initrd", appliancedir); *appliance = safe_asprintf (g, "%s/root", appliancedir); /* Touch the files so they don't get deleted (as they are in /var/tmp). */ (void) utimes (*kernel, NULL); (void) utimes (*initrd, NULL); /* Checking backend != "uml" is a big hack. UML encodes the mtime * of the original backing file (in this case, the appliance) in the * COW file, and checks it when adding it to the VM. If there are * multiple threads running and one touches the appliance here, it * will disturb the mtime and UML will give an error. * * We can get rid of this hack as soon as UML fixes the * ubdN=cow,original parsing bug, since we won't need to run * uml_mkcow separately, so there is no possible race. * * XXX */ if (STRNEQ (g->backend, "uml")) (void) utimes (*appliance, NULL); return 0; }
/* Build supermin appliance from supermin_path to $TMPDIR/.guestfs-$UID. * * Returns: * 0 = built * -1 = error (aborts launch) */ static int build_supermin_appliance (guestfs_h *g, const char *supermin_path, uid_t uid, char **kernel, char **dtb, char **initrd, char **appliance) { CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g); struct stat statbuf; size_t len; /* len must be longer than the length of any pathname we can * generate in this function. */ len = strlen (tmpdir) + 128; char cachedir[len]; snprintf (cachedir, len, "%s/.guestfs-%ju", tmpdir, (uintmax_t) uid); char lockfile[len]; snprintf (lockfile, len, "%s/lock", cachedir); char appliancedir[len]; snprintf (appliancedir, len, "%s/appliance.d", cachedir); ignore_value (mkdir (cachedir, 0755)); ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */ /* See if the cache directory exists and passes some simple checks * to make sure it has not been tampered with. */ if (lstat (cachedir, &statbuf) == -1) return 0; if (statbuf.st_uid != uid) { error (g, _("security: cached appliance %s is not owned by UID %ju"), cachedir, (uintmax_t) uid); return -1; } if (!S_ISDIR (statbuf.st_mode)) { error (g, _("security: cached appliance %s is not a directory (mode %o)"), cachedir, statbuf.st_mode); return -1; } if ((statbuf.st_mode & 0022) != 0) { error (g, _("security: cached appliance %s is writable by group or other (mode %o)"), cachedir, statbuf.st_mode); return -1; } (void) utimes (cachedir, NULL); if (g->verbose) guestfs_int_print_timestamped_message (g, "begin building supermin appliance"); /* Build the appliance if it needs to be built. */ if (g->verbose) guestfs_int_print_timestamped_message (g, "run supermin"); if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1) return -1; if (g->verbose) guestfs_int_print_timestamped_message (g, "finished building supermin appliance"); /* Return the appliance filenames. */ *kernel = safe_malloc (g, len); #ifdef DTB_WILDCARD *dtb = safe_malloc (g, len); #else *dtb = NULL; #endif *initrd = safe_malloc (g, len); *appliance = safe_malloc (g, len); snprintf (*kernel, len, "%s/kernel", appliancedir); #ifdef DTB_WILDCARD snprintf (*dtb, len, "%s/dtb", appliancedir); #endif snprintf (*initrd, len, "%s/initrd", appliancedir); snprintf (*appliance, len, "%s/root", appliancedir); /* Touch the files so they don't get deleted (as they are in /var/tmp). */ (void) utimes (*kernel, NULL); #ifdef DTB_WILDCARD (void) utimes (*dtb, NULL); #endif (void) utimes (*initrd, NULL); /* Checking backend != "uml" is a big hack. UML encodes the mtime * of the original backing file (in this case, the appliance) in the * COW file, and checks it when adding it to the VM. If there are * multiple threads running and one touches the appliance here, it * will disturb the mtime and UML will give an error. * * We can get rid of this hack as soon as UML fixes the * ubdN=cow,original parsing bug, since we won't need to run * uml_mkcow separately, so there is no possible race. * * XXX */ if (STRNEQ (g->backend, "uml")) (void) utimes (*appliance, NULL); return 0; }