--- src/init.c +++ src/init.c 2006-08-22 15:04:27.000000000 +0200 @@ -115,6 +115,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 */ @@ -184,6 +186,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 { @@ -379,6 +383,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; @@ -1705,6 +1715,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; @@ -1905,6 +1917,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 @@ -1936,6 +1967,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); @@ -2231,6 +2263,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; @@ -2409,6 +2443,7 @@ int init_main() console_init(); if (!reload) { + int fd; /* Close whatever files are open, and reset the console. */ close(0); @@ -2426,7 +2461,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 14:29:39.000000000 +0200 @@ -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 14:28:52.000000000 +0200 @@ -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 /*