Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: Peter Jones <pjones@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
- Loading branch information
Showing
5 changed files
with
203 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ sparc32.8 | |
sparc32bash.8 | ||
sparc64.8 | ||
sparc.8 | ||
switch_root | ||
tunelp | ||
vidmode.8 | ||
x86_64.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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@redhat.com> | ||
* Jeremy Katz <katzj@redhat.com> | ||
*/ | ||
|
||
#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 | ||
*/ |