summaryrefslogtreecommitdiffstats
path: root/loader/init.c
diff options
context:
space:
mode:
authorMatt Wilson <msw@redhat.com>1999-05-06 18:50:50 +0000
committerMatt Wilson <msw@redhat.com>1999-05-06 18:50:50 +0000
commit3a8069a96bd89cf4fdedf03eccc7781d17fec6a7 (patch)
treebc8a9fd486a54535a719c838663728d32b5b0448 /loader/init.c
parenta47ebb82d8e73b4a940baeec26584b53908865b1 (diff)
downloadanaconda-3a8069a96bd89cf4fdedf03eccc7781d17fec6a7.tar.gz
anaconda-3a8069a96bd89cf4fdedf03eccc7781d17fec6a7.tar.xz
anaconda-3a8069a96bd89cf4fdedf03eccc7781d17fec6a7.zip
beginnings of new stage1
Diffstat (limited to 'loader/init.c')
-rw-r--r--loader/init.c759
1 files changed, 759 insertions, 0 deletions
diff --git a/loader/init.c b/loader/init.c
new file mode 100644
index 000000000..1b653f319
--- /dev/null
+++ b/loader/init.c
@@ -0,0 +1,759 @@
+/*
+ * init.c
+ *
+ * This is the install type init
+ *
+ * Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#if USE_MINILIBC
+#include "minilibc.h"
+#else
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/klog.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/reboot.h>
+#include <termios.h>
+
+
+#define syslog klogctl
+#endif
+
+#define KICK_FLOPPY 1
+#define KICK_BOOTP 2
+
+#define MS_REMOUNT 32
+
+#define ENV_PATH 0
+#define ENV_LD_LIBRARY_PATH 1
+#define ENV_HOME 2
+#define ENV_TERM 3
+#define ENV_DEBUG 4
+
+char * environ[] = {
+ "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
+ "/mnt/bin:/mnt/usr/bin",
+ "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib",
+ "HOME=/",
+ "TERM=linux",
+ "DEBUG=",
+ NULL
+};
+
+
+/*
+ * this needs to handle the following cases:
+ *
+ * 1) run from a CD root filesystem
+ * 2) run from a read only nfs rooted filesystem
+ * 3) run from a floppy
+ * 4) run from a floppy that's been loaded into a ramdisk
+ *
+ */
+
+int testing;
+
+void printstr(char * string) {
+ write(1, string, strlen(string));
+}
+
+void fatal_error(int usePerror) {
+/* FIXME */
+#if 0
+ if (usePerror)
+ perror("failed:");
+ else
+#endif
+ printf("failed.\n");
+
+ printf("\nI can't recover from this.\n");
+ while (1) ;
+}
+
+int doMke2fs(char * device, char * size) {
+ char * args[] = { "/usr/bin/mke2fs", NULL, NULL, NULL };
+ int pid, status;
+
+ args[1] = device;
+ args[2] = size;
+
+ if (!(pid = fork())) {
+ /* child */
+ execve("/usr/bin/mke2fs", args, environ);
+ fatal_error(1);
+ }
+
+ wait4(-1, &status, 0, NULL);
+
+ return 0;
+}
+
+int hasNetConfiged(void) {
+ int rc;
+ int s;
+ struct ifconf configs;
+ struct ifreq devs[10];
+
+ #ifdef __i386__
+ return 0;
+ #endif
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ /* FIXME was perror*/
+ printf("error creating socket: %d\n", errno);
+ return 0;
+ } else {
+ /* this is just good enough to tell us if we have anything
+ configured */
+ configs.ifc_len = sizeof(devs);
+ configs.ifc_buf = (void *) devs;
+
+ rc = ioctl(s, SIOCGIFCONF, &configs);
+ if (rc < 0) {
+ /* FIXME was perror*/
+ printstr("SIOCGIFCONF");
+ return 0;
+ }
+ if (configs.ifc_len == 0) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void doklog(char * fn) {
+ fd_set readset, unixs;
+ int in, out, i;
+ int log;
+ int s;
+ int sock = -1;
+ struct sockaddr_un sockaddr;
+ char buf[1024];
+ int readfd;
+
+ in = open("/proc/kmsg", O_RDONLY,0);
+ if (in < 0) {
+ /* FIXME: was perror */
+ printstr("open /proc/kmsg");
+ return;
+ }
+
+ out = open(fn, O_WRONLY, 0);
+ if (out < 0)
+ printf("couldn't open %s for syslog -- still using /tmp/syslog\n", fn);
+
+ log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644);
+ if (log < 0) {
+ /* FIXME: was perror */
+ printstr("error opening /tmp/syslog");
+ sleep(5);
+
+ close(in);
+ return;
+ }
+
+ /* if we get this far, we should be in good shape */
+
+ if (fork()) {
+ /* parent */
+ close(in);
+ close(out);
+ close(log);
+ return;
+ }
+ close(0);
+ close(1);
+ close(2);
+
+ dup2(1, log);
+
+#if defined(USE_LOGDEV)
+ /* now open the syslog socket */
+ sockaddr.sun_family = AF_UNIX;
+ strcpy(sockaddr.sun_path, "/dev/log");
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ printf("error creating socket: %d\n", errno);
+ sleep(5);
+ }
+ printstr("got socket\n");
+ if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) +
+ strlen(sockaddr.sun_path))) {
+ printf("bind error: %d\n", errno);
+ sleep(5);
+ }
+ printstr("bound socket\n");
+ chmod("/dev/log", 0666);
+ if (listen(sock, 5)) {
+ printf("listen error: %d\n", errno);
+ sleep(5);
+ }
+#endif
+
+ syslog(8, NULL, 1);
+
+ FD_ZERO(&unixs);
+ while (1) {
+ memcpy(&readset, &unixs, sizeof(unixs));
+
+ if (sock >= 0) FD_SET(sock, &readset);
+ FD_SET(in, &readset);
+
+ i = select(20, &readset, NULL, NULL, NULL);
+ if (i <= 0) continue;
+
+ if (FD_ISSET(in, &readset)) {
+ i = read(in, buf, sizeof(buf));
+ if (i > 0) {
+ if (out >= 0) write(out, buf, i);
+ write(log, buf, i);
+ }
+ }
+
+ for (readfd = 0; readfd < 20; ++readfd) {
+ if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
+ i = read(readfd, buf, sizeof(buf));
+ if (i > 0) {
+ if (out >= 0) {
+ write(out, buf, i);
+ write(out, "\n", 1);
+ }
+
+ write(log, buf, i);
+ write(log, "\n", 1);
+ } else if (i == 0) {
+ /* socket closed */
+ close(readfd);
+ FD_CLR(readfd, &unixs);
+ }
+ }
+ }
+
+ if (sock >= 0 && FD_ISSET(sock, &readset)) {
+ s = sizeof(sockaddr);
+ readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
+ if (readfd < 0) {
+ if (out >= 0) write(out, "error in accept\n", 16);
+ write(log, "error in accept\n", 16);
+ close(sock);
+ sock = -1;
+ } else {
+ FD_SET(readfd, &unixs);
+ }
+ }
+ }
+}
+
+#if defined(__alpha__)
+char * findKernel(void) {
+ char * dev, * file;
+ struct stat sb;
+
+ dev = getenv("bootdevice");
+ file = getenv("bootfile");
+
+ if (!dev || !file) {
+ printf("I can't find your kernel. When you are booting"
+ " from a CDROM, you must pass\n");
+ printf("the bootfile argument to the kernel if your"
+ " boot loader doesn't do so automatically.\n");
+ printf("\n");
+ printf("You should now reboot your system and try "
+ "again\n");
+
+ while (1) ;
+ }
+
+ if (!strcmp(dev, "fd0")) {
+ if (!strcmp(file, "vmlinux.gz")) {
+ printf("The kernel on a boot floppy must be named vmlinux.gz. "
+ "You\n");
+ printf("are using a kernel named %s instead. You'll have "
+ "to\n", file);
+ printf("fix this and try again.\n");
+
+ while (1) ;
+ }
+
+ return NULL;
+ } else {
+ if (stat(file, &sb)) {
+ printf("I can't find your kernel. When you are booting"
+ " from a CDROM, you must pass\n");
+ printf("the bootfile argument to the kernel if your"
+ " boot loader doesn't do so automatically.\n");
+ printf("\n");
+ printf("You should now reboot your system and try "
+ "again\n");
+
+ while (1) ;
+ }
+
+ return file;
+ }
+}
+#endif
+
+int setupTerminal(int fd) {
+ struct winsize winsize;
+
+ if (ioctl(fd, TIOCGWINSZ, &winsize)) {
+ printf("failed to get winsize");
+ fatal_error(1);
+ }
+
+ winsize.ws_row = 24;
+ winsize.ws_col = 80;
+
+ if (ioctl(fd, TIOCSWINSZ, &winsize)) {
+ printf("failed to set winsize");
+ fatal_error(1);
+ }
+
+ environ[ENV_TERM] = "TERM=vt100";
+
+ return 0;
+}
+
+void unmountFilesystems(void) {
+ int fd, size;
+ char buf[65535]; /* this should be big enough */
+ char * chptr, * start;
+ struct {
+ char * name;
+ int len;
+ } filesystems[500], tmp;
+ int numFilesystems = 0;
+ int i, j;
+
+ fd = open("/proc/mounts", O_RDONLY, 0);
+ if (fd < 1) {
+ /* FIXME: was perror */
+ printstr("failed to open /proc/mounts");
+ sleep(2);
+ return;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+
+ close(fd);
+
+ chptr = buf;
+ while (*chptr) {
+ while (*chptr != ' ') chptr++;
+ chptr++;
+ start = chptr;
+ while (*chptr != ' ') chptr++;
+ *chptr++ = '\0';
+ filesystems[numFilesystems].name = start;
+ filesystems[numFilesystems].len = strlen(start);
+ numFilesystems++;
+ while (*chptr != '\n') chptr++;
+ chptr++;
+ }
+
+ /* look ma, a *bubble* sort */
+ for (i = 0; i < (numFilesystems - 1); i++) {
+ for (j = i; j < numFilesystems; j++) {
+ if (filesystems[i].len < filesystems[j].len) {
+ tmp = filesystems[i];
+ filesystems[i] = filesystems[j];
+ filesystems[j] = tmp;
+ }
+ }
+ }
+
+ /* -1 because the last one will always be '/' */
+ for (i = 0; i < numFilesystems - 1; i++) {
+ printf("\t%s", filesystems[i].name);
+ /* don't need to unmount /tmp. it is busy anyway. */
+ if (!testing && strncmp(filesystems[i].name, "/tmp", 4)) {
+ if (umount(filesystems[i].name) < 0) {
+ /* FIXME printf(" failed: %s", strerror(errno));*/
+ printstr(" umount failed");
+ }
+ }
+ printf("\n");
+ }
+}
+
+void readargs(int * isRescue, int * isSerial, int * isExpert, int * isKick,
+ int * forceSupp, int * isNetwork) {
+ char buf[512];
+ char * arg;
+ int fd;
+ int size;
+ int done = 0;
+ char * start, * end;
+
+ printf("opening /proc/cmdline... ");
+
+ if ((fd = open("/proc/cmdline", O_RDONLY, 0)) < 0) fatal_error(1);
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+ close(fd);
+
+ printf("done\n");
+
+ printf("checking command line arguments... ");
+ start = buf;
+
+ while (!done) {
+ while (*start && isspace(*start)) start++;
+ if (!(*start)) break;
+
+ end = start;
+ while (*end && !isspace(*end) && *end != '\n') end++;
+
+ if (!*end) done = 1;
+ *end = '\0';
+
+ if (!*start ||
+ !strcmp(start, "auto") ||
+ !strncmp(start, "BOOT_IMAGE", 10) ||
+ !strncmp(start, "initrd=", 7) ||
+ !strncmp(start, "bootdevice=", 11) ||
+ !strncmp(start, "bootfile=", 9) ||
+ !strcmp(start, "ro") ||
+ !strncmp(start, "root=", 5) ||
+ !strncmp(start, "mem=", 4) ||
+ !strncmp(start, "hda=", 4) ||
+ !strncmp(start, "hdb=", 4) ||
+ !strncmp(start, "hdc=", 4) ||
+ !strncmp(start, "hdd=", 4) ||
+ !strncmp(start, "load_ramdisk", 12) ||
+ !strncmp(start, "prompt_ramdisk", 14)) {
+ /* lilo does this for us -- we don't care */
+ } else if (!strcmp(start, "debug")) {
+ printf("\n\tdebug disk mode enabled");
+ environ[ENV_DEBUG] = "DEBUG=1";
+ } else if (!strcmp(start, "rescue")) {
+ printf("\n\trescue disk mode enabled");
+ *isRescue = 1;
+ } else if (!strcmp(start, "serial")) {
+ printf("\n\tserial mode enabled");
+ *isSerial = 1;
+ } else if (!strcmp(start, "expert")) {
+ printf("\n\texpert mode enabled");
+ *isExpert = 1;
+ } else if (!strcmp(start, "supp")) {
+ *forceSupp = 1;
+ } else if (!strcmp(start, "local")) {
+ *isNetwork = 0;
+ } else if (!strcmp(start, "network")) {
+ *isNetwork = 1;
+ } else if (!strncmp(start, "kickstart", 9) ||
+ !strncmp(start, "ks", 2)) {
+ arg = strchr(start, '=');
+
+ if (arg) {
+ *isKick = KICK_FLOPPY;
+ printf("\n\ta floppy kickstart install will be performed");
+ } else {
+ *isKick = KICK_BOOTP;
+ printf("\n\ta bootp kickstart install will be performed");
+ }
+ } else {
+ printf("\n\tunknown option '%s'!", start);
+ sleep(5);
+ }
+
+ start = end + 1;
+ }
+ printf("done\n");
+}
+
+int main(void) {
+ pid_t installpid, childpid;
+ int waitStatus;
+ int fd;
+ int nfsRoot = 0;
+ int roRoot = 0;
+ int cdRoot = 0;
+ int isRescue = 0;
+ int isSerial = 0;
+ int isExpert = 0;
+ int isKick = 0;
+ int isNetwork = 0;
+ int doReboot = 0;
+ int doShutdown =0;
+ int forceSupp = 0;
+#ifdef __alpha__
+ char * kernel;
+#endif
+ char * argv[15];
+ char ** argvp = argv;
+
+ /* getpid() != 1 should work, by linuxrc tends to get a larger pid */
+ testing = (getpid() > 50);
+
+ if (!testing) {
+ /* turn off screen blanking */
+ printstr("\033[9;0]");
+ printstr("\033[8]");
+ }
+
+ printstr("hello\n");
+
+ printf("Red Hat install init version %s starting\n", VERSION);
+
+ printf("mounting /proc filesystem... ");
+
+ if (!testing) {
+ if (mount("/proc", "/proc", "proc", 0, NULL))
+ fatal_error(1);
+ }
+
+ printf("done\n");
+
+ readargs(&isRescue, &isSerial, &isExpert, &isKick, &forceSupp, &isNetwork);
+
+ if (isSerial) {
+ fd = open("/dev/ttyS0", O_RDWR, 0);
+ if (fd < 0) {
+ printf("failed to open /dev/ttyS0");
+ fatal_error(1);
+ }
+ write(fd, "Switching to serial console...", 29);
+
+ /* gulp */
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ printf("done\n\n");
+
+ printf("Red Hat install init version %s using a serial console\n",
+ VERSION);
+
+ printf("remember, cereal is an important part of a nutritionally "
+ "balanced breakfast.\n\n");
+
+ setupTerminal(0);
+
+ close(fd);
+ }
+
+ if (!testing) {
+ sethostname("localhost.localdomain", 21);
+ /* the default domainname (as of 2.0.35) is "(none)", which confuses
+ glibc */
+ setdomainname("", 0);
+ }
+
+ printf("checking for NFS root filesystem...");
+ if (hasNetConfiged()) {
+ printf("yes\n");
+ roRoot = nfsRoot = 1;
+ } else {
+ printf("no\n");
+ }
+
+ if (!nfsRoot) {
+ printf("trying to remount root filesystem read write... ");
+ if (mount("/", "/", NULL, MS_REMOUNT | MS_MGC_VAL, NULL)) {
+ printf("failed (but that's okay)\n");
+
+ roRoot = 1;
+ } else {
+ printf("done\n");
+
+ /* 2.0.18 (at least) lets us remount a CD r/w!! */
+ printf("checking for writeable /tmp... ");
+ fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ printf("no (probably a CD rooted install)\n");
+ roRoot = 1;
+ } else {
+ close(fd);
+ unlink("/tmp/tmp");
+ printf("yes\n");
+ }
+ }
+ }
+
+ if (!testing && roRoot) {
+ printf("creating 300k of ramdisk space... ");
+ if (doMke2fs("/dev/ram", "300"))
+ fatal_error(0);
+
+ printf("done\n");
+
+ printf("mounting /tmp from ramdisk... ");
+ if (mount("/dev/ram", "/tmp", "ext2", 0, NULL))
+ fatal_error(1);
+
+ printf("done\n");
+
+ if (!nfsRoot) cdRoot = 1;
+ }
+
+ /* Now we have some /tmp space set up, and /etc and /dev point to
+ it. We should be in pretty good shape. */
+
+ if (!testing)
+ doklog("/dev/tty4");
+
+ /* Go into normal init mode - keep going, and then do a orderly shutdown
+ when:
+
+ 1) /bin/install exits
+ 2) we receive a SIGHUP
+ */
+
+ printf("running install...\n");
+
+ if (!(installpid = fork())) {
+ /* child */
+ if (!isSerial) {
+ fd = open("/dev/tty1", O_RDWR, 0);
+ if (fd < 0) {
+ printf("failed to open /dev/tty1");
+ fatal_error(1);
+ }
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL)) {
+ printf("could not set new controlling tty");
+ }
+
+ setsid();
+ close(fd);
+ }
+
+ if (0 && (nfsRoot || cdRoot)) {
+ symlink("/", "/tmp/rhimage");
+ symlink("/", "/tmp/image");
+
+ *argvp++ = "/usr/bin/runinstall2";
+ *argvp++ = argv[0];
+ *argvp++ = "--method";
+ *argvp++ = nfsRoot ? "nfs" : "cdrom";
+
+#if 0 /* we don't need this anymore */
+# if defined(__alpha__)
+ if (cdRoot && (kernel = findKernel())) {
+ *argvp++ = "--kernel";
+ *argvp++ = kernel;
+ }
+# endif
+#endif /* not needed */
+ } else {
+ *argvp++ = "/bin/loader";
+ }
+
+ if (isRescue)
+ *argvp++ = "--rescue";
+
+ if (isExpert) *argvp++ = "--expert";
+ if (forceSupp) *argvp++ = "--forcesupp";
+ if (isKick == KICK_FLOPPY)
+ *argvp++ = "--ks=floppy";
+ else if (isKick)
+ *argvp++ = "--ks=bootp";
+
+#ifdef __i386__
+ if (isNetwork)
+ *argvp++ = "--network";
+ else
+ *argvp++ = "--local";
+#endif
+
+ *argvp++ = NULL;
+
+ execve(argv[0], argv, environ);
+
+ exit(0);
+ }
+
+ while (!doShutdown) {
+ childpid = wait4(-1, &waitStatus, 0, NULL);
+
+ if (childpid == installpid)
+ doShutdown = 1;
+ }
+
+ if (!WIFEXITED(waitStatus) || WEXITSTATUS(waitStatus)) {
+ printf("install exited abnormally ");
+ if (WIFSIGNALED(waitStatus)) {
+ printf("-- recieved signal %d", WTERMSIG(waitStatus));
+ }
+ printf("\n");
+ } else {
+ doReboot = 1;
+ }
+
+ if (testing)
+ exit(0);
+
+ sync(); sync();
+
+ if (!testing) {
+ printf("sending termination signals...");
+ kill(-1, 15);
+ sleep(2);
+ printf("done\n");
+
+ printf("sending kill signals...");
+ kill(-1, 9);
+ sleep(2);
+ printf("done\n");
+ }
+
+ printf("unmounting filesystems...\n");
+ unmountFilesystems();
+
+ if (doReboot) {
+ printf("rebooting system\n");
+ sleep(2);
+
+ #if USE_MINILIBC
+ reboot(0xfee1dead, 672274793, 0x1234567);
+ #else
+ reboot(RB_AUTOBOOT);
+ #endif
+ } else {
+ printf("you may safely reboot your system\n");
+ while (1);
+ }
+
+ exit(0);
+
+ return 0;
+}