Add the comment from Andrea Arcangeli about the correct
authorDr. Werner Fink <werner@suse.de>
Tue, 24 Nov 2009 10:03:19 +0000 (10:03 +0000)
committerDr. Werner Fink <werner@suse.de>
Tue, 24 Nov 2009 10:03:19 +0000 (10:03 +0000)
place of setting the default childhandler within spawn().
Make sure that newline is printed out for last(1) even
if an utmp record entry is truncated.
Check if utmp not only exists but is writable and delay
writing out of the utmp runlevel record if utmp is not writable.
Be able to find libcrypt also on 64 bit based architectures.

git-svn-id: svn://svn.sv.gnu.org/sysvinit/sysvinit/trunk@27 456724a4-4300-0410-8514-c89748c515a2

src/Makefile
src/init.c
src/init.h
src/last.c
src/utmp.c

index d56360e498e2329a7433e9e108410a4e64be7d2b..6e0e962fe919c3dea3c3e797fa7d1b7313d3d4c6 100644 (file)
@@ -64,7 +64,7 @@ endif
 
 
 # Additional libs for GNU libc.
-ifneq ($(wildcard /usr/lib/libcrypt.a),)
+ifneq ($(wildcard /usr/lib*/libcrypt.a),)
 LCRYPT         = -lcrypt
 endif
 
index 5fe053083b4a6184c21f888fe49612a8385c593f..5f7a2b6389256dbf020c6418202a0750f681e100 100644 (file)
@@ -121,6 +121,8 @@ sig_atomic_t got_signals;   /* Set if we received a signal. */
 int emerg_shell = 0;           /* Start emergency shell? */
 int wrote_wtmp_reboot = 1;     /* Set when we wrote the reboot record */
 int wrote_utmp_reboot = 1;     /* Set when we wrote the reboot record */
+int wrote_wtmp_rlevel = 1;     /* Set when we wrote the runlevel record */
+int wrote_utmp_rlevel = 1;     /* Set when we wrote the runlevel record */
 int sltime = 5;                        /* Sleep time between TERM and KILL */
 char *argv0;                   /* First arguments; show up in ps listing */
 int maxproclen;                        /* Maximal length of argv[0] with \0 */
