/* * 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 */