From: Harald Hoyer Date: Fri, 19 Jun 2009 10:09:14 +0000 (+0200) Subject: updated switch_root.c X-Git-Tag: 0.1~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d49449cd4ecfb6a3e03296e1bc8a81c961411e34;p=platform%2Fupstream%2Fdracut.git updated switch_root.c matches the version, which will go to util-linux-ng --- diff --git a/Makefile b/Makefile index 3ec288a..f693ace 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ sbindir = ${prefix}/sbin mandir = ${prefix}/share/man modules.d/99base/switch_root: switch_root.c - gcc -o modules.d/99base/switch_root switch_root.c + gcc -D _GNU_SOURCE -D 'PACKAGE_STRING="dracut"' -std=gnu99 -fsigned-char -g -O2 -o modules.d/99base/switch_root switch_root.c all: modules.d/99base/switch_root diff --git a/switch_root.c b/switch_root.c index ef7a0fb..8daacb1 100644 --- a/switch_root.c +++ b/switch_root.c @@ -1,7 +1,7 @@ /* * switchroot.c - switch to new root directory and start init. * - * Copyright 2002-2008 Red Hat, Inc. All rights reserved. + * Copyright 2002-2009 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 @@ -17,12 +17,9 @@ * along with this program. If not, see . * * Authors: - * Peter Jones + * Peter Jones * Jeremy Katz */ - -#define _GNU_SOURCE 1 - #include #include #include @@ -35,164 +32,163 @@ #include #include #include +#include #ifndef MS_MOVE #define MS_MOVE 8192 #endif -#ifndef MNT_DETACH -#define MNT_DETACH 0x2 -#endif +/* remove all files/directories below dirName -- don't cross mountpoints */ +static int recursiveRemove(char *dirName) +{ + struct stat rb; + DIR *dir; + int rc = -1; + int dfd; + + if (!(dir = opendir(dirName))) { + warn("failed to open %s", dirName); + goto done; + } -enum { - ok, - err_no_directory, - err_usage, -}; + dfd = dirfd(dir); -/* 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; - } + if (fstat(dfd, &rb)) { + warn("failed to stat %s", dirName); + goto done; + } + + while(1) { + struct dirent *d; + + errno = 0; + if (!(d = readdir(dir))) { + if (errno) { + warn("failed to read %s", dirName); + goto done; + } + break; /* end of directory */ + } + + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + if (d->d_type == DT_DIR) { + struct stat sb; + + if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) { + warn("failed to stat %s/%s", dirName, d->d_name); + continue; + } + + /* remove subdirectories if device is same as dir */ + if (sb.st_dev == rb.st_dev) { + char subdir[ strlen(dirName) + + strlen(d->d_name) + 2 ]; + + sprintf(subdir, "%s/%s", dirName, d->d_name); + recursiveRemove(subdir); + } else + continue; + } + + if (unlinkat(dfd, d->d_name, + d->d_type == DT_DIR ? AT_REMOVEDIR : 0)) + warn("failed to unlink %s/%s", dirName, d->d_name); + } + + rc = 0; /* success */ + +done: + if (dir) + closedir(dir); + return rc; +} 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]); + + snprintf(newmount, sizeof(newmount), "%s%s", newroot, umounts[i]); + if (mount(umounts[i], newmount, NULL, MS_MOVE, NULL) < 0) { - fprintf(stderr, "Error mount moving old %s %s %m\n", + warn("failed to mount moving %s to %s", umounts[i], newmount); - fprintf(stderr, "Forcing unmount of %s\n", umounts[i]); + warnx("forcing unmount of %s", umounts[i]); umount2(umounts[i], MNT_FORCE); } } - if (chdir(newroot) < 0) { - errnum=errno; - fprintf(stderr, "switchroot: chdir failed: %m\n"); - errno=errnum; - return -1; + if (chdir(newroot)) { + warn("failed to change directory to %s", newroot); + return -1; } + recursiveRemove("/"); + if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) { - errnum = errno; - fprintf(stderr, "switchroot: mount failed: %m\n"); - errno = errnum; + warn("failed to mount moving %s to /", newroot); return -1; } if (chroot(".")) { - errnum = errno; - fprintf(stderr, "switchroot: chroot failed: %m\n"); - errno = errnum; - return -2; + warn("failed to change root"); + return -1; } - return 1; + return 0; } static void usage(FILE *output) { - fprintf(output, "usage: switchroot \n"); - if (output == stderr) - exit(err_usage); - exit(ok); + fprintf(output, "usage: %s \n", + program_invocation_short_name); + exit(output == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + +static void version(void) +{ + fprintf(stdout, "%s from %s\n", program_invocation_short_name, + PACKAGE_STRING); + exit(EXIT_SUCCESS); } int main(int argc, char *argv[]) { - char *newroot = argv[1]; - char *init = argv[2]; - char **initargs = &argv[2]; + char *newroot, *init, **initargs; - if (newroot == NULL || newroot[0] == '\0' || - init == NULL || init[0] == '\0' ) { + if (argv[1] && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + usage(stdout); + if (argv[1] && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V"))) + version(); + if (argc < 3) 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]); + newroot = argv[1]; + init = argv[2]; + initargs = &argv[2]; + + if (!*newroot || !*init) + usage(stderr); + + if (switchroot(newroot)) + errx(EXIT_FAILURE, "failed. Sorry."); + + if (access(init, X_OK)) + warn("cannot access %s", init); /* get session leader */ setsid(); + /* set controlling terminal */ - ioctl (0, TIOCSCTTY, 1); + if (ioctl (0, TIOCSCTTY, 1)) + warn("failed to TIOCSCTTY"); - execv(initargs[0], initargs); + execv(init, initargs); + err(EXIT_FAILURE, "failed to execute %s", init); } -/* - * vim:noet:ts=8:sw=8:sts=8 - */