--- src/init.c +++ src/init.c 2006-08-22 13:04:27.000000000 +0000 @@ -107,6 +107,8 @@ sig_atomic_t got_signals; /* Set if we r 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 */ @@ -176,6 +178,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 { @@ -371,6 +375,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; @@ -1697,6 +1707,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; @@ -1897,6 +1909,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 @@ -1928,6 +1959,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); @@ -2223,6 +2255,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; @@ -2401,6 +2435,7 @@ int init_main() console_init(); if (!reload) { + int fd; /* Close whatever files are open, and reset the console. */ close(0); @@ -2418,7 +2453,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 --- src/init.h +++ src/init.h 2006-08-22 12:29:39.000000000 +0000 @@ -99,6 +99,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 @@ -120,4 +124,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 --- src/utmp.c +++ src/utmp.c 2006-08-22 12:28:52.000000000 +0000 @@ -49,6 +49,12 @@ char *line) /* Which line is this */ struct utsname uname_buf; /* + * 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 * wtmp file is accessible. @@ -69,6 +75,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 /* @@ -115,9 +138,9 @@ char *oldline) /* Line of old utmp ent struct utmp *utmptr; /* - * 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 @@ -130,10 +153,27 @@ char *oldline) /* Line of old utmp ent * 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 /*