=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/calendar/calendar.c,v retrieving revision 1.13 retrieving revision 1.23 diff -u -r1.13 -r1.23 --- src/usr.bin/calendar/calendar.c 2000/06/30 16:00:11 1.13 +++ src/usr.bin/calendar/calendar.c 2004/12/10 15:31:01 1.23 @@ -1,4 +1,4 @@ -/* $OpenBSD: calendar.c,v 1.13 2000/06/30 16:00:11 millert Exp $ */ +/* $OpenBSD: calendar.c,v 1.23 2004/12/10 15:31:01 mickey Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -12,11 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -43,14 +39,19 @@ #if 0 static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #else -static char rcsid[] = "$OpenBSD: calendar.c,v 1.13 2000/06/30 16:00:11 millert Exp $"; +static const char rcsid[] = "$OpenBSD: calendar.c,v 1.23 2004/12/10 15:31:01 mickey Exp $"; #endif #endif /* not lint */ +#include +#include +#include #include #include #include +#include #include +#include #include #include #include @@ -61,26 +62,31 @@ #include "pathnames.h" #include "calendar.h" +char *calendarFile = "calendar"; /* default calendar file */ +char *calendarHome = ".calendar"; /* HOME */ +char *calendarNoMail = "nomail"; /* don't sent mail if this file exists */ + struct passwd *pw; int doall = 0; time_t f_time = 0; +int bodun_always = 0; int f_dayAfter = 0; /* days after current date */ int f_dayBefore = 0; /* days before current date */ struct specialev spev[NUMEV]; +void childsig(int); + int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { - int ch, i; + int ch; char *caldir; (void)setlocale(LC_ALL, ""); - while ((ch = getopt(argc, argv, "-af:t:A:B:")) != -1) + while ((ch = getopt(argc, argv, "abf:t:A:B:-")) != -1) switch (ch) { case '-': /* backward contemptible */ case 'a': @@ -89,6 +95,10 @@ doall = 1; break; + case 'b': + bodun_always++; + break; + case 'f': /* other calendar file */ calendarFile = optarg; break; @@ -128,20 +138,110 @@ settime(&f_time); if (doall) { + pid_t kid, deadkid; + int kidstat, kidreaped, runningkids; + int acstat; + struct stat sbuf; + time_t t; + unsigned int sleeptime; + + signal(SIGCHLD, childsig); + runningkids = 0; + t = time(NULL); while ((pw = getpwent()) != NULL) { - (void)setlocale(LC_ALL, ""); - (void)setegid(pw->pw_gid); - (void)initgroups(pw->pw_name, pw->pw_gid); - (void)seteuid(pw->pw_uid); - if (!chdir(pw->pw_dir)) { + acstat = 0; + /* Avoid unnecessary forks. The calendar file is only + * opened as the user later; if it can't be opened, + * it's no big deal. Also, get to correct directory. + * Note that in an NFS environment root may get EACCES + * on a chdir(), in which case we have to fork. As long as + * we can chdir() we can stat(), unless the user is + * modifying permissions while this is running. + */ + if (chdir(pw->pw_dir)) { + if (errno == EACCES) + acstat = 1; + else + continue; + } + if (stat(calendarFile, &sbuf) != 0) { + if (chdir(calendarHome)) { + if (errno == EACCES) + acstat = 1; + else + continue; + } + if (stat(calendarNoMail, &sbuf) == 0 || + stat(calendarFile, &sbuf) != 0) + continue; + } + sleeptime = USERTIMEOUT; + switch ((kid = fork())) { + case -1: /* error */ + warn("fork"); + continue; + case 0: /* child */ + (void)setlocale(LC_ALL, ""); + if (setusercontext(NULL, pw, pw->pw_uid, + LOGIN_SETALL ^ LOGIN_SETLOGIN)) + err(1, "unable to set user context (uid %u)", + pw->pw_uid); + if (acstat) { + if (chdir(pw->pw_dir) || + stat(calendarFile, &sbuf) != 0 || + chdir(calendarHome) || + stat(calendarNoMail, &sbuf) == 0 || + stat(calendarFile, &sbuf) != 0) + exit(0); + } cal(); - /* Keep user settings from propogating */ - for (i = 0; i < NUMEV; i++) - if (spev[i].uname != NULL) - free(spev[i].uname); + exit(0); } - (void)seteuid(0); + /* parent: wait a reasonable time, then kill child if + * necessary. + */ + runningkids++; + kidreaped = 0; + do { + sleeptime = sleep(sleeptime); + /* Note that there is the possibility, if the sleep + * stops early due to some other signal, of the child + * terminating and not getting detected during the next + * sleep. In that unlikely worst case, we just sleep + * too long for that user. + */ + for (;;) { + deadkid = waitpid(-1, &kidstat, WNOHANG); + if (deadkid <= 0) + break; + runningkids--; + if (deadkid == kid) { + kidreaped = 1; + sleeptime = 0; + } + } + } while (sleeptime); + + if (!kidreaped) { + /* It doesn't _really_ matter if the kill fails, e.g. + * if there's only a zombie now. + */ + (void)kill(kid, SIGTERM); + warnx("uid %u did not finish in time", pw->pw_uid); + } + if (time(NULL) - t >= SECSPERDAY) + errx(2, "'calendar -a' took more than a day; stopped at uid %u", + pw->pw_uid); } + for (;;) { + deadkid = waitpid(-1, &kidstat, WNOHANG); + if (deadkid <= 0) + break; + runningkids--; + } + if (runningkids) + warnx( +"%d child processes still running when 'calendar -a' finished", runningkids); } else if ((caldir = getenv("CALENDAR_DIR")) != NULL) { if(!chdir(caldir)) @@ -154,9 +254,16 @@ void -usage() +usage(void) { (void)fprintf(stderr, - "usage: calendar [-a] [-A days] [-B days] [-f calendarfile] [-t [[[yy]yy][mm]]dd]\n"); + "usage: calendar [-ab] [-A num] [-B num] [-f calendarfile] " + "[-t [[[cc]yy][mm]]dd]\n"); exit(1); +} + + +void +childsig(int signo) +{ }