@@ -189,6 +191,8 @@ struct {
   { "-WU",        D_WROTE_UTMP_REBOOT},
   { "-ST",        D_SLTIME     },
   { "-DB",        D_DIDBOOT    },
+  { "-LW",        D_WROTE_WTMP_RLEVEL},
+  { "-LU",        D_WROTE_UTMP_RLEVEL},
   { "",                   0            }
 };
 struct {
@@ -385,6 +389,12 @@ static CHILD *get_record(FILE *f)
                        case D_DIDBOOT:
                                fscanf(f, "%d\n", &did_boot);
                                break;
+                       case D_WROTE_WTMP_RLEVEL:
+                               fscanf(f, "%d\n", &wrote_wtmp_rlevel);
+                               break;
+                       case D_WROTE_UTMP_RLEVEL:
+                               fscanf(f, "%d\n", &wrote_utmp_rlevel);
+                               break;
                        default:
                                if (cmd > 0 || cmd == C_EOF) {
                                        oops_error = -1;
@@ -1004,6 +1014,14 @@ int spawn(CHILD *ch, int *res)
                                dup(f);
                                dup(f);
                        }
+
+                       /*
+                        * 4 Sep 2001, Andrea Arcangeli:
+                        * Fix a race in spawn() that is used to deadlock init in a
+                        * waitpid() loop: must set the childhandler as default before forking
+                        * off the child or the chld_handler could run before the waitpid loop
+                        * has a chance to find its zombie-child.
+                        */
                        SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
                        if ((pid = fork()) < 0) {
                                initlog(L_VB, "cannot fork: %s",
@@ -1729,6 +1747,8 @@ int read_level(int arg)
        }
 
        /* Store both the old and the new runlevel. */
+       wrote_utmp_rlevel = 0;
+       wrote_wtmp_rlevel = 0;
        write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
        thislevel = foo;
        prevlevel = runlevel;
@@ -1929,6 +1949,25 @@ void re_exec(void)
        initlog(L_CO, "Attempt to re-exec failed");
 }
 
+/*
+ *     Redo utmp/wtmp entries if required or requested
+ *     Check for written records and size of utmp
+ */
+static
+void redo_utmp_wtmp(void)
+{
+       struct stat ustat;
+       const int ret = stat(UTMP_FILE, &ustat);
+
+       if ((ret < 0) || (ustat.st_size == 0))
+               wrote_utmp_rlevel = wrote_utmp_reboot = 0;
+
+       if ((wrote_wtmp_reboot == 0) || (wrote_utmp_reboot == 0))
+               write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+       if ((wrote_wtmp_rlevel == 0) || (wrote_wtmp_rlevel == 0))
+               write_utmp_wtmp("runlevel", "~~", thislevel + 256 * prevlevel, RUN_LVL, "~");
+}
 
 /*
  *     We got a change runlevel request through the
@@ -1960,6 +1999,7 @@ void fifo_new_level(int level)
                        if (oldlevel != 'S' && runlevel == 'S') console_stty();
                        if (runlevel == '6' || runlevel == '0' ||
                            runlevel == '1') console_stty();
+                       if (runlevel  > '1' && runlevel  < '6') redo_utmp_wtmp();
                        read_inittab();
                        fail_cancel();
                        setproctitle("init [%c]", runlevel);
@@ -2243,6 +2283,8 @@ void boot_transitions()
        }
        if (loglevel > 0) {
                initlog(L_VB, "Entering runlevel: %c", runlevel);
+               wrote_utmp_rlevel = 0;
+               wrote_wtmp_rlevel = 0;
                write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
                thislevel = runlevel;
                prevlevel = oldlevel;
@@ -2421,6 +2463,7 @@ int init_main()
   console_init();
 
   if (!reload) {
+       int fd;
 
        /* Close whatever files are open, and reset the console. */
        close(0);
@@ -2438,7 +2481,8 @@ int init_main()
         *      Initialize /var/run/utmp (only works if /var is on
         *      root and mounted rw)
         */
-       (void) close(open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));
+       if ((fd = open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
+               close(fd);
 
        /*
         *      Say hello to the world
index 8a44468cb865a2d78cb50d30b2e28d97dfe6601d..9763140a292787076d7934b1c4a2083921b6069d 100644 (file)
@@ -118,6 +118,10 @@ typedef struct _child_ {
 extern CHILD *family;
 extern int wrote_wtmp_reboot;
 extern int wrote_utmp_reboot;
+extern int wrote_wtmp_rlevel;
+extern int wrote_utmp_rlevel;
+extern char thislevel;
+extern char prevlevel;
 
 /* Tokens in state parser */
 #define C_VER          1
@@ -139,4 +143,6 @@ extern int wrote_utmp_reboot;
 #define D_WROTE_UTMP_REBOOT -7
 #define D_SLTIME       -8
 #define D_DIDBOOT      -9
+#define D_WROTE_WTMP_RLEVEL -16
+#define D_WROTE_UTMP_RLEVEL -17
 
index 38d23ff49ece3f67ded69801f2641bd885255528..da91e82c414f94bdced1fab610e3f4d91da24143 100644 (file)
@@ -476,14 +476,14 @@ int list(struct utmp *p, time_t t, int what)
                     strcmp(s + 1, domainname) == 0) *s = 0;
 #endif
                if (!altlist) {
-                       snprintf(final, sizeof(final),
+                       len = snprintf(final, sizeof(final),
                                fulltime ?
                                "%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
                                "%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
                                p->ut_name, utline,
                                domain, logintime, logouttime, length);
                } else {
-                       snprintf(final, sizeof(final), 
+                       len = snprintf(final, sizeof(final), 
                                fulltime ?
                                "%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
                                "%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
@@ -491,13 +491,19 @@ int list(struct utmp *p, time_t t, int what)
                                logintime, logouttime, length, domain);
                }
        } else
-               snprintf(final, sizeof(final),
+               len = snprintf(final, sizeof(final),
                        fulltime ?
                        "%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
                        "%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
                        p->ut_name, utline,
                        logintime, logouttime, length);
 
+#if defined(__GLIBC__)
+#  if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)
+       final[sizeof(final)-1] = '\0';
+#  endif
+#endif
+
        /*
         *      Print out "final" string safely.
         */
@@ -508,6 +514,9 @@ int list(struct utmp *p, time_t t, int what)
                        putchar('*');
        }
 
+       if (len < 0 || len >= sizeof(final))
+               putchar('\n');
+
        recsdone++;
        if (maxrecs && recsdone >= maxrecs)
                return 1;
index 5a0c101e8f0f2bdb87a0ec43f626b4c85fec92e4..c1ae0c9a7d742888f885bdb5da74438c6d3114df 100644 (file)
@@ -65,6 +65,12 @@ char *line)                  /* Which line is this */
        struct utsname uname_buf;
        struct timeval tv;
        
+       /*
+        *      Can't do much if WTMP_FILE is not present or not writable.
+        */
+       if (access(WTMP_FILE, W_OK) < 0)
+               return;
+
        /*
         *      Try to open the wtmp file. Note that we even try
         *      this if we have updwtmp() so we can see if the
@@ -86,6 +92,23 @@ char *line)                  /* Which line is this */
         */
        if (wrote_wtmp_reboot == 0 && type != BOOT_TIME)
                write_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+       /*
+        *      Note if we are going to write a runlevel record.
+        */
+       if (type == RUN_LVL) wrote_wtmp_rlevel++;
+
+       /*
+        *      See if we need to write a runlevel record. The reason that
+        *      we are being so paranoid is that when we first tried to
+        *      write the reboot record, /var was possibly not mounted
+        *      yet. As soon as we can open WTMP we write a delayed runlevel record.
+        */
+       if (wrote_wtmp_rlevel == 0 && type != RUN_LVL) {
+               int runlevel = thislevel;
+               int oldlevel = prevlevel;
+               write_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
+       }
 #endif
 
        /*
@@ -135,9 +158,9 @@ char *oldline)                      /* Line of old utmp entry. */
        struct timeval tv;
 
        /*
-        *      Can't do much if UTMP_FILE is not present.
+        *      Can't do much if UTMP_FILE is not present or not writable.
         */
-       if (access(UTMP_FILE, F_OK) < 0)
+       if (access(UTMP_FILE, W_OK) < 0)
                return;
 
 #ifdef INIT_MAIN
@@ -150,10 +173,27 @@ char *oldline)                    /* Line of old utmp entry. */
         *      See if we need to write a reboot record. The reason that
         *      we are being so paranoid is that when we first tried to
         *      write the reboot record, /var was possibly not mounted
-        *      yet. As soon as we can open WTMP we write a delayed boot record.
+        *      yet. As soon as we can open UTMP we write a delayed boot record.
         */
        if (wrote_utmp_reboot == 0 && type != BOOT_TIME)
                write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL);
+
+       /*
+        *      Note if we are going to write a runlevel record.
+        */
+       if (type == RUN_LVL) wrote_utmp_rlevel++;
+
+       /*
+        *      See if we need to write a runlevel record. The reason that
+        *      we are being so paranoid is that when we first tried to
+        *      write the reboot record, /var was possibly not mounted
+        *      yet. As soon as we can open UTMP we write a delayed runlevel record.
+        */
+       if (wrote_utmp_rlevel == 0 && type != RUN_LVL) {
+               int runlevel = thislevel;
+               int oldlevel = prevlevel;
+               write_utmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~", NULL);
+       }
 #endif
 
        /*