On 06/19/2009 05:25 AM, Karel Zak wrote: > Copied from Dracut project: > git://dracut.git.sourceforge.net/gitroot/dracut > > switch_root history in dracut.git repository: > > $ git shortlog switch_root.c > Harald Hoyer (5): > replace switch_root shell script with binary > add \n to switch_root > use switch_root code from http://pjones.fedorapeople.org/mkstart/usr/lib/mkstart/switchroot.c > mount move instead of umount and fix the search for fallback inits > setsid() and set controlling terminal for real /sbin/init > > Victor Lowther (2): > Simplify switch_root.c a bit > Remove all files on the initramfs before switching root > > Signed-off-by: Karel Zak <kzak@xxxxxxxxxx> Signed-off-by: Peter Jones <pjones@xxxxxxxxxx> > --- > AUTHORS | 2 + > po/POTFILES.in | 1 + > sys-utils/.gitignore | 1 + > sys-utils/Makefile.am | 2 +- > sys-utils/switch_root.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 203 insertions(+), 1 deletions(-) > create mode 100644 sys-utils/switch_root.c > > diff --git a/AUTHORS b/AUTHORS > index c684348..93fb841 100644 > --- a/AUTHORS > +++ b/AUTHORS > @@ -29,6 +29,8 @@ AUTHORS (merged projects & commands): > setarch: Elliot Lee <sopwith@xxxxxxxxxx> > Jindrich Novy <jnovy@xxxxxxxxxx> > simpleinit: Richard Gooch <rgooch@xxxxxxxxxxxxx> > + switch_root: Peter Jones <pjones@xxxxxxxxxx> > + Jeremy Katz <katzj@xxxxxxxxxx> > > > CONTRIBUTORS: > 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 Gravity is a habit that is hard to shake off. -- Pratchett -- 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