/*
* 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 .
*
* Authors:
* Peter Jones
* Jeremy Katz
*/
#define _GNU_SOURCE 1
#include
#include
#include
enum {
ok,
err_invalid_failscript,
err_no_directory,
err_usage,
};
static int readFD(int fd, char **buf)
{
char *p;
size_t size = 16384;
int s = 0, filesize = 0;
if (!(*buf = calloc (16384, sizeof (char))))
return -1;
do {
p = *buf + filesize;
s = read(fd, p, 16384 - s);
if (s < 0)
break;
filesize += s;
/* only exit for empty reads */
if (s == 0)
break;
else if (s == 16384) {
*buf = realloc(*buf, size + 16384);
memset(*buf + size, '\0', 16384);
size += s;
s = 0;
} else {
size += s;
}
} while (1);
*buf = realloc(*buf, filesize+1);
(*buf)[filesize] = '\0';
return *buf ? filesize : -1;
}
static void build_init_args(char **init, char ***initargs)
{
const char *initprogs[] = { "/sbin/init", "/etc/init",
"/bin/init", "/bin/sh", NULL };
const char *ignoreargs[] = { "console=", "BOOT_IMAGE=", NULL };
char *cmdline = NULL;
int fd = -1;
int rc = -1;
fd = open("/proc/cmdline", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Error: Could not open /proc/cmdline: %m\n");
} else {
if (readFD(fd, &cmdline) < 0) {
fprintf(stderr, "Error: could not read /proc/cmdline: %m\n");
} else {
}
}
}
static void switchroot(const char *newroot, const char *failscript)
{
/* Don't try to unmount the old "/", there's no way to do it. */
const char *umounts[] = { "/dev", "/proc", "/sys", NULL };
char *init, **initargs;
char *new = NULL, *arg;
int fd, i = 0, j = 0, rc = 0;
build_init_args(&init, &initargs);
}
static void usage(FILE *output)
{
fprintf(output, "usage: switchroot [ {-f|--failscript} ] {-n|--newroot} \n");
if (output == stderr)
exit(err_usage);
exit(ok);
}
int main(int argc, char *argv[])
{
int rc = ok;
int oldroot = -1;
char *newroot = NULL;
char *failscript = NULL;
char *failscriptargs[] = { NULL, NULL };
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-f")
|| !strcmp(argv[i], "--failscript")) {
failscript = argv[++i];
} else if (!strncmp(argv[i], "--failscript=", 13)) {
failscript = argv[i] + 13;
} else if (!strcmp(argv[i], "--help")
|| !strcmp(argv[i], "-h")
|| !strcmp(argv[i], "--usage")) {
usage(stdout);
} else if (!strcmp(argv[i], "-n")
|| !strcmp(argv[i], "--newroot")) {
newroot = argv[++i];
} else if (!strncmp(argv[i], "--newroot=", 10)) {
newroot = argv[i] + 10;
} else {
usage(stderr);
}
}
if (failscript != NULL && failscript[0] == '\0') {
failscript == NULL;
}
if (newroot == NULL || newroot[0] == '\0') {
usage(stderr);
}
if (failscript) {
if (access(failscript, F_OK|X_OK)) {
fprintf(stderr, "Error: Cannot access failure script \"%s\": %m\n", failscript);
} else if ((oldroot = open("/", O_RDONLY)) < 0) {
fprintf(stderr, "Error: Cannot open root directory: %m\n");
}
}
rc = switchroot(newroot);
if (oldroot >= 0) {
fchdir(oldroot);
close(oldroot);
failscriptargs[0] = failscript;
execv(failscript, failscriptargs);
}
fprintf(stderr, "Booting has failed. Sorry.\n");
while (1) {
sleep(60);
}
return rc;
}
/*
* vim:noet:ts=8:sw=8:sts=8
*/