Stuf
authorEric Andersen <andersen@codepoet.org>
Mon, 25 Oct 1999 23:32:44 +0000 (23:32 -0000)
committerEric Andersen <andersen@codepoet.org>
Mon, 25 Oct 1999 23:32:44 +0000 (23:32 -0000)
13 files changed:
Changelog
Makefile
applets/busybox.c
busybox.c
busybox.def.h
chvt.c [new file with mode: 0644]
console-tools/chvt.c [new file with mode: 0644]
console-tools/deallocvt.c [new file with mode: 0644]
deallocvt.c [new file with mode: 0644]
init.c
init/init.c
internal.h
utility.c

index 9714b46..0f3b1e0 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -4,6 +4,9 @@
        * Fixed mkdir -m option so that it works.
        * kill segfaulted w/o any arguments.  Now it doesn't do that.
        * kill wasn't properly accepting signal names.  It does now.
+       * Added new apps chvt and deallocvt
+       * Major adjustment of init.c.  Code is now readable IMHO,
+           and much more solid.
 
         -Erik Andersen
 
index 0d8d3fb..bcd62bf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ BUILDTIME=$(shell date "+%Y%m%d-%H%M")
 
 # Comment out the following to make a debuggable build
 # Leave this off for production use.
-DODEBUG=false
+DODEBUG=true
 # If you want a static binary, turn this on.  I can't think
 # of many situations where anybody would ever want it static, 
 # but...
