Add the comment from Andrea Arcangeli about the correct
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.
This commit is contained in:
parent
1e43b0911c
commit
13de2e9e05
@ -64,7 +64,7 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
# Additional libs for GNU libc.
|
# Additional libs for GNU libc.
|
||||||
ifneq ($(wildcard /usr/lib/libcrypt.a),)
|
ifneq ($(wildcard /usr/lib*/libcrypt.a),)
|
||||||
LCRYPT = -lcrypt
|
LCRYPT = -lcrypt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
46
src/init.c
46
src/init.c
@ -121,6 +121,8 @@ sig_atomic_t got_signals; /* Set if we received a signal. */
|
|||||||
int emerg_shell = 0; /* Start emergency shell? */
|
int emerg_shell = 0; /* Start emergency shell? */
|
||||||
int wrote_wtmp_reboot = 1; /* Set when we wrote the reboot record */
|
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_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 */
|
int sltime = 5; /* Sleep time between TERM and KILL */
|
||||||
char *argv0; /* First arguments; show up in ps listing */
|
char *argv0; /* First arguments; show up in ps listing */
|
||||||
int maxproclen; /* Maximal length of argv[0] with \0 */
|
int maxproclen; /* Maximal length of argv[0] with \0 */
|
||||||
@ -189,6 +191,8 @@ struct {
|
|||||||
{ "-WU", D_WROTE_UTMP_REBOOT},
|
{ "-WU", D_WROTE_UTMP_REBOOT},
|
||||||
{ "-ST", D_SLTIME },
|
{ "-ST", D_SLTIME },
|
||||||
{ "-DB", D_DIDBOOT },
|
{ "-DB", D_DIDBOOT },
|
||||||
|
{ "-LW", D_WROTE_WTMP_RLEVEL},
|
||||||
|
{ "-LU", D_WROTE_UTMP_RLEVEL},
|
||||||
{ "", 0 }
|
{ "", 0 }
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
@ -385,6 +389,12 @@ static CHILD *get_record(FILE *f)
|
|||||||
case D_DIDBOOT:
|
case D_DIDBOOT:
|
||||||
fscanf(f, "%d\n", &did_boot);
|
fscanf(f, "%d\n", &did_boot);
|
||||||
break;
|
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:
|
default:
|
||||||
if (cmd > 0 || cmd == C_EOF) {
|
if (cmd > 0 || cmd == C_EOF) {
|
||||||
oops_error = -1;
|
oops_error = -1;
|
||||||
@ -1004,6 +1014,14 @@ int spawn(CHILD *ch, int *res)
|
|||||||
dup(f);
|
dup(f);
|
||||||
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);
|
SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
|
||||||
if ((pid = fork()) < 0) {
|
if ((pid = fork()) < 0) {
|
||||||
initlog(L_VB, "cannot fork: %s",
|
initlog(L_VB, "cannot fork: %s",
|
||||||
@ -1729,6 +1747,8 @@ int read_level(int arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store both the old and the new runlevel. */
|
/* 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, "~");
|
write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
|
||||||
thislevel = foo;
|
thislevel = foo;
|
||||||
prevlevel = runlevel;
|
prevlevel = runlevel;
|
||||||
@ -1929,6 +1949,25 @@ void re_exec(void)
|
|||||||
initlog(L_CO, "Attempt to re-exec failed");
|
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
|
* 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 (oldlevel != 'S' && runlevel == 'S') console_stty();
|
||||||
if (runlevel == '6' || runlevel == '0' ||
|
if (runlevel == '6' || runlevel == '0' ||
|
||||||
runlevel == '1') console_stty();
|
runlevel == '1') console_stty();
|
||||||
|
if (runlevel > '1' && runlevel < '6') redo_utmp_wtmp();
|
||||||
read_inittab();
|
read_inittab();
|
||||||
fail_cancel();
|
fail_cancel();
|
||||||
setproctitle("init [%c]", runlevel);
|
setproctitle("init [%c]", runlevel);
|
||||||
@ -2243,6 +2283,8 @@ void boot_transitions()
|
|||||||
}
|
}
|
||||||
if (loglevel > 0) {
|
if (loglevel > 0) {
|
||||||
initlog(L_VB, "Entering runlevel: %c", runlevel);
|
initlog(L_VB, "Entering runlevel: %c", runlevel);
|
||||||
|
wrote_utmp_rlevel = 0;
|
||||||
|
wrote_wtmp_rlevel = 0;
|
||||||
write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
|
write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
|
||||||
thislevel = runlevel;
|
thislevel = runlevel;
|
||||||
prevlevel = oldlevel;
|
prevlevel = oldlevel;
|
||||||
@ -2421,6 +2463,7 @@ int init_main()
|
|||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
if (!reload) {
|
if (!reload) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
/* Close whatever files are open, and reset the console. */
|
/* Close whatever files are open, and reset the console. */
|
||||||
close(0);
|
close(0);
|
||||||
@ -2438,7 +2481,8 @@ int init_main()
|
|||||||
* Initialize /var/run/utmp (only works if /var is on
|
* Initialize /var/run/utmp (only works if /var is on
|
||||||
* root and mounted rw)
|
* 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
|
* Say hello to the world
|
||||||
|
@ -118,6 +118,10 @@ typedef struct _child_ {
|
|||||||
extern CHILD *family;
|
extern CHILD *family;
|
||||||
extern int wrote_wtmp_reboot;
|
extern int wrote_wtmp_reboot;
|
||||||
extern int wrote_utmp_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 */
|
/* Tokens in state parser */
|
||||||
#define C_VER 1
|
#define C_VER 1
|
||||||
@ -139,4 +143,6 @@ extern int wrote_utmp_reboot;
|
|||||||
#define D_WROTE_UTMP_REBOOT -7
|
#define D_WROTE_UTMP_REBOOT -7
|
||||||
#define D_SLTIME -8
|
#define D_SLTIME -8
|
||||||
#define D_DIDBOOT -9
|
#define D_DIDBOOT -9
|
||||||
|
#define D_WROTE_WTMP_RLEVEL -16
|
||||||
|
#define D_WROTE_UTMP_RLEVEL -17
|
||||||
|
|
||||||
|
15
src/last.c
15
src/last.c
@ -476,14 +476,14 @@ int list(struct utmp *p, time_t t, int what)
|
|||||||
strcmp(s + 1, domainname) == 0) *s = 0;
|
strcmp(s + 1, domainname) == 0) *s = 0;
|
||||||
#endif
|
#endif
|
||||||
if (!altlist) {
|
if (!altlist) {
|
||||||
snprintf(final, sizeof(final),
|
len = snprintf(final, sizeof(final),
|
||||||
fulltime ?
|
fulltime ?
|
||||||
"%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
|
"%-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",
|
"%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
|
||||||
p->ut_name, utline,
|
p->ut_name, utline,
|
||||||
domain, logintime, logouttime, length);
|
domain, logintime, logouttime, length);
|
||||||
} else {
|
} else {
|
||||||
snprintf(final, sizeof(final),
|
len = snprintf(final, sizeof(final),
|
||||||
fulltime ?
|
fulltime ?
|
||||||
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
|
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
|
||||||
"%-8.8s %-12.12s %-16.16s %-7.7s %-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);
|
logintime, logouttime, length, domain);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
snprintf(final, sizeof(final),
|
len = snprintf(final, sizeof(final),
|
||||||
fulltime ?
|
fulltime ?
|
||||||
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
|
"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
|
||||||
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
|
"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
|
||||||
p->ut_name, utline,
|
p->ut_name, utline,
|
||||||
logintime, logouttime, length);
|
logintime, logouttime, length);
|
||||||
|
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
# if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)
|
||||||
|
final[sizeof(final)-1] = '\0';
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print out "final" string safely.
|
* Print out "final" string safely.
|
||||||
*/
|
*/
|
||||||
@ -508,6 +514,9 @@ int list(struct utmp *p, time_t t, int what)
|
|||||||
putchar('*');
|
putchar('*');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len < 0 || len >= sizeof(final))
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
recsdone++;
|
recsdone++;
|
||||||
if (maxrecs && recsdone >= maxrecs)
|
if (maxrecs && recsdone >= maxrecs)
|
||||||
return 1;
|
return 1;
|
||||||
|
46
src/utmp.c
46
src/utmp.c
@ -65,6 +65,12 @@ char *line) /* Which line is this */
|
|||||||
struct utsname uname_buf;
|
struct utsname uname_buf;
|
||||||
struct timeval tv;
|
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
|
* Try to open the wtmp file. Note that we even try
|
||||||
* this if we have updwtmp() so we can see if the
|
* 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)
|
if (wrote_wtmp_reboot == 0 && type != BOOT_TIME)
|
||||||
write_wtmp("reboot", "~~", 0, 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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -135,9 +158,9 @@ char *oldline) /* Line of old utmp entry. */
|
|||||||
struct timeval tv;
|
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;
|
return;
|
||||||
|
|
||||||
#ifdef INIT_MAIN
|
#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
|
* See if we need to write a reboot record. The reason that
|
||||||
* we are being so paranoid is that when we first tried to
|
* we are being so paranoid is that when we first tried to
|
||||||
* write the reboot record, /var was possibly not mounted
|
* 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)
|
if (wrote_utmp_reboot == 0 && type != BOOT_TIME)
|
||||||
write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL);
|
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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user