[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: init/umount problem persists



Hi.

I checked the system.c in glibc-2.1.2, and tried the following patch.
But this does not work. This problem does not seem avoidable by
signal blocking only.


--- init.c.0	Tue Feb  8 00:48:53 2000
+++ init.c	Tue Feb  8 01:31:43 2000
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
@@ -436,6 +437,105 @@
     return wpid;
 }
 
+/* used in shutdown_system() to execute swapoff and umount */
+/* lines are adopted from glibc-2.1.2 system.c */
+static int runsingle(char* command)
+{
+    int i, status, save;
+    pid_t pid;
+    char* tmpCmd;
+    char* cmd[255];
+    char* environment[] = {
+	"HOME=/",
+	"PATH=/usr/bin:/bin:/usr/sbin:/sbin",
+	"SHELL=/bin/sh",
+	termType,
+	"USER=root",
+	0
+    };
+
+/*  ---  require to block SIGCHLD  --- */
+    struct sigaction sa, intr, quit;
+    sigset_t block, omask;
+
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = 0;
+    sigemptyset (&sa.sa_mask);
+
+    if (sigaction (SIGINT, &sa, &intr) < 0)
+      return -1;
+    if (sigaction (SIGQUIT, &sa, &quit) < 0) {
+      save = errno;
+      (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+      errno = save;
+      return -1;
+    }
+
+    sigemptyset (&block);
+    sigaddset (&block, SIGCHLD);
+    save = errno;
+    if (sigprocmask (SIG_BLOCK, &block, &omask) < 0) {
+      if (errno == ENOSYS)
+        errno = save;
+      else {
+        save = errno;
+        (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+        (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+        errno = save;
+        return -1;
+      }
+    }
+
+#define UNBLOCK sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)
+
+    pid = vfork ();
+    if (pid == (pid_t) 0) {
+	/* Child side.  */
+
+	/* Restore the signals.  */
+	(void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+	(void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+	(void) UNBLOCK;
+
+	/* Convert command (char*) into cmd (char**, one word per string) */
+	for (tmpCmd=command, i=0; (tmpCmd=strsep(&command, " \t")) != NULL;) {
+	    if (*tmpCmd != '\0') {
+		cmd[i] = tmpCmd;
+		message(LOG, "%s ", tmpCmd);
+		tmpCmd++;
+		i++;
+	    }
+	}
+	cmd[i] = NULL;
+	message(LOG, "'\r\n");
+
+	/* Now run it.  The new program will take over this PID, 
+	 * so nothing further in init.c should be run. */
+	(void) execve(cmd[0], cmd, environment);
+	exit (127);
+    } else if (pid < (pid_t) 0) {
+    /* The fork failed.  */
+	status = -1;
+    } else {
+    /* Parent side.  */
+	if (waitpid (pid, &status, 0) != pid)
+	status = -1;
+    }
+
+    save = errno;
+    if ((sigaction (SIGINT, &intr, (struct sigaction *) NULL) |
+	 sigaction (SIGQUIT, &quit, (struct sigaction *) NULL) |
+	 UNBLOCK) != 0) {
+		if (errno == ENOSYS)
+        		errno = save;
+		else
+		        return -1;
+    }
+
+    return status;
+}
+
+
 /* Make sure there is enough memory to do something useful. *
  * Calls swapon if needed so be sure /proc is mounted. */
 static void check_memory()
@@ -481,9 +581,11 @@
     sleep(5);
 
     message(CONSOLE, "Disabling swap.\r\n");
-	waitfor( "swapoff -a", console, FALSE);
+/*	waitfor( "swapoff -a", console, FALSE); */
+	runsingle( "/sbin/swapoff -a" );
     message(CONSOLE, "Unmounting filesystems.\r\n");
-	waitfor("umount -a -r", console, FALSE);
+/*	waitfor("umount -a -r", console, FALSE); */
+	runsingle("/bin/umount -a -r" );
     sync();
     if (kernelVersion > 0 && kernelVersion <= 2 * 65536 + 2 * 256 + 11) {
 	/* bdflush, kupdate not needed for kernels >2.2.11 */



On the other hand, I have found several other points in init.c for busybox,
by reading the init.c in sysvinit.

init.c in sysvinit has the following code:

    847   } else if (any(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
    848   /* See if we need to fire off a shell for this command */
    849         /* Give command line to shell */
    850         args[1] = SHELL;
    851         args[2] = "-c";
    852         strcpy(buf, "exec ");
    853         strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
    854         args[3] = buf;
    855         args[4] = NULL;

This is used when the command (proc) line includes the characters
such like "<" or ">", then /sbin/init takes them as the command line
to shell.

BTW, in our boot-floppies, there are "scripts/rootdisk/prototype/etc/inittab",
and in that file, the following lines are written.

     17 # rc script, output to tty3; also creates this file for syslog
     18 null::sysinit:/etc/init.d/rcS >> /var/log/messages 2>&1

But init.c in busybox does not seem to have the code such like the code
in sysvinit, shown above. busybox's init takes the part from the last
 ":" to the end of the line, and feed them to run() in init.c

    331 static pid_t run(char* command,
    332         char *terminal, int get_enter)

and run() splits the strings into the array of strings, then feed them
into execve().

    396         /* Convert command (char*) into cmd (char**, one word per string) */
    397         for (tmpCmd=command, i=0; (tmpCmd=strsep(&command, " \t")) != NULL;) {
    398             if (*tmpCmd != '\0') {
    399                 cmd[i] = tmpCmd;
    400                 message(LOG, "%s ", tmpCmd);
    401                 tmpCmd++;
    402                 i++;
    403             }
    404         }
    405         cmd[i] = NULL;
    406         message(LOG, "'\r\n");
    407
    408         /* Now run it.  The new program will take over this PID,
    409          * so nothing further in init.c should be run. */
    410         execve(cmd[0], cmd, environment);

Now, we feed the command "/etc/init.d/rcS >> /var/log/messages 2>&1"
(written in prototype/etc/inittab) here for execve() as the four strings;
 "/etc/init.d/rcS", ">>", "/var/log/messages", "2>&1"

execve() gets the filename "/etc/init.d/rcS" (prototype/etc/init.d/rcS),
and feed it to /bin/sh because this file has the head line:

      1 #!/bin/sh

The result: "/etc/init.d/rcS" is executed as "/bin/sh /etc/init.d/rcS"
and the rest three arguments are given to "/etc/init.d/rcS" as the argument.
(you chan check this by writing "echo $0 $1 $2 $3" in that file.)

This shows that /var/log/messages can not be created by just writing
 ">> /var/log/messages 2>&1" in /etc/inittab, unless the code is written
also in /etc/init.d/rcS to use these given arguments.

Anyway, this ">> /var/log/messages 2>&1" is no use, even if the busybox's
init has the ability to feed  "/bin/sh", "-c", "exec [given command line]"
to execve(), because the time when init execute this command, the root
filesystem is mounted as readonly. The executed command, "/etc/init.d/rcS"
has the command to remount it as writable.

     12 # mount root writable
     13 mount /dev/root / -o remount,rw
     14 /sbin/update

So at this timing, "/var/log/messages" can not be created.

I think we should remove this confusing part and the comment.

I have another idea for init in busybox.

How about to add the new actiontype "last", to be executed at
the final moment of the system shutdown.

Here is the diff (caution ! I have not test this) :

--- init.c.orig	Tue Feb  8 18:57:38 2000
+++ init.c	Tue Feb  8 19:11:46 2000
@@ -78,7 +78,8 @@
     RESPAWN,
     ASKFIRST,
     WAIT,
-    ONCE
+    ONCE,
+    LAST
 } initActionEnum;
 
 /* And now a list of the actions we support in the version of init */
@@ -93,6 +94,7 @@
     {"askfirst",    ASKFIRST},
     {"wait",        WAIT},
     {"once",        ONCE},
+    {"last",        LAST},
     {0}
 };
 
@@ -106,6 +108,7 @@
     initActionEnum action;
 };
 initAction* initActionList = NULL;
+initAction* lastActionList = NULL;
 
 
 static char *secondConsole = VT_SECONDARY;
@@ -480,6 +483,11 @@
     kill(-1, SIGKILL);
     sleep(5);
 
+    /* run anything to be run at final stage */
+    for( a=lastActionList ; a; a=a->nextPtr) {
+	run(a->process, a->console, FALSE);
+    }
+
     message(CONSOLE, "Disabling swap.\r\n");
 	waitfor( "swapoff -a", console, FALSE);
     message(CONSOLE, "Unmounting filesystems.\r\n");
@@ -625,14 +633,21 @@
 	message(LOG|CONSOLE,"Memory allocation failure\n");
 	while (1) sleep(1);
     }
-    newAction->nextPtr = initActionList;
-    initActionList = newAction;
-    strncpy( newAction->process, process, 255);
+
+    strncpy(newAction->process, process, 255);
     newAction->action = action;
     strncpy(newAction->console, cons, 255);
     newAction->pid = 0;
-//    message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
+
+    if (action != LAST) {
+        newAction->nextPtr = initActionList;
+        initActionList = newAction;
+//      message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
 //	    newAction->process, newAction->action, newAction->console);
+    } else {
+        newAction->nextPtr = lastActionList;
+        lastActionList = newAction;
+    }
 }
 
 void delete_initAction (initAction *action)



Using this, we wil have more flexibility to manage the system.

Regards.

-- 
  Taketoshi Sano: <sano@debian.org>,<sano@debian.or.jp>,<kgh12351@nifty.ne.jp>


Reply to: