Re: [PATCH 1/9] switch_root: new command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06/09/2009 04:48 PM, Karel Zak wrote:
> Copied from Dracut project:
> git://dracut.git.sourceforge.net/gitroot/dracut
> 
> Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>

Obviously, I'm okay with this, though I think you should probably break it down into the commits to dracut, use --author a bunch, and preserve changelogs on this particular one.

> ---
>  po/POTFILES.in          |    1 +
>  sys-utils/.gitignore    |    1 +
>  sys-utils/Makefile.am   |    2 +-
>  sys-utils/switch_root.c |  198 +++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 201 insertions(+), 1 deletions(-)
>  create mode 100644 sys-utils/switch_root.c
> 
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 2ca79c6..334b8e5 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -180,6 +180,7 @@ sys-utils/renice.c
>  sys-utils/rtcwake.c
>  sys-utils/setarch.c
>  sys-utils/setsid.c
> +sys-utils/switch_root.c
>  sys-utils/tunelp.c
>  text-utils/col.c
>  text-utils/colcrt.c
> diff --git a/sys-utils/.gitignore b/sys-utils/.gitignore
> index c47cd07..6f0be71 100644
> --- a/sys-utils/.gitignore
> +++ b/sys-utils/.gitignore
> @@ -36,6 +36,7 @@ sparc32.8
>  sparc32bash.8
>  sparc64.8
>  sparc.8
> +switch_root
>  tunelp
>  vidmode.8
>  x86_64.8
> diff --git a/sys-utils/Makefile.am b/sys-utils/Makefile.am
> index b4c6ac6..856d6a1 100644
> --- a/sys-utils/Makefile.am
> +++ b/sys-utils/Makefile.am
> @@ -1,7 +1,7 @@
>  include $(top_srcdir)/config/include-Makefile.am
>  
>  bin_PROGRAMS =
> -sbin_PROGRAMS =
> +sbin_PROGRAMS = switch_root
>  usrbinexec_PROGRAMS = flock ipcrm ipcs ipcmk renice setsid
>  usrsbinexec_PROGRAMS = readprofile
>  
> diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c
> new file mode 100644
> index 0000000..9188006
> --- /dev/null
> +++ b/sys-utils/switch_root.c
> @@ -0,0 +1,198 @@
> +/*
> + * switchroot.c - switch to new root directory and start init.
> + *
> + * Copyright 2002-2008 Red Hat, Inc.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + *	Peter Jones <pjones@xxxxxxxxxx>
> + *	Jeremy Katz <katzj@xxxxxxxxxx>
> + */
> +
> +#define _GNU_SOURCE 1
> +
> +#include <sys/mount.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/param.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <ctype.h>
> +#include <dirent.h>
> +
> +#ifndef MS_MOVE
> +#define MS_MOVE 8192
> +#endif
> +
> +#ifndef MNT_DETACH
> +#define MNT_DETACH 0x2
> +#endif
> +
> +enum {
> +	ok,
> +	err_no_directory,
> +	err_usage,
> +};
> +
> +/* remove all files/directories below dirName -- don't cross mountpoints */
> +static int
> +recursiveRemove(char * dirName)
> + {
> +    struct stat sb,rb;
> +    DIR * dir;
> +    struct dirent * d;
> +    char * strBuf = alloca(strlen(dirName) + 1024);
> +
> +    if (!(dir = opendir(dirName))) {
> +        printf("error opening %s: %m\n", dirName);
> +        return 0;
> +    }
> +
> +    if (fstat(dirfd(dir),&rb)) {
> +        printf("unable to stat %s: %m\n", dirName);
> +        closedir(dir);
> +        return 0;
> +    }
> +
> +    errno = 0;
> +    while ((d = readdir(dir))) {
> +        errno = 0;
> +
> +        if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
> +            errno = 0;
> +            continue;
> +        }
> +
> +        strcpy(strBuf, dirName);
> +        strcat(strBuf, "/");
> +        strcat(strBuf, d->d_name);
> +
> +        if (lstat(strBuf, &sb)) {
> +            printf("failed to stat %s: %m\n", strBuf);
> +            errno = 0;
> +            continue;
> +        }
> +
> +        /* only descend into subdirectories if device is same as dir */
> +        if (S_ISDIR(sb.st_mode)) {
> +            if (sb.st_dev == rb.st_dev) {
> +	        recursiveRemove(strBuf);
> +                if (rmdir(strBuf))
> +                    printf("failed to rmdir %s: %m\n", strBuf);
> +            }
> +            errno = 0;
> +            continue;
> +        }
> +        if (unlink(strBuf)) {
> +            printf("failed to remove %s: %m\n", strBuf);
> +            errno = 0;
> +            continue;
> +        }
> +    }
> +
> +    if (errno) {
> +        closedir(dir);
> +        printf("error reading from %s: %m\n", dirName);
> +        return 1;
> +    }
> +
> +    closedir(dir);
> +
> +    return 0;
> + }
> +
> +static int switchroot(const char *newroot)
> +{
> +	/*  Don't try to unmount the old "/", there's no way to do it. */
> +	const char *umounts[] = { "/dev", "/proc", "/sys", NULL };
> +	int errnum;
> +	int i;
> +
> +	for (i = 0; umounts[i] != NULL; i++) {
> +		char newmount[PATH_MAX];
> +		strcpy(newmount, newroot);
> +		strcat(newmount, umounts[i]);
> +		if (mount(umounts[i], newmount, NULL, MS_MOVE, NULL) < 0) {
> +			fprintf(stderr, "Error mount moving old %s %s %m\n",
> +				umounts[i], newmount);
> +			fprintf(stderr, "Forcing unmount of %s\n", umounts[i]);
> +			umount2(umounts[i], MNT_FORCE);
> +		}
> +	}
> +
> +	if (chdir(newroot) < 0) {
> +	  errnum=errno;
> +	  fprintf(stderr, "switchroot: chdir failed: %m\n");
> +	  errno=errnum;
> +	  return -1;
> +	}
> +	recursiveRemove("/");
> +	if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) {
> +		errnum = errno;
> +		fprintf(stderr, "switchroot: mount failed: %m\n");
> +		errno = errnum;
> +		return -1;
> +	}
> +
> +	if (chroot(".")) {
> +		errnum = errno;
> +		fprintf(stderr, "switchroot: chroot failed: %m\n");
> +		errno = errnum;
> +		return -2;
> +	}
> +	return 1;
> +}
> +
> +static void usage(FILE *output)
> +{
> +	fprintf(output, "usage: switchroot <newrootdir> <init> <args to init>\n");
> +	if (output == stderr)
> +		exit(err_usage);
> +	exit(ok);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	char *newroot = argv[1];
> +	char *init = argv[2];
> +	char **initargs = &argv[2];
> +
> +	if (newroot == NULL || newroot[0] == '\0' ||
> +	    init == NULL || init[0] == '\0' ) {
> +		usage(stderr);
> +	}
> +
> +	if (switchroot(newroot) < 0) {
> +	  fprintf(stderr, "switchroot has failed.  Sorry.\n");
> +	  return 1;
> +	}
> +	if (access(initargs[0], X_OK))
> +	  fprintf(stderr, "WARNING: can't access %s\n", initargs[0]);
> +
> +	/* get session leader */
> +	setsid();
> +	/* set controlling terminal */
> +	ioctl (0, TIOCSCTTY, 1);
> +
> +	execv(initargs[0], initargs);
> +}
> +
> +/*
> + * vim:noet:ts=8:sw=8:sts=8
> + */


-- 
        Peter

I hope you know that this will go down on your permanent record.
--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux