blob: 0ad3151694c509e96cfa5426b84e43a8f6976e74 [file] [log] [blame]
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#include <limits.h>
#include "kinit.h"
#include "ipconfig.h"
static const char *progname = "kinit";
int mnt_procfs;
int mnt_sysfs;
void dump_args(int argc, char *argv[])
{
(void) argc;
(void) argv;
#ifdef INI_DEBUG
int i;
printf("%s: argc == %d\n", argv[0], argc);
for (i = 1; i < argc; i++) {
printf(" argv[%d]: '%s'\n", i, argv[i]);
}
#endif
}
static int do_ipconfig(int argc, char *argv[])
{
int i, a = 1;
argv[0] = (char *) "IP-Config";
DEBUG(("Running ipconfig\n"));
#ifdef INI_DEBUG
argv[a++] = (char *) "-n";
#endif
for (i = 1; i < argc; i++) {
if (strncmp(argv[i], "ip=", 3) == 0 ||
strncmp(argv[i], "nfsaddrs=", 9) == 0) {
argv[a++] = argv[i];
}
}
if (a > 1) {
argv[a] = NULL;
dump_args(a, argv);
return ipconfig_main(a, argv);
}
return 0;
}
static int split_cmdline(int *cmdc, char *cmdv[],
char *cmdline,
int argc, char *argv[])
{
char was_space = 1;
char *i = cmdline;
int vmax = *cmdc;
int v = 1, a;
if ( cmdv )
cmdv[0] = argv[0];
while (i && *i && v < vmax) {
if ((*i == ' ' || *i == '\t') && !was_space) {
if ( cmdv )
*i = '\0';
was_space = 1;
} else if (was_space) {
if ( cmdv )
cmdv[v] = i;
v++;
was_space = 0;
}
i++;
}
for (a = 1; a < argc && v < vmax; a++) {
if ( cmdv )
cmdv[v] = argv[a];
v++;
}
if ( cmdv )
cmdv[v] = NULL;
return *cmdc = v;
}
static int mount_sys_fs(const char *check, const char *fsname,
const char *fstype)
{
struct stat st;
if (stat(check, &st) == 0) {
return 0;
}
mkdir(fsname, 0555);
if (mount("none", fsname, fstype, 0, NULL) == -1) {
fprintf(stderr, "%s: could not mount %s as %s\n",
progname, fsname, fstype);
return -1;
}
return 1;
}
static char *get_kernel_cmdline(char *buf, int len)
{
FILE *fp;
if ((fp = fopen("/proc/cmdline", "r")) == NULL) {
fprintf(stderr, "%s: could not open kernel command line\n",
progname);
buf = NULL;
goto bail;
}
if (fgets(buf, len, fp) == NULL) {
buf = NULL;
goto bail;
}
len = strlen(buf);
if (buf[len - 1] == '\n') {
buf[--len] = '\0';
}
bail:
if (fp) {
fclose(fp);
}
return buf;
}
static void save_cmdline(char **saved, int cmdc, char *cmdv[])
{
int i;
int len;
char *x;
for (i = len = 0; i < cmdc; i++)
len += strlen(cmdv[i]) + 1;
if ((x = *saved = malloc(len)) == NULL) {
perror("malloc");
exit(1);
}
for (i = 0; i < cmdc; i++) {
strcpy(x, cmdv[i]);
x += strlen(x) + 1;
}
}
static void restore_cmdline(char *saved, int cmdc, char *cmdv[])
{
int i;
optind = 1;
for (i = 0; i < cmdc; i++) {
cmdv[i] = saved;
saved += strlen(saved) + 1;
}
cmdv[cmdc] = NULL;
}
/* Was this argument passed? */
char *get_arg(int argc, char *argv[], const char *name)
{
int len = strlen(name);
char *ret = NULL;
int i;
for (i = 1; i < argc; i++) {
if (argv[i] && strncmp(argv[i], name, len) == 0 &&
(argv[i][len] == '\0')) {
ret = argv[i] + len;
break;
}
}
return ret;
}
static void check_path(const char *path)
{
struct stat st;
if (stat(path, &st) == -1) {
if (errno != ENOENT) {
perror("stat");
exit(1);
}
if (mkdir(path, 0755) == -1) {
perror("mkdir");
exit(1);
}
}
else if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "NFS-Root: '%s' not a directory\n", path);
exit(1);
}
}
int main(int argc, char *argv[])
{
char **cmdv, *saved;
char *kinit = NULL;
char buf[1024];
char *cmdline;
int ret = 0;
int cmdc;
int fd;
int i;
if ((fd = open("/dev/console", O_RDWR)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) {
close(fd);
}
}
if ((mnt_procfs = mount_sys_fs("/proc/cmdline", "/proc", "proc")) == -1) {
ret = 1;
goto bail;
}
if ((mnt_sysfs = mount_sys_fs("/sys/bus", "/sys", "sysfs")) == -1) {
ret = 1;
goto bail;
}
if ((cmdline = get_kernel_cmdline(buf, sizeof(buf))) == NULL) {
ret = 1;
goto bail;
}
cmdc = INT_MAX;
cmdv = (char **) alloca(sizeof(char *) *
(split_cmdline(&cmdc, NULL, cmdline, argc, argv+1)));
if (split_cmdline(&cmdc, cmdv, cmdline, argc, argv) == 0) {
ret = 1;
goto bail;
}
save_cmdline(&saved, cmdc, cmdv);
do_ipconfig(cmdc, cmdv);
restore_cmdline(saved, cmdc, cmdv);
check_path("/root");
check_path("/old_root");
do_mounts(cmdc, cmdv);
#ifndef INI_DEBUG
if (pivot_root(".", "old_root") == -1) {
perror("pivot_root");
ret = 2;
goto bail;
}
if (mnt_procfs == 1)
umount2("/proc", 0);
if (mnt_sysfs == 1)
umount2("/sys", 0);
for (i = 1; i < cmdc; i++) {
if (strncmp(cmdv[i], "kinit=", 6) == 0) {
kinit = cmdv[i] + 6;
}
}
if (kinit) {
char *s = strrchr(kinit, '/');
if (s) {
s++;
}
execl(kinit, s, NULL);
}
execl("/sbin/init", "init", NULL);
execl("/etc/init", "init", NULL);
execl("/bin/init", "init", NULL);
execl("/bin/sh", "sh", NULL);
fprintf(stderr, "%s: I give up - there's nothing to run.\n", progname);
ret = 2;
goto done;
#else
printf("%s: imagine pivot_root and exec\n", progname);
#endif
bail:
if (mnt_procfs == 1)
umount2("/proc", 0);
if (mnt_sysfs == 1)
umount2("/sys", 0);
done:
exit(ret);
}