[libvirt] PATCH: 7/7: Allow replacing root filesystem
Jim Meyering
jim at meyering.net
Wed Aug 6 09:00:05 UTC 2008
"Daniel P. Berrange" <berrange at redhat.com> wrote:
...
> -static int lxcContainerSetStdio(int control, const char *ttyPath)
> +static int lxcContainerSetStdio(int control, int ttyfd)
> {
Hi Dan,
Not a big deal, but since ttyfd is now an input to this function,
it'd be less surprising if the caller were to close it.
Probably not worth changing...
> int rc = -1;
> - int ttyfd;
> int open_max, i;
>
> if (setsid() < 0) {
> lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> _("setsid failed: %s"), strerror(errno));
> - goto error_out;
> - }
> -
> - ttyfd = open(ttyPath, O_RDWR|O_NOCTTY);
> - if (ttyfd < 0) {
> - lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> - _("open(%s) failed: %s"), ttyPath, strerror(errno));
> - goto error_out;
> + goto cleanup;
> }
>
> if (ioctl(ttyfd, TIOCSCTTY, NULL) < 0) {
> @@ -159,8 +161,6 @@
>
> cleanup:
> close(ttyfd);
> -
> -error_out:
> return rc;
> }
>
> @@ -223,6 +223,7 @@
> return 0;
> }
>
> +
> /**
> * lxcEnableInterfaces:
> * @vm: Pointer to vm structure
> @@ -252,6 +253,20 @@
> return rc;
> }
...
> + if (root) {
> + char *oldroot;
> + struct mntent *mntent;
> + char **mounts = NULL;
> + int nmounts = 0;
> + FILE *procmnt;
This can be "const":
> + struct {
> + int maj;
> + int min;
> + const char *path;
> + } devs[] = {
> + { 1, 3, "/dev/null" },
> + { 1, 5, "/dev/zero" },
> + { 1, 7, "/dev/full" },
> + { 5, 1, "/dev/console" },
Might be good to add /dev/random and /dev/urandom.
I recently had trouble on a system where udev malfunctioned,
and some /dev/{u,}random-requiring libs/services failed in unusual ways.
Also, how about adding permission bits to the table, so that
console doesn't end up being mode 0777:
struct {
int maj;
int min;
mode_t mode,
const char *path;
} const devs[] = {
{ 1, 3, 0666, "/dev/null" },
{ 1, 5, 0666, "/dev/zero" },
{ 1, 7, 0666, "/dev/full" },
{ 5, 1, 0600, "/dev/console" },
{ 1, 8, 0666, "/dev/random" },
{ 1, 9, 0666, "/dev/urandom" },
};
> + if (virFileMakePath("/dev/pts") < 0 ||
> + mount("/.oldroot/dev/pts", "/dev/pts", NULL,
> + MS_MOVE, NULL) < 0) {
> + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + _("failed to move /dev/pts into container: %s"),
> + strerror(errno));
> + return -1;
> + }
> +
> + /* Populate /dev/ with a few important bits */
> + umask(0);
In principle, it's better never to change umask. Otherwise, when
multi-threaded, that temporarily-cleared umask could hose a file-creation
operation in another thread -- and it'd be a race, so probably hard to
reproduce.
> + for (i = 0 ; i < ARRAY_CARDINALITY(devs) ; i++) {
> + dev_t dev = makedev(devs[i].maj, devs[i].min);
> + if (mknod(devs[i].path,
> + 0777 | S_IFCHR,
Dropping the umask, you might do s/0777/0/ here, and then
call chmod to set each mode to devs[i].mode
> + dev) < 0) {
> + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + _("failed to make device %s: %s"),
> + devs[i].path, strerror(errno));
Returning here would leave umask set to 0.
Another reason not to change it in the first place.
> + return -1;
> + }
> + }
> + umask(0700);
When you do change umask, be sure to restore to the previous value.
> + /* Pull in rest of container's mounts */
> + for (tmp = vmDef->fss; tmp; tmp = tmp->next) {
> + char *src;
> + if (STREQ(tmp->dst, "/"))
> + continue;
> + // XXX fix
> + if (tmp->type != VIR_DOMAIN_FS_TYPE_MOUNT)
> + continue;
> +
> + if (asprintf(&src, "/.oldroot/%s", tmp->src) < 0)
> + return -1;
> +
> + if (virFileMakePath(tmp->dst) < 0 ||
> + mount(src, tmp->dst, NULL, MS_BIND, NULL) < 0) {
> + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + _("failed to mount %s at %s for container: %s"),
> + tmp->src, tmp->dst, strerror(errno));
Call VIR_FREE(src) here to avoid a leak.
> + return -1;
> + }
> + VIR_FREE(src);
> + }
> +
> + if (!(procmnt = setmntent("/proc/mounts", "r"))) {
> + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + _("failed to read /proc/mounts: %s"),
> + strerror(errno));
> + return -1;
> + }
> + while ((mntent = getmntent(procmnt)) != NULL) {
> + if (!STRPREFIX(mntent->mnt_dir, "/.oldroot"))
> + continue;
> + if (VIR_REALLOC_N(mounts, nmounts+1) < 0)
Call endmntent(procmnt) here, to
avoid a potential file descriptor leak.
> + return -1;
> + mounts[nmounts++] = strdup(mntent->mnt_dir);
A failed strdup here would lead to segfault via qsort's comparator.
> + }
> + endmntent(procmnt);
> +
> + qsort(mounts, nmounts, sizeof(mounts[0]),
> + lxcContainerChildMountSort);
> +
> + for (i = 0 ; i < nmounts ; i++) {
> + if (umount(mounts[i]) < 0) {
> + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> + _("failed to unmount %s: %s"),
> + mounts[i], strerror(errno));
> + return -1;
Maybe try to unmount all of them before returning, even if an
earlier one fails?
Also, be sure to free "mounts" before returning.
> + }
> + }
> + } else {
...
More information about the libvir-list
mailing list