index d4313ef..05144c4 100644 (file)
@@ -51,6 +51,12 @@ static const struct Applet applets[] = {
 #ifdef BB_FIND                 //usr/bin
     {"find", find_main},
 #endif
+#ifdef BB_CHVT                 //usr/bin
+    {"chvt", chvt_main},
+#endif
+#ifdef BB_DEALLOCVT                    //usr/bin
+    {"deallocvt", deallocvt_main},
+#endif
 #ifdef BB_FSCK_MINIX           //sbin
     {"fsck.minix", fsck_minix_main},
 #endif
@@ -156,6 +162,9 @@ static const struct Applet applets[] = {
     {"true", true_main},
     {"false", false_main},
 #endif
+#ifdef BB_UNAME                        //bin
+    {"uname",  uname_main},
+#endif
 #ifdef BB_UMOUNT               //bin
     {"umount",  umount_main},
 #endif
index d4313ef..05144c4 100644 (file)
--- a/busybox.c
+++ b/busybox.c
@@ -51,6 +51,12 @@ static const struct Applet applets[] = {
 #ifdef BB_FIND                 //usr/bin
     {"find", find_main},
 #endif
+#ifdef BB_CHVT                 //usr/bin
+    {"chvt", chvt_main},
+#endif
+#ifdef BB_DEALLOCVT                    //usr/bin
+    {"deallocvt", deallocvt_main},
+#endif
 #ifdef BB_FSCK_MINIX           //sbin
     {"fsck.minix", fsck_minix_main},
 #endif
@@ -156,6 +162,9 @@ static const struct Applet applets[] = {
     {"true", true_main},
     {"false", false_main},
 #endif
+#ifdef BB_UNAME                        //bin
+    {"uname",  uname_main},
+#endif
 #ifdef BB_UMOUNT               //bin
     {"umount",  umount_main},
 #endif
index 845e463..a79eaaf 100644 (file)
@@ -18,6 +18,8 @@
 #define BB_FIND
 //#define BB_FSCK_MINIX
 //#define BB_MKFS_MINIX
+#define BB_CHVT
+#define BB_DEALLOCVT
 #define BB_GREP
 //#define BB_HALT
 #define BB_INIT
@@ -53,6 +55,7 @@
 //#define BB_TRUE_FALSE  // Supplied by ash
 #define BB_UMOUNT
 #define BB_UPDATE
+#define BB_UNAME
 #define BB_ZCAT
 //#define BB_GZIP
 // Don't turn BB_UTILITY off.  It contains support code 
diff --git a/chvt.c b/chvt.c
new file mode 100644 (file)
index 0000000..81d1995
--- /dev/null
+++ b/chvt.c
@@ -0,0 +1,36 @@
+/*
+ * chvt.c - aeb - 940227 - Change virtual terminal
+ *
+ * busyboxed by Erik Andersen
+ */
+#include "internal.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+extern int getfd(void);
+
+int
+chvt_main(int argc, char** argv) 
+{
+    int fd, num;
+
+    if ( ( argc != 2) || (**(argv+1) == '-' ) ) {
+       usage ("chvt </dev/ttyN>\n");
+    }
+    fd = get_console_fd("/dev/console");
+    num = atoi(argv[1]);
+    if (ioctl(fd,VT_ACTIVATE,num)) {
+       perror("VT_ACTIVATE");
+       exit(FALSE);
+    }
+    if (ioctl(fd,VT_WAITACTIVE,num)) {
+       perror("VT_WAITACTIVE");
+       exit(FALSE);
+    }
+    exit( TRUE);
+}
+
diff --git a/console-tools/chvt.c b/console-tools/chvt.c
new file mode 100644 (file)
index 0000000..81d1995
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * chvt.c - aeb - 940227 - Change virtual terminal
+ *
+ * busyboxed by Erik Andersen
+ */
+#include "internal.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+extern int getfd(void);
+
+int
+chvt_main(int argc, char** argv) 
+{
+    int fd, num;
+
+    if ( ( argc != 2) || (**(argv+1) == '-' ) ) {
+       usage ("chvt </dev/ttyN>\n");
+    }
+    fd = get_console_fd("/dev/console");
+    num = atoi(argv[1]);
+    if (ioctl(fd,VT_ACTIVATE,num)) {
+       perror("VT_ACTIVATE");
+       exit(FALSE);
+    }
+    if (ioctl(fd,VT_WAITACTIVE,num)) {
+       perror("VT_WAITACTIVE");
+       exit(FALSE);
+    }
+    exit( TRUE);
+}
+
diff --git a/console-tools/deallocvt.c b/console-tools/deallocvt.c
new file mode 100644 (file)
index 0000000..a8feeb5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
+ * Renamed deallocvt.
+ */
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <stdio.h>
+
+extern int getfd(void);
+char *progname;
+
+int
+deallocvt_main(int argc, char *argv[]) {
+    int fd, num, i;
+
+    if (argc < 1)              /* unlikely */
+      exit(1);
+    progname = argv[0];
+
+    fd = get_console_fd("/dev/console");
+
+    if (argc == 1) {
+       /* deallocate all unused consoles */
+       if (ioctl(fd,VT_DISALLOCATE,0)) {
+           perror("VT_DISALLOCATE");
+           exit(1);
+       }
+    } else
+    for (i = 1; i < argc; i++) {
+       num = atoi(argv[i]);
+       if (num == 0)
+           fprintf(stderr, "%s: 0: illegal VT number\n", progname);
+       else if (num == 1)
+           fprintf(stderr, "%s: VT 1 cannot be deallocated\n", progname);
+       else
+       if (ioctl(fd,VT_DISALLOCATE,num)) {
+           perror("VT_DISALLOCATE");
+           fprintf(stderr, "%s: could not deallocate console %d\n",
+                   progname, num);
+           exit(1);
+       }
+    }
+    exit(0);
+}
diff --git a/deallocvt.c b/deallocvt.c
new file mode 100644 (file)
index 0000000..a8feeb5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s)
+ * Renamed deallocvt.
+ */
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <stdio.h>
+
+extern int getfd(void);
+char *progname;
+
+int
+deallocvt_main(int argc, char *argv[]) {
+    int fd, num, i;
+
+    if (argc < 1)              /* unlikely */
+      exit(1);
+    progname = argv[0];
+
+    fd = get_console_fd("/dev/console");
+
+    if (argc == 1) {
+       /* deallocate all unused consoles */
+       if (ioctl(fd,VT_DISALLOCATE,0)) {
+           perror("VT_DISALLOCATE");
+           exit(1);
+       }
+    } else
+    for (i = 1; i < argc; i++) {
+       num = atoi(argv[i]);
+       if (num == 0)
+           fprintf(stderr, "%s: 0: illegal VT number\n", progname);
+       else if (num == 1)
+           fprintf(stderr, "%s: VT 1 cannot be deallocated\n", progname);
+       else
+       if (ioctl(fd,VT_DISALLOCATE,num)) {
+           perror("VT_DISALLOCATE");
+           fprintf(stderr, "%s: could not deallocate console %d\n",
+                   progname, num);
+           exit(1);
+       }
+    }
+    exit(0);
+}
diff --git a/init.c b/init.c
index c32124d..0676bf7 100644 (file)
--- a/init.c
+++ b/init.c
 #include <sys/vt.h>            /* for vt_stat */
 #include <sys/ioctl.h>
 
-static const char  init_usage[] = "Used internally by the system.";
-static char        console[16] = "";
-static const char* default_console = "/dev/tty2";
-static char*       first_terminal = NULL;
-static const char* second_terminal = "/dev/tty2";
-static const char* log = "/dev/tty3";
-static char* term_ptr = NULL;
+#define DEBUG_INIT
 
-static void
-message(const char* terminal, const char * pattern, ...)
-{
-       int     fd;
-       FILE *  con = 0;
-       va_list arguments;
-
-       /*
-        * Open the console device each time a message is printed. If the user
-        * has switched consoles, the open will get the new console. If we kept
-        * the console open, we'd always print to the same one.
-        */
-       if ( !terminal
-        ||  ((fd = open(terminal, O_WRONLY|O_NOCTTY)) < 0)
-        ||  ((con = fdopen(fd, "w")) == NULL) )
-               return;
+#define CONSOLE         "/dev/console"          /* Logical system console */
+#define VT_PRIMARY      "/dev/tty0"             /* Virtual console master */
+#define VT_SECONDARY    "/dev/tty1"             /* Virtual console master */
+#define VT_LOG          "/dev/tty2"             /* Virtual console master */
+#define SHELL           "/bin/sh"               /* Default shell */
+#define INITSCRIPT      "/etc/init.d/rcS"       /* Initscript. */
+#define PATH_DEFAULT    "PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin"
 
-       va_start(arguments, pattern);
-       vfprintf(con, pattern, arguments);
-       va_end(arguments);
-       fclose(con);
+static int maxproclen=0;
+static char* argv0;
+
+static char* console = CONSOLE;
+static char* second_terminal = "/dev/tty2";
+static char* log = "/dev/tty3";
+
+
+
+/* try to open up the specified device */
+int device_open(char* device, int mode)
+{
+    int m, f, fd = -1;
+    
+    mode = m | O_NONBLOCK;
+    
+    /* Retry up to 5 times */
+    for(f = 0; f < 5; f++)
+       if ((fd = open(device, m)) >= 0) break;
+    if (fd < 0) return fd;
+    /* Set original flags. */
+    if (m != mode)
+       fcntl(fd, F_SETFL, mode);
+    return fd;
 }
 
-static int
-waitfor(int pid)
+/* print a message to the specified device */
+void message(char* device, char *fmt, ...)
 {
-       int     status;
-       int     wpid;
-       
-       message(log, "Waiting for process %d.\n", pid);
-       while ( (wpid = wait(&status)) != pid ) {
-               if ( wpid > 0 ) {
-                       message(
-                        log
-                       ,"pid %d exited, status=%x.\n"
-                       ,wpid
-                       ,status);
-               }
-       }
-       return wpid;
+    int fd;
+    va_list arguments;
+    if ((fd = device_open(device, O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
+       va_start(arguments, fmt);
+       vdprintf(fd, fmt, arguments);
+       va_end(arguments);
+    }
+    close( fd);
 }
 
-static int
-run(const char* program, const char* const* arguments, 
-       const char* terminal, int get_enter)
+/* Set terminal settings to reasonable defaults */
+void set_term()
 {
-       static const char       control_characters[] = {
-               '\003',
-               '\034',
-               '\177',
-               '\025',
-               '\004',
-               '\0',
-               '\1',
-               '\0',
-               '\021',
-               '\023',
-               '\032',
-               '\0',
-               '\022',
-               '\017',
-               '\027',
-               '\026',
-               '\0'
-       };
-
-       static char * environment[] = {
-               "HOME=/",
-               "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
-               "SHELL=/bin/sh",
-               0,
-               "USER=root",
-               0
-       };
-
-       static const char       press_enter[] =
- "\nPlease press Enter to activate this console. ";
-
-       int     pid;
-
-       environment[3]=term_ptr;
-
-       pid = fork();
-       if ( pid == 0 ) {
-               struct termios  t;
-               const char * const * arg;
-
-               close(0);
-               close(1);
-               close(2);
-               setsid();
-
-               open(terminal, O_RDWR);
-               dup(0);
-               dup(0);
-               tcsetpgrp(0, getpgrp());
-
-               tcgetattr(0, &t);
-               memcpy(t.c_cc, control_characters, sizeof(control_characters));
-               t.c_line = 0;
-               t.c_iflag = ICRNL|IXON|IXOFF;
-               t.c_oflag = OPOST|ONLCR;
-               t.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
-               tcsetattr(0, TCSANOW, &t);
-
-               if ( get_enter ) {
-                       /*
-                        * Save memory by not exec-ing anything large (like a shell)
-                        * before the user wants it. This is critical if swap is not
-                        * enabled and the system has low memory. Generally this will
-                        * be run on the second virtual console, and the first will
-                        * be allowed to start a shell or whatever an init script 
-                        * specifies.
-                        */
-                       char    c;
-                       write(1, press_enter, sizeof(press_enter) - 1);
-                       read(0, &c, 1);
-               }
-               
-               message(log, "Executing ");
-               arg = arguments;
-               while ( *arg != 0 )
-                       message(log, "%s ", *arg++);
-               message(log, "\n");
-
-               execve(program, (char * *)arguments, (char * *)environment);
-               message(log, "%s: could not execute: %s.\r\n", program, strerror(errno));
-               exit(-1);
-       }
-       return pid;
+    int fd;
+    struct termios tty;
+
+    if ((fd = device_open(console, O_RDWR|O_NOCTTY)) < 0) {
+       message(log, "can't open %s", console);
+       return;
+    }
+    ioctl(fd, TCGETS, &tty);
+    tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+    tty.c_cflag |= HUPCL|CLOCAL;
+
+    tty.c_cc[VINTR]  = 3;
+    tty.c_cc[VQUIT]  = 28;
+    tty.c_cc[VERASE] = 127;
+    tty.c_cc[VKILL]  = 24;
+    tty.c_cc[VEOF]   = 4;
+    tty.c_cc[VTIME]  = 0;
+    tty.c_cc[VMIN]   = 1;
+    tty.c_cc[VSTART] = 17;
+    tty.c_cc[VSTOP]  = 19;
+    tty.c_cc[VSUSP]  = 26;
+
+    /* Set pre and post processing */
+    tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+    tty.c_oflag = OPOST|ONLCR;
+    tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+    /* Now set the terminal line. */
+    ioctl(fd, TCSETS, &tty);
+    close( fd);
 }
 
 static int
@@ -217,33 +161,168 @@ set_free_pages()
     fclose(f);
 }
 
+
 static void
-shutdown_system(void)
+console_init()
 {
-       static const char * const umount_args[] = {"/bin/umount", "-a", "-n", 0};
-       static const char * const swapoff_args[] = {"/bin/swapoff", "-a", 0};
+    int fd;
+    int tried_devcons = 0;
+    int tried_vtmaster = 0;
+    char *s;
+
+    if ((s = getenv("CONSOLE")) != NULL)
+       console = s;
+    else {
+       console = CONSOLE;
+       tried_devcons++;
+    }
+    while ((fd = open(console, O_RDONLY|O_NONBLOCK)) < 0) {
+       if (!tried_devcons) {
+           tried_devcons++;
+           console = CONSOLE;
+           continue;
+       }
+       if (!tried_vtmaster) {
+           tried_vtmaster++;
+           console = VT_PRIMARY;
+           continue;
+       }
+       break;
+    }
+    if (fd < 0)
+       console = "/dev/null";
+    else
+       close(fd);
+}
 
-       message(console, "The system is going down NOW !!");
-       sync();
-       /* Allow Ctrl-Alt-Del to reboot system. */
-       reboot(RB_ENABLE_CAD);
+static int
+waitfor(int pid)
+{
+    int status, wpid;
 
-       /* Send signals to every process _except_ pid 1 */
-       message(console, "Sending SIGHUP to all processes.\r\n");
-       kill(-1, SIGHUP);
-       sleep(2);
-       sync();
-       message(console, "Sending SIGKILL to all processes.\r\n");
-       kill(-1, SIGKILL);
-       sleep(1);
-       waitfor(run("/bin/swapoff", swapoff_args, console, 0));
-       waitfor(run("/bin/umount", umount_args, console, 0));
-       sync();
-       if (get_kernel_revision() <= 2*65536+2*256+11) {
-           /* Removed  bdflush call, kupdate in kernels >2.2.11 */
-           bdflush(1, 0);
-           sync();
+    message(log, "Waiting for process %d.\n", pid);
+    while ( (wpid = wait(&status)) != pid ) {
+       if ( wpid > 0 )
+           message(log,"pid %d exited, status=%x.\n", wpid, status);
+    }
+    return wpid;
+}
+
+static int
+run(const char* command, char* terminal, int get_enter)
+{
+    int        f, pid;
+    char *args[16];
+    char buf[256];
+    char* ptr;
+    static const char press_enter[] = 
+       "\nPlease press Enter to activate this console. ";
+
+       
+    /* Make a proper command from the command string */ 
+    strcpy(buf, command);
+    ptr = buf;
+    for(f = 1; f < 15; f++) {
+       /* Skip white space */
+       while(*ptr == ' ' || *ptr == '\t') ptr++;
+       args[f] = ptr;
+       /* May be trailing space.. */
+       if (*ptr == 0) break;
+       /* Skip this `word' */
+       while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')
+           ptr++;
+       /* If end-of-line, break */
+       if (*ptr == '#' || *ptr == 0) {
+           f++;
+           *ptr = 0;
+           break;
+       }
+       /* End word with \0 and continue */
+       args[f] = NULL;
+    }
+    args[0] = args[1];
+       
+
+    if ((pid = fork()) == 0) {
+       /* Clean up */
+       close(0);
+       close(1);
+       close(2);
+       setsid();
+
+       if ((f = device_open(terminal, O_RDWR|O_NOCTTY)) < 0) {
+           message( log, "open(%s) failed: %s", terminal, strerror(errno));
+           return -1;
+       }
+       dup(f);
+       dup(f);
+       tcsetpgrp(0, getpgrp());
+       set_term();
+
+       if ( get_enter ) {
+           /*
+            * Save memory by not exec-ing anything large (like a shell)
+            * before the user wants it. This is critical if swap is not
+            * enabled and the system has low memory. Generally this will
+            * be run on the second virtual console, and the first will
+            * be allowed to start a shell or whatever an init script 
+            * specifies.
+            */
+           char        c;
+           write(1, press_enter, sizeof(press_enter) - 1);
+           read(0, &c, 1);
        }
+
+       /* Log the process name and args */
+       message(log, "Executing '%s'\n", command);
+
+       /* Now run it.  This should take over the PID, so nothing 
+        * further in init.c should be run by this PID. */
+       execvp(args[1], args + 1);
+
+       /* If shell scripts are not executed, force the issue */
+       if (errno == ENOEXEC) {
+           char buf[256];
+           args[1] = SHELL;
+           args[2] = "-c";
+           strcpy(buf, "exec ");
+           strcat(buf, command);
+           args[3] = buf;
+           args[4] = NULL;
+           execvp(args[1], args + 1);
+       }
+       message(log, "Could not execute '%s'\n", command, strerror(errno));
+       exit(-1);
+    }
+    return pid;
+}
+
+#ifndef DEBUG_INIT
+static void
+shutdown_system(void)
+{
+
+    message(console, "The system is going down NOW !!");
+    sync();
+    /* Allow Ctrl-Alt-Del to reboot system. */
+    reboot(RB_ENABLE_CAD);
+
+    /* Send signals to every process _except_ pid 1 */
+    message(console, "Sending SIGHUP to all processes.\r\n");
+    kill(-1, SIGHUP);
+    sleep(2);
+    sync();
+    message(console, "Sending SIGKILL to all processes.\r\n");
+    kill(-1, SIGKILL);
+    sleep(1);
+    waitfor(run("/bin/swapoff -a", console, 0));
+    waitfor(run("/bin/umount -a -n", console, 0));
+    sync();
+    if (get_kernel_revision() <= 2*65536+2*256+11) {
+       /* Removed  bdflush call, kupdate in kernels >2.2.11 */
+       bdflush(1, 0);
+       sync();
+    }
 }
 
 static void
@@ -251,7 +330,7 @@ halt_signal(int sig)
 {
     shutdown_system();
     message(console, "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
-    reboot( RB_HALT_SYSTEM);
+    reboot( RB_POWER_OFF);
     exit(0);
 }
 
@@ -263,202 +342,136 @@ reboot_signal(int sig)
     reboot( RB_AUTOBOOT);
     exit(0);
 }
+#endif
 
-static void
-configure_terminals( int serial_cons, int single_user_mode )
+int setproctitle(char *fmt, ...)
 {
-       char *tty;
-       struct serial_struct sr;
-       struct vt_stat vt;
-
-
-       switch (serial_cons) {
-       case -1:
-           /* 2.2 kernels:
-           * identify the real console backend and try to make use of it */
-           if (ioctl(0,TIOCGSERIAL,&sr) == 0) {
-               sprintf( console, "/dev/ttyS%d", sr.line );
-               serial_cons = sr.line+1;
-           }
-           else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
-               sprintf( console, "/dev/tty%d", vt.v_active );
-               serial_cons = 0;
-           }
-           else {
-               /* unknown backend: fallback to /dev/console */
-               strcpy( console, "/dev/console" );
-               serial_cons = 0;
-           }
-           break;
-
-       case 1:
-               strcpy( console, "/dev/cua0" );
-               break;
-       case 2:
-               strcpy( console, "/dev/cua1" );
-               break;
-       default:
-               tty = ttyname(0);
-               if (tty) {
-                       strcpy( console, tty );
-                       if (!strncmp( tty, "/dev/cua", 8 ))
-                               serial_cons=1;
-               }
-               else
-                       /* falls back to /dev/tty1 if an error occurs */
-                       strcpy( console, default_console );
-       }
-       if (!first_terminal)
-               first_terminal = console;
-#if defined (__sparc__)
-       if (serial_cons > 0 && !strncmp(term_ptr,"TERM=linux",10))
-           term_ptr = "TERM=vt100";
-#endif
-       if (serial_cons) {
-           /* disable other but the first terminal:
-           * VT is not initialized anymore on 2.2 kernel when booting from
-           * serial console, therefore modprobe is flooding the display with
-           * "can't locate module char-major-4" messages. */
-           log = 0;
-           second_terminal = 0;
-       }
+    va_list ap;
+    int len;
+    char buf[256];
+
+    buf[0] = 0;
+    va_start(ap, fmt);
+    len = vsprintf(buf, fmt, ap);
+    va_end(ap);
+    memset(argv0, 0, maxproclen + 1);
+    strncpy(argv0, buf, maxproclen);
+    return len;
 }
 
 extern int
 init_main(int argc, char * * argv)
 {
-       const char *                rc_arguments[100];
-       const char *                arguments[100];
-       int                         run_rc = TRUE;
-       int                         j;
-       int                         pid1 = 0;
-       int                         pid2 = 0;
-       struct stat                 statbuf;
-       const char *                tty_commands[3] = { "etc/init.d/rcS", "bin/sh"};
-       int                         serial_console = 0;
-       int retval;
-
-       /*
-        * If I am started as /linuxrc instead of /sbin/init, I don't have the
-        * environment that init expects. I can't fix the signal behavior. Try
-        * to divorce from the controlling terminal with setsid(). This won't work
-        * if I am the process group leader.
-        */
-       setsid();
-
+       int run_rc = TRUE;
+       int pid1 = 0;
+       int pid2 = 0;
+       struct stat statbuf;
+       const char* init_commands = SHELL "-c exec " INITSCRIPT;
+       const char* shell_commands = SHELL;
+       const char* tty0_commands = init_commands;
+       const char* tty1_commands = shell_commands;
+       const char* no_memory = 
+           "Sorry, your computer does not have enough memory.\n";
+
+       /* For later use */
+       argv0 = argv[0];
+       maxproclen = strlen(argv[0]);
+       setproctitle("init [boot]");
+
+
+#ifndef DEBUG_INIT
+       /* Set up sig handlers */
        signal(SIGUSR1, halt_signal);
+       signal(SIGSEGV, halt_signal);
+       signal(SIGPWR,  halt_signal);
+       signal(SIGALRM, halt_signal);
+       signal(SIGHUP,  halt_signal);
        signal(SIGUSR2, reboot_signal);
-       signal(SIGINT, reboot_signal);
+       signal(SIGINT,  reboot_signal);
        signal(SIGTERM, reboot_signal);
+#endif
+       /* Figure out where the default console should be */
+       console_init();
 
+       /* Turn off rebooting via CTL-ALT-DEL -- we get a 
+        * SIGINT on CAD so we can shut things down gracefully... */
+#ifndef DEBUG_INIT
        reboot(RB_DISABLE_CAD);
+#endif
 
-       message(log, "%s: started. ", argv[0]);
+       /* Close whatever files are open, and reset the console. */
+       close(0);
+       close(1);
+       close(2);
+       set_term();
+       setsid();
 
-       for ( j = 1; j < argc; j++ ) {
-               if ( strcmp(argv[j], "single") == 0 ) {
-                       run_rc = FALSE;
-                       tty_commands[0] = "bin/sh";
-                       tty_commands[1] = 0;
-               }
-       }
-       for ( j = 0; __environ[j] != 0; j++ ) {
-               if ( strncmp(__environ[j], "tty", 3) == 0
-                && __environ[j][3] >= '1'
-                && __environ[j][3] <= '2'
-                && __environ[j][4] == '=' ) {
-                       const char * s = &__environ[j][5];
+       /* Make sure PATH is set to something sane */
+       if (getenv("PATH") == NULL) 
+           putenv(PATH_DEFAULT);
 
-                       if ( *s == 0 || strcmp(s, "off") == 0 )
-                               s = 0;
+       /* Hello world */
+       message(console, "%s started:  BusyBox v%s (%s) multi-call binary", 
+               argv[0], BB_VER, BB_BT);
+       message(log, "%s started:  BusyBox v%s (%s) multi-call binary", 
+               argv[0], BB_VER, BB_BT);
 
-                       tty_commands[__environ[j][3] - '1'] = s;
-               }
-               /* Should catch the syntax of Sparc kernel console setting.   */
-               /* The kernel does not recognize a serial console when getting*/
-               /* console=/dev/ttySX !! */
-               else if ( strcmp(__environ[j], "console=ttya") == 0 ) {
-                       serial_console=1;
-               }
-               else if ( strcmp(__environ[j], "console=ttyb") == 0 ) {
-                       serial_console=2;
-               }
-               /* standard console settings */
-               else if ( strncmp(__environ[j], "console=", 8) == 0 ) {
-                       first_terminal=&(__environ[j][8]);
-               }
-               else if ( strncmp(__environ[j], "TERM=", 5) == 0) {
-                       term_ptr=__environ[j];
-               }
-       }
 
-       printf("mounting /proc ...\n");
+       /* Mount /proc */
+       message(console, "Mounting /proc: \n");
        if (mount("/proc","/proc","proc",0,0)) {
-         perror("mounting /proc failed\n");
-       }
-       printf("\tdone.\n");
-
-       if (get_kernel_revision() >= 2*65536+1*256+71) {
-           /* if >= 2.1.71 kernel, /dev/console is not a symlink anymore:
-           * use it as primary console */
-           serial_console=-1;
+           message(log, "%s: could not mount /proc!\n", argv[0]);
+           message(console, "failed!\n");
        }
+       message(console, "done.\n");
 
-       /* Make sure /etc/init.d/rc exists */
-       retval= stat(tty_commands[0],&statbuf);
-       if (retval)
-           run_rc = FALSE;
-
-       configure_terminals( serial_console,  run_rc);
 
+       /* Make sure there is enough memory to do something useful*/
        set_free_pages();
-
-       /* not enough memory to do anything useful*/
        if (mem_total() < 2000) { 
+           int retval;
            retval= stat("/etc/fstab",&statbuf);
            if (retval) {
-               printf("You do not have enough RAM, sorry.\n");
+               message(console, "%s", no_memory);
                while (1) { sleep(1);}
            } else { 
              /* Try to turn on swap */
-               static const char * const swapon_args[] = {"/bin/swapon", "-a", 0};
-               waitfor(run("/bin/swapon", swapon_args, console, 0));
+               waitfor(run("/bin/swapon -a", console, 0));
                if (mem_total() < 2000) { 
-                   printf("You do not have enough RAM, sorry.\n");
+                   message(console, "%s", no_memory);
                    while (1) { sleep(1);}
                }
            }
        }
 
-       /*
-        * Don't modify **argv directly, it would show up in the "ps" display.
-        * I don't want "init" to look like "rc".
-        */
-       rc_arguments[0] = tty_commands[0];
-       for ( j = 1; j < argc; j++ ) {
-               rc_arguments[j] = argv[j];
+       /* Check if we are supposed to be in single user mode */
+       if (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || !strcmp(argv[1], "1")) {
+               run_rc = FALSE;
+               tty0_commands = shell_commands;
+               tty1_commands = 0;
+               setproctitle("init [S]");
+       } else { 
+           setproctitle("init [1]");
        }
-       rc_arguments[j] = 0;
 
-       arguments[0] = "-sh";
-       arguments[1] = 0;
-       
-       /* Ok, now launch the rc script /etc/init.d/rcS and prepare to start up
-        * some VTs on tty1 and tty2 if somebody hits enter 
+       /* Make sure an init script exists before trying to run it */
+       if ( run_rc == TRUE && stat( INITSCRIPT, &statbuf)) {
+           tty0_commands = shell_commands;
+           tty1_commands = shell_commands;
+       } 
+
+       /* Ok, now launch the rc script and/or prepare to 
+        * start up some VTs if somebody hits enter... 
         */
        for ( ; ; ) {
                int     wpid;
                int     status;
 
-               if ( pid1 == 0  && tty_commands[0] ) {
-                  if ( run_rc == TRUE ) {
-                       pid1 = run(tty_commands[0], rc_arguments, first_terminal, 0);
-                  } else {
-                       pid2 = run(tty_commands[1], arguments, first_terminal, 1);
-                  }
+               if ( pid1 == 0  && *tty0_commands ) {
+                   pid1 = run(tty0_commands, console, 1);
                }
-               if ( pid2 == 0 && second_terminal && tty_commands[1] ) {
-                       pid2 = run(tty_commands[1], arguments, second_terminal, 1);
+               if ( pid2 == 0 && *tty1_commands ) {
+                   pid2 = run(tty1_commands, second_terminal, 1);
                }
                wpid = wait(&status);
                if ( wpid > 0  && wpid != pid1) {
@@ -467,6 +480,7 @@ init_main(int argc, char * * argv)
                if ( wpid == pid2 ) {
                        pid2 = 0;
                }
+               sleep(1);
        }
 }
 
index c32124d..0676bf7 100644 (file)
 #include <sys/vt.h>            /* for vt_stat */
 #include <sys/ioctl.h>
 
-static const char  init_usage[] = "Used internally by the system.";
-static char        console[16] = "";
-static const char* default_console = "/dev/tty2";
-static char*       first_terminal = NULL;
-static const char* second_terminal = "/dev/tty2";
-static const char* log = "/dev/tty3";
-static char* term_ptr = NULL;
+#define DEBUG_INIT
 
-static void
-message(const char* terminal, const char * pattern, ...)
-{
-       int     fd;
-       FILE *  con = 0;
-       va_list arguments;
-
-       /*
-        * Open the console device each time a message is printed. If the user
-        * has switched consoles, the open will get the new console. If we kept
-        * the console open, we'd always print to the same one.
-        */
-       if ( !terminal
-        ||  ((fd = open(terminal, O_WRONLY|O_NOCTTY)) < 0)
-        ||  ((con = fdopen(fd, "w")) == NULL) )
-               return;
+#define CONSOLE         "/dev/console"          /* Logical system console */
+#define VT_PRIMARY      "/dev/tty0"             /* Virtual console master */
+#define VT_SECONDARY    "/dev/tty1"             /* Virtual console master */
+#define VT_LOG          "/dev/tty2"             /* Virtual console master */
+#define SHELL           "/bin/sh"               /* Default shell */
+#define INITSCRIPT      "/etc/init.d/rcS"       /* Initscript. */
+#define PATH_DEFAULT    "PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin"
 
-       va_start(arguments, pattern);
-       vfprintf(con, pattern, arguments);
-       va_end(arguments);
-       fclose(con);
+static int maxproclen=0;
+static char* argv0;
+
+static char* console = CONSOLE;
+static char* second_terminal = "/dev/tty2";
+static char* log = "/dev/tty3";
+
+
+
+/* try to open up the specified device */
+int device_open(char* device, int mode)
+{
+    int m, f, fd = -1;
+    
+    mode = m | O_NONBLOCK;
+    
+    /* Retry up to 5 times */
+    for(f = 0; f < 5; f++)
+       if ((fd = open(device, m)) >= 0) break;
+    if (fd < 0) return fd;
+    /* Set original flags. */
+    if (m != mode)
+       fcntl(fd, F_SETFL, mode);
+    return fd;
 }
 
-static int
-waitfor(int pid)
+/* print a message to the specified device */
+void message(char* device, char *fmt, ...)
 {
-       int     status;
-       int     wpid;
-       
-       message(log, "Waiting for process %d.\n", pid);
-       while ( (wpid = wait(&status)) != pid ) {
-               if ( wpid > 0 ) {
-                       message(
-                        log
-                       ,"pid %d exited, status=%x.\n"
-                       ,wpid
-                       ,status);
-               }
-       }
-       return wpid;
+    int fd;
+    va_list arguments;
+    if ((fd = device_open(device, O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
+       va_start(arguments, fmt);
+       vdprintf(fd, fmt, arguments);
+       va_end(arguments);
+    }
+    close( fd);
 }
 
-static int
-run(const char* program, const char* const* arguments, 
-       const char* terminal, int get_enter)
+/* Set terminal settings to reasonable defaults */
+void set_term()
 {
-       static const char       control_characters[] = {
-               '\003',
-               '\034',
-               '\177',
-               '\025',
-               '\004',
-               '\0',
-               '\1',
-               '\0',
-               '\021',
-               '\023',
-               '\032',
-               '\0',
-               '\022',
-               '\017',
-               '\027',
-               '\026',
-               '\0'
-       };
-
-       static char * environment[] = {
-               "HOME=/",
-               "PATH=/bin:/sbin:/usr/bin:/usr/sbin",
-               "SHELL=/bin/sh",
-               0,
-               "USER=root",
-               0
-       };
-
-       static const char       press_enter[] =
- "\nPlease press Enter to activate this console. ";
-
-       int     pid;
-
-       environment[3]=term_ptr;
-
-       pid = fork();
-       if ( pid == 0 ) {
-               struct termios  t;
-               const char * const * arg;
-
-               close(0);
-               close(1);
-               close(2);
-               setsid();
-
-               open(terminal, O_RDWR);
-               dup(0);
-               dup(0);
-               tcsetpgrp(0, getpgrp());
-
-               tcgetattr(0, &t);
-               memcpy(t.c_cc, control_characters, sizeof(control_characters));
-               t.c_line = 0;
-               t.c_iflag = ICRNL|IXON|IXOFF;
-               t.c_oflag = OPOST|ONLCR;
-               t.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
-               tcsetattr(0, TCSANOW, &t);
-
-               if ( get_enter ) {
-                       /*
-                        * Save memory by not exec-ing anything large (like a shell)
-                        * before the user wants it. This is critical if swap is not
-                        * enabled and the system has low memory. Generally this will
-                        * be run on the second virtual console, and the first will
-                        * be allowed to start a shell or whatever an init script 
-                        * specifies.
-                        */
-                       char    c;
-                       write(1, press_enter, sizeof(press_enter) - 1);
-                       read(0, &c, 1);
-               }
-               
-               message(log, "Executing ");
-               arg = arguments;
-               while ( *arg != 0 )
-                       message(log, "%s ", *arg++);
-               message(log, "\n");
-
-               execve(program, (char * *)arguments, (char * *)environment);
-               message(log, "%s: could not execute: %s.\r\n", program, strerror(errno));
-               exit(-1);
-       }
-       return pid;
+    int fd;
+    struct termios tty;
+
+    if ((fd = device_open(console, O_RDWR|O_NOCTTY)) < 0) {
+       message(log, "can't open %s", console);
+       return;
+    }
+    ioctl(fd, TCGETS, &tty);
+    tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+    tty.c_cflag |= HUPCL|CLOCAL;
+
+    tty.c_cc[VINTR]  = 3;
+    tty.c_cc[VQUIT]  = 28;
+    tty.c_cc[VERASE] = 127;
+    tty.c_cc[VKILL]  = 24;
+    tty.c_cc[VEOF]   = 4;
+    tty.c_cc[VTIME]  = 0;
+    tty.c_cc[VMIN]   = 1;
+    tty.c_cc[VSTART] = 17;
+    tty.c_cc[VSTOP]  = 19;
+    tty.c_cc[VSUSP]  = 26;
+
+    /* Set pre and post processing */
+    tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+    tty.c_oflag = OPOST|ONLCR;
+    tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+    /* Now set the terminal line. */
+    ioctl(fd, TCSETS, &tty);
+    close( fd);
 }
 
 static int
@@ -217,33 +161,168 @@ set_free_pages()
     fclose(f);
 }
 
+
 static void
-shutdown_system(void)
+console_init()
 {
-       static const char * const umount_args[] = {"/bin/umount", "-a", "-n", 0};
-       static const char * const swapoff_args[] = {"/bin/swapoff", "-a", 0};
+    int fd;
+    int tried_devcons = 0;
+    int tried_vtmaster = 0;
+    char *s;
+
+    if ((s = getenv("CONSOLE")) != NULL)
+       console = s;
+    else {
+       console = CONSOLE;
+       tried_devcons++;
+    }
+    while ((fd = open(console, O_RDONLY|O_NONBLOCK)) < 0) {
+       if (!tried_devcons) {
+           tried_devcons++;
+           console = CONSOLE;
+           continue;
+       }
+       if (!tried_vtmaster) {
+           tried_vtmaster++;
+           console = VT_PRIMARY;
+           continue;
+       }
+       break;
+    }
+    if (fd < 0)
+       console = "/dev/null";
+    else
+       close(fd);
+}
 
-       message(console, "The system is going down NOW !!");
-       sync();
-       /* Allow Ctrl-Alt-Del to reboot system. */
-       reboot(RB_ENABLE_CAD);
+static int
+waitfor(int pid)
+{
+    int status, wpid;
 
-       /* Send signals to every process _except_ pid 1 */
-       message(console, "Sending SIGHUP to all processes.\r\n");
-       kill(-1, SIGHUP);
-       sleep(2);
-       sync();
-       message(console, "Sending SIGKILL to all processes.\r\n");
-       kill(-1, SIGKILL);
-       sleep(1);
-       waitfor(run("/bin/swapoff", swapoff_args, console, 0));
-       waitfor(run("/bin/umount", umount_args, console, 0));
-       sync();
-       if (get_kernel_revision() <= 2*65536+2*256+11) {
-           /* Removed  bdflush call, kupdate in kernels >2.2.11 */
-           bdflush(1, 0);
-           sync();
+    message(log, "Waiting for process %d.\n", pid);
+    while ( (wpid = wait(&status)) != pid ) {
+       if ( wpid > 0 )
+           message(log,"pid %d exited, status=%x.\n", wpid, status);
+    }
+    return wpid;
+}
+
+static int
+run(const char* command, char* terminal, int get_enter)
+{
+    int        f, pid;
+    char *args[16];
+    char buf[256];
+    char* ptr;
+    static const char press_enter[] = 
+       "\nPlease press Enter to activate this console. ";
+
+       
+    /* Make a proper command from the command string */ 
+    strcpy(buf, command);
+    ptr = buf;
+    for(f = 1; f < 15; f++) {
+       /* Skip white space */
+       while(*ptr == ' ' || *ptr == '\t') ptr++;
+       args[f] = ptr;
+       /* May be trailing space.. */
+       if (*ptr == 0) break;
+       /* Skip this `word' */
+       while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')
+           ptr++;
+       /* If end-of-line, break */
+       if (*ptr == '#' || *ptr == 0) {
+           f++;
+           *ptr = 0;
+           break;
+       }
+       /* End word with \0 and continue */
+       args[f] = NULL;
+    }
+    args[0] = args[1];
+       
+
+    if ((pid = fork()) == 0) {
+       /* Clean up */
+       close(0);
+       close(1);
+       close(2);
+       setsid();
+
+       if ((f = device_open(terminal, O_RDWR|O_NOCTTY)) < 0) {
+           message( log, "open(%s) failed: %s", terminal, strerror(errno));
+           return -1;
+       }
+       dup(f);
+       dup(f);
+       tcsetpgrp(0, getpgrp());
+       set_term();
+
+       if ( get_enter ) {
+           /*
+            * Save memory by not exec-ing anything large (like a shell)
+            * before the user wants it. This is critical if swap is not
+            * enabled and the system has low memory. Generally this will
+            * be run on the second virtual console, and the first will
+            * be allowed to start a shell or whatever an init script 
+            * specifies.
+            */
+           char        c;
+           write(1, press_enter, sizeof(press_enter) - 1);
+           read(0, &c, 1);
        }
+
+       /* Log the process name and args */
+       message(log, "Executing '%s'\n", command);
+
+       /* Now run it.  This should take over the PID, so nothing 
+        * further in init.c should be run by this PID. */
+       execvp(args[1], args + 1);
+
+       /* If shell scripts are not executed, force the issue */
+       if (errno == ENOEXEC) {
+           char buf[256];
+           args[1] = SHELL;
+           args[2] = "-c";
+           strcpy(buf, "exec ");
+           strcat(buf, command);
+           args[3] = buf;
+           args[4] = NULL;
+           execvp(args[1], args + 1);
+       }
+       message(log, "Could not execute '%s'\n", command, strerror(errno));
+       exit(-1);
+    }
+    return pid;
+}
+
+#ifndef DEBUG_INIT
+static void
+shutdown_system(void)
+{
+
+    message(console, "The system is going down NOW !!");
+    sync();
+    /* Allow Ctrl-Alt-Del to reboot system. */
+    reboot(RB_ENABLE_CAD);
+
+    /* Send signals to every process _except_ pid 1 */
+    message(console, "Sending SIGHUP to all processes.\r\n");
+    kill(-1, SIGHUP);
+    sleep(2);
+    sync();
+    message(console, "Sending SIGKILL to all processes.\r\n");
+    kill(-1, SIGKILL);
+    sleep(1);
+    waitfor(run("/bin/swapoff -a", console, 0));
+    waitfor(run("/bin/umount -a -n", console, 0));
+    sync();
+    if (get_kernel_revision() <= 2*65536+2*256+11) {
+       /* Removed  bdflush call, kupdate in kernels >2.2.11 */
+       bdflush(1, 0);
+       sync();
+    }
 }
 
 static void
@@ -251,7 +330,7 @@ halt_signal(int sig)
 {
     shutdown_system();
     message(console, "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
-    reboot( RB_HALT_SYSTEM);
+    reboot( RB_POWER_OFF);
     exit(0);
 }
 
@@ -263,202 +342,136 @@ reboot_signal(int sig)
     reboot( RB_AUTOBOOT);
     exit(0);
 }
+#endif
 
-static void
-configure_terminals( int serial_cons, int single_user_mode )
+int setproctitle(char *fmt, ...)
 {
-       char *tty;
-       struct serial_struct sr;
-       struct vt_stat vt;
-
-
-       switch (serial_cons) {
-       case -1:
-           /* 2.2 kernels:
-           * identify the real console backend and try to make use of it */
-           if (ioctl(0,TIOCGSERIAL,&sr) == 0) {
-               sprintf( console, "/dev/ttyS%d", sr.line );
-               serial_cons = sr.line+1;
-           }
-           else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
-               sprintf( console, "/dev/tty%d", vt.v_active );
-               serial_cons = 0;
-           }
-           else {
-               /* unknown backend: fallback to /dev/console */
-               strcpy( console, "/dev/console" );
-               serial_cons = 0;
-           }
-           break;
-
-       case 1:
-               strcpy( console, "/dev/cua0" );
-               break;
-       case 2:
-               strcpy( console, "/dev/cua1" );
-               break;
-       default:
-               tty = ttyname(0);
-               if (tty) {
-                       strcpy( console, tty );
-                       if (!strncmp( tty, "/dev/cua", 8 ))
-                               serial_cons=1;
-               }
-               else
-                       /* falls back to /dev/tty1 if an error occurs */
-                       strcpy( console, default_console );
-       }
-       if (!first_terminal)
-               first_terminal = console;
-#if defined (__sparc__)
-       if (serial_cons > 0 && !strncmp(term_ptr,"TERM=linux",10))
-           term_ptr = "TERM=vt100";
-#endif
-       if (serial_cons) {
-           /* disable other but the first terminal:
-           * VT is not initialized anymore on 2.2 kernel when booting from
-           * serial console, therefore modprobe is flooding the display with
-           * "can't locate module char-major-4" messages. */
-           log = 0;
-           second_terminal = 0;
-       }
+    va_list ap;
+    int len;
+    char buf[256];
+
+    buf[0] = 0;
+    va_start(ap, fmt);
+    len = vsprintf(buf, fmt, ap);
+    va_end(ap);
+    memset(argv0, 0, maxproclen + 1);
+    strncpy(argv0, buf, maxproclen);
+    return len;
 }
 
 extern int
 init_main(int argc, char * * argv)
 {
-       const char *                rc_arguments[100];
-       const char *                arguments[100];
-       int                         run_rc = TRUE;
-       int                         j;
-       int                         pid1 = 0;
-       int                         pid2 = 0;
-       struct stat                 statbuf;
-       const char *                tty_commands[3] = { "etc/init.d/rcS", "bin/sh"};
-       int                         serial_console = 0;
-       int retval;
-
-       /*
-        * If I am started as /linuxrc instead of /sbin/init, I don't have the
-        * environment that init expects. I can't fix the signal behavior. Try
-        * to divorce from the controlling terminal with setsid(). This won't work
-        * if I am the process group leader.
-        */
-       setsid();
-
+       int run_rc = TRUE;
+       int pid1 = 0;
+       int pid2 = 0;
+       struct stat statbuf;
+       const char* init_commands = SHELL "-c exec " INITSCRIPT;
+       const char* shell_commands = SHELL;
+       const char* tty0_commands = init_commands;
+       const char* tty1_commands = shell_commands;
+       const char* no_memory = 
+           "Sorry, your computer does not have enough memory.\n";
+
+       /* For later use */
+       argv0 = argv[0];
+       maxproclen = strlen(argv[0]);
+       setproctitle("init [boot]");
+
+
+#ifndef DEBUG_INIT
+       /* Set up sig handlers */
        signal(SIGUSR1, halt_signal);
+       signal(SIGSEGV, halt_signal);
+       signal(SIGPWR,  halt_signal);
+       signal(SIGALRM, halt_signal);
+       signal(SIGHUP,  halt_signal);
        signal(SIGUSR2, reboot_signal);
-       signal(SIGINT, reboot_signal);
+       signal(SIGINT,  reboot_signal);
        signal(SIGTERM, reboot_signal);
+#endif
+       /* Figure out where the default console should be */
+       console_init();
 
+       /* Turn off rebooting via CTL-ALT-DEL -- we get a 
+        * SIGINT on CAD so we can shut things down gracefully... */
+#ifndef DEBUG_INIT
        reboot(RB_DISABLE_CAD);
+#endif
 
-       message(log, "%s: started. ", argv[0]);
+       /* Close whatever files are open, and reset the console. */
+       close(0);
+       close(1);
+       close(2);
+       set_term();
+       setsid();
 
-       for ( j = 1; j < argc; j++ ) {
-               if ( strcmp(argv[j], "single") == 0 ) {
-                       run_rc = FALSE;
-                       tty_commands[0] = "bin/sh";
-                       tty_commands[1] = 0;
-               }
-       }
-       for ( j = 0; __environ[j] != 0; j++ ) {
-               if ( strncmp(__environ[j], "tty", 3) == 0
-                && __environ[j][3] >= '1'
-                && __environ[j][3] <= '2'
-                && __environ[j][4] == '=' ) {
-                       const char * s = &__environ[j][5];
+       /* Make sure PATH is set to something sane */
+       if (getenv("PATH") == NULL) 
+           putenv(PATH_DEFAULT);
 
-                       if ( *s == 0 || strcmp(s, "off") == 0 )
-                               s = 0;
+       /* Hello world */
+       message(console, "%s started:  BusyBox v%s (%s) multi-call binary", 
+               argv[0], BB_VER, BB_BT);
+       message(log, "%s started:  BusyBox v%s (%s) multi-call binary", 
+               argv[0], BB_VER, BB_BT);
 
-                       tty_commands[__environ[j][3] - '1'] = s;
-               }
-               /* Should catch the syntax of Sparc kernel console setting.   */
-               /* The kernel does not recognize a serial console when getting*/
-               /* console=/dev/ttySX !! */
-               else if ( strcmp(__environ[j], "console=ttya") == 0 ) {
-                       serial_console=1;
-               }
-               else if ( strcmp(__environ[j], "console=ttyb") == 0 ) {
-                       serial_console=2;
-               }
-               /* standard console settings */
-               else if ( strncmp(__environ[j], "console=", 8) == 0 ) {
-                       first_terminal=&(__environ[j][8]);
-               }
-               else if ( strncmp(__environ[j], "TERM=", 5) == 0) {
-                       term_ptr=__environ[j];
-               }
-       }
 
-       printf("mounting /proc ...\n");
+       /* Mount /proc */
+       message(console, "Mounting /proc: \n");
        if (mount("/proc","/proc","proc",0,0)) {
-         perror("mounting /proc failed\n");
-       }
-       printf("\tdone.\n");
-
-       if (get_kernel_revision() >= 2*65536+1*256+71) {
-           /* if >= 2.1.71 kernel, /dev/console is not a symlink anymore:
-           * use it as primary console */
-           serial_console=-1;
+           message(log, "%s: could not mount /proc!\n", argv[0]);
+           message(console, "failed!\n");
        }
+       message(console, "done.\n");
 
-       /* Make sure /etc/init.d/rc exists */
-       retval= stat(tty_commands[0],&statbuf);
-       if (retval)
-           run_rc = FALSE;
-
-       configure_terminals( serial_console,  run_rc);
 
+       /* Make sure there is enough memory to do something useful*/
        set_free_pages();
-
-       /* not enough memory to do anything useful*/
        if (mem_total() < 2000) { 
+           int retval;
            retval= stat("/etc/fstab",&statbuf);
            if (retval) {
-               printf("You do not have enough RAM, sorry.\n");
+               message(console, "%s", no_memory);
                while (1) { sleep(1);}
            } else { 
              /* Try to turn on swap */
-               static const char * const swapon_args[] = {"/bin/swapon", "-a", 0};
-               waitfor(run("/bin/swapon", swapon_args, console, 0));
+               waitfor(run("/bin/swapon -a", console, 0));
                if (mem_total() < 2000) { 
-                   printf("You do not have enough RAM, sorry.\n");
+                   message(console, "%s", no_memory);
                    while (1) { sleep(1);}
                }
            }
        }
 
-       /*
-        * Don't modify **argv directly, it would show up in the "ps" display.
-        * I don't want "init" to look like "rc".
-        */
-       rc_arguments[0] = tty_commands[0];
-       for ( j = 1; j < argc; j++ ) {
-               rc_arguments[j] = argv[j];
+       /* Check if we are supposed to be in single user mode */
+       if (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || !strcmp(argv[1], "1")) {
+               run_rc = FALSE;
+               tty0_commands = shell_commands;
+               tty1_commands = 0;
+               setproctitle("init [S]");
+       } else { 
+           setproctitle("init [1]");
        }
-       rc_arguments[j] = 0;
 
-       arguments[0] = "-sh";
-       arguments[1] = 0;
-       
-       /* Ok, now launch the rc script /etc/init.d/rcS and prepare to start up
-        * some VTs on tty1 and tty2 if somebody hits enter 
+       /* Make sure an init script exists before trying to run it */
+       if ( run_rc == TRUE && stat( INITSCRIPT, &statbuf)) {
+           tty0_commands = shell_commands;
+           tty1_commands = shell_commands;
+       } 
+
+       /* Ok, now launch the rc script and/or prepare to 
+        * start up some VTs if somebody hits enter... 
         */
        for ( ; ; ) {
                int     wpid;
                int     status;
 
-               if ( pid1 == 0  && tty_commands[0] ) {
-                  if ( run_rc == TRUE ) {
-                       pid1 = run(tty_commands[0], rc_arguments, first_terminal, 0);
-                  } else {
-                       pid2 = run(tty_commands[1], arguments, first_terminal, 1);
-                  }
+               if ( pid1 == 0  && *tty0_commands ) {
+                   pid1 = run(tty0_commands, console, 1);
                }
-               if ( pid2 == 0 && second_terminal && tty_commands[1] ) {
-                       pid2 = run(tty_commands[1], arguments, second_terminal, 1);
+               if ( pid2 == 0 && *tty1_commands ) {
+                   pid2 = run(tty1_commands, second_terminal, 1);
                }
                wpid = wait(&status);
                if ( wpid > 0  && wpid != pid1) {
@@ -467,6 +480,7 @@ init_main(int argc, char * * argv)
                if ( wpid == pid2 ) {
                        pid2 = 0;
                }
+               sleep(1);
        }
 }
 
index 0caaf5c..35f990a 100644 (file)
@@ -82,6 +82,8 @@ extern int loadfont_main(int argc, char** argv);
 extern int loadkmap_main(int argc, char** argv);
 extern int losetup_main(int argc, char** argv);
 extern int ls_main(int argc, char** argv);
+extern int chvt_main(int argc, char** argv);
+extern int deallocvt_main(int argc, char** argv);
 extern int makedevs_main(int argc, char** argv);
 extern int math_main(int argc, char** argv);
 extern int mkdir_main(int argc, char** argv);
@@ -110,6 +112,7 @@ extern int true_main(int argc, char** argv);
 extern int tryopen_main(int argc, char** argv);
 extern int umount_main(int argc, char** argv);
 extern int update_main(int argc, char** argv);
+extern int uname_main(int argc, char** argv);
 extern int zcat_main(int argc, char** argv);
 extern int gzip_main(int argc, char** argv);
 
@@ -141,7 +144,7 @@ extern gid_t my_getgrnam(char *name);
 extern void my_getpwuid(char* name, uid_t uid);
 extern void my_getgrgid(char* group, gid_t gid);
 extern int get_kernel_revision();
-
+extern int get_console_fd(char* tty_name);
 
 
 #if defined (BB_FSCK_MINIX) || defined (BB_MKFS_MINIX)
index 124efda..6491d83 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -720,5 +720,97 @@ extern int find_match(char *haystack, char *needle, int ignoreCase)
 }
 #endif
 
+
+
+#if (defined BB_CHVT) || (defined BB_DEALLOCVT)
+
+
+#include <linux/kd.h>
+#include <sys/ioctl.h>
+
+int is_a_console(int fd) 
+{
+  char arg;
+  
+  arg = 0;
+  return (ioctl(fd, KDGKBTYPE, &arg) == 0
+         && ((arg == KB_101) || (arg == KB_84)));
+}
+
+static int open_a_console(char *fnam) 
+{
+  int fd;
+  
+  /* try read-only */
+  fd = open(fnam, O_RDWR);
+  
+  /* if failed, try read-only */
+  if (fd < 0 && errno == EACCES)
+      fd = open(fnam, O_RDONLY);
+  
+  /* if failed, try write-only */
+  if (fd < 0 && errno == EACCES)
+      fd = open(fnam, O_WRONLY);
+  
+  /* if failed, fail */
+  if (fd < 0)
+      return -1;
+  
+  /* if not a console, fail */
+  if (! is_a_console(fd))
+    {
+      close(fd);
+      return -1;
+    }
+  
+  /* success */
+  return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ *
+ * if tty_name is non-NULL, try this one instead.
+ */
+
+int get_console_fd(char* tty_name) 
+{
+  int fd;
+
+  if (tty_name)
+    {
+      if (-1 == (fd = open_a_console(tty_name)))
+       return -1;
+      else
+       return fd;
+    }
+  
+  fd = open_a_console("/dev/tty");
+  if (fd >= 0)
+    return fd;
+  
+  fd = open_a_console("/dev/tty0");
+  if (fd >= 0)
+    return fd;
+  
+  fd = open_a_console("/dev/console");
+  if (fd >= 0)
+    return fd;
+  
+  for (fd = 0; fd < 3; fd++)
+    if (is_a_console(fd))
+      return fd;
+  
+  fprintf(stderr,
+         "Couldnt get a file descriptor referring to the console\n");
+  return -1;           /* total failure */
+}
+
+
+#endif
+
+
 /* END CODE */