Annotation of src/usr.bin/calendar/calendar.c, Revision 1.22
1.22 ! jmc 1: /* $OpenBSD: calendar.c,v 1.21 2003/06/10 22:20:45 deraadt Exp $ */
1.1 deraadt 2:
3: /*
4: * Copyright (c) 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.20 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #ifndef lint
1.5 millert 33: static const char copyright[] =
1.1 deraadt 34: "@(#) Copyright (c) 1989, 1993\n\
35: The Regents of the University of California. All rights reserved.\n";
36: #endif /* not lint */
37:
38: #ifndef lint
39: #if 0
1.5 millert 40: static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
41: #else
1.22 ! jmc 42: static char rcsid[] = "$OpenBSD: calendar.c,v 1.21 2003/06/10 22:20:45 deraadt Exp $";
1.1 deraadt 43: #endif
44: #endif /* not lint */
45:
1.15 pjanzen 46: #include <sys/stat.h>
47: #include <sys/types.h>
48: #include <sys/wait.h>
1.1 deraadt 49: #include <err.h>
50: #include <errno.h>
1.5 millert 51: #include <locale.h>
1.15 pjanzen 52: #include <login_cap.h>
1.1 deraadt 53: #include <pwd.h>
1.15 pjanzen 54: #include <signal.h>
1.1 deraadt 55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
1.5 millert 58: #include <time.h>
1.12 pjanzen 59: #include <tzfile.h>
1.1 deraadt 60: #include <unistd.h>
61:
62: #include "pathnames.h"
1.5 millert 63: #include "calendar.h"
1.1 deraadt 64:
1.15 pjanzen 65: char *calendarFile = "calendar"; /* default calendar file */
66: char *calendarHome = ".calendar"; /* HOME */
67: char *calendarNoMail = "nomail"; /* don't sent mail if this file exists */
68:
1.1 deraadt 69: struct passwd *pw;
1.5 millert 70: int doall = 0;
71: time_t f_time = 0;
1.16 mickey 72: int bodun_always = 0;
1.1 deraadt 73:
1.5 millert 74: int f_dayAfter = 0; /* days after current date */
75: int f_dayBefore = 0; /* days before current date */
1.1 deraadt 76:
1.12 pjanzen 77: struct specialev spev[NUMEV];
78:
1.17 millert 79: void childsig(int);
1.15 pjanzen 80:
1.1 deraadt 81: int
1.21 deraadt 82: main(int argc, char *argv[])
1.1 deraadt 83: {
1.15 pjanzen 84: int ch;
1.1 deraadt 85: char *caldir;
86:
1.12 pjanzen 87: (void)setlocale(LC_ALL, "");
1.5 millert 88:
1.19 millert 89: while ((ch = getopt(argc, argv, "abf:t:A:B:-")) != -1)
1.1 deraadt 90: switch (ch) {
91: case '-': /* backward contemptible */
92: case 'a':
1.5 millert 93: if (getuid())
1.13 millert 94: errx(1, "%s", strerror(EPERM));
1.1 deraadt 95: doall = 1;
96: break;
1.5 millert 97:
1.16 mickey 98: case 'b':
99: bodun_always++;
100: break;
101:
1.5 millert 102: case 'f': /* other calendar file */
103: calendarFile = optarg;
104: break;
105:
106: case 't': /* other date, undocumented, for tests */
1.12 pjanzen 107: if ((f_time = Mktime(optarg)) <= 0)
1.11 pjanzen 108: errx(1, "specified date is outside allowed range");
1.5 millert 109: break;
110:
111: case 'A': /* days after current date */
112: f_dayAfter = atoi(optarg);
113: break;
114:
115: case 'B': /* days before current date */
116: f_dayBefore = atoi(optarg);
117: break;
118:
1.1 deraadt 119: default:
120: usage();
121: }
122: argc -= optind;
123: argv += optind;
124:
125: if (argc)
126: usage();
127:
1.5 millert 128: /* use current time */
129: if (f_time <= 0)
130: (void)time(&f_time);
131:
1.12 pjanzen 132: if (f_dayBefore) {
133: /* Move back in time and only look forwards */
134: f_dayAfter += f_dayBefore;
135: f_time -= SECSPERDAY * f_dayBefore;
136: f_dayBefore = 0;
137: }
138: settime(&f_time);
1.5 millert 139:
1.10 millert 140: if (doall) {
1.15 pjanzen 141: pid_t kid, deadkid;
142: int kidstat, kidreaped, runningkids;
143: int acstat;
144: struct stat sbuf;
145: time_t t;
146: unsigned int sleeptime;
147:
148: signal(SIGCHLD, childsig);
149: runningkids = 0;
150: t = time(NULL);
1.1 deraadt 151: while ((pw = getpwent()) != NULL) {
1.15 pjanzen 152: acstat = 0;
153: /* Avoid unnecessary forks. The calendar file is only
154: * opened as the user later; if it can't be opened,
155: * it's no big deal. Also, get to correct directory.
156: * Note that in an NFS environment root may get EACCES
157: * on a chdir(), in which case we have to fork. As long as
158: * we can chdir() we can stat(), unless the user is
159: * modifying permissions while this is running.
160: */
161: if (chdir(pw->pw_dir)) {
162: if (errno == EACCES)
163: acstat = 1;
164: else
165: continue;
166: }
167: if (stat(calendarFile, &sbuf) != 0) {
168: if (chdir(calendarHome)) {
169: if (errno == EACCES)
170: acstat = 1;
171: else
172: continue;
173: }
174: if (stat(calendarNoMail, &sbuf) == 0 ||
175: stat(calendarFile, &sbuf) != 0)
176: continue;
177: }
178: sleeptime = USERTIMEOUT;
179: switch ((kid = fork())) {
180: case -1: /* error */
181: warn("fork");
182: continue;
183: case 0: /* child */
184: (void)setlocale(LC_ALL, "");
185: if (setusercontext(NULL, pw, pw->pw_uid,
186: LOGIN_SETALL ^ LOGIN_SETLOGIN))
1.18 deraadt 187: err(1, "unable to set user context (uid %u)",
188: pw->pw_uid);
1.15 pjanzen 189: if (acstat) {
190: if (chdir(pw->pw_dir) ||
191: stat(calendarFile, &sbuf) != 0 ||
192: chdir(calendarHome) ||
193: stat(calendarNoMail, &sbuf) == 0 ||
194: stat(calendarFile, &sbuf) != 0)
195: exit(0);
196: }
1.1 deraadt 197: cal();
1.15 pjanzen 198: exit(0);
199: }
200: /* parent: wait a reasonable time, then kill child if
201: * necessary.
202: */
203: runningkids++;
204: kidreaped = 0;
205: do {
206: sleeptime = sleep(sleeptime);
207: /* Note that there is the possibility, if the sleep
208: * stops early due to some other signal, of the child
209: * terminating and not getting detected during the next
210: * sleep. In that unlikely worst case, we just sleep
211: * too long for that user.
212: */
213: for (;;) {
214: deadkid = waitpid(-1, &kidstat, WNOHANG);
215: if (deadkid <= 0)
216: break;
217: runningkids--;
218: if (deadkid == kid) {
219: kidreaped = 1;
220: sleeptime = 0;
221: }
222: }
223: } while (sleeptime);
224:
225: if (!kidreaped) {
226: /* It doesn't _really_ matter if the kill fails, e.g.
227: * if there's only a zombie now.
228: */
229: (void)kill(kid, SIGTERM);
1.18 deraadt 230: warnx("uid %u did not finish in time", pw->pw_uid);
1.12 pjanzen 231: }
1.15 pjanzen 232: if (time(NULL) - t >= SECSPERDAY)
1.18 deraadt 233: errx(2, "'calendar -a' took more than a day; stopped at uid %u",
234: pw->pw_uid);
1.15 pjanzen 235: }
236: for (;;) {
237: deadkid = waitpid(-1, &kidstat, WNOHANG);
238: if (deadkid <= 0)
239: break;
240: runningkids--;
1.1 deraadt 241: }
1.15 pjanzen 242: if (runningkids)
243: warnx(
244: "%d child processes still running when 'calendar -a' finished", runningkids);
1.10 millert 245: }
1.1 deraadt 246: else if ((caldir = getenv("CALENDAR_DIR")) != NULL) {
1.5 millert 247: if(!chdir(caldir))
248: cal();
1.1 deraadt 249: } else
250: cal();
1.5 millert 251:
1.1 deraadt 252: exit(0);
253: }
254:
255:
256: void
1.21 deraadt 257: usage(void)
1.1 deraadt 258: {
1.5 millert 259: (void)fprintf(stderr,
1.22 ! jmc 260: "usage: calendar [-ab] [-A num] [-B num] [-f calendarfile] "
! 261: "[-t [[[cc]yy][mm]]dd]\n");
1.1 deraadt 262: exit(1);
1.15 pjanzen 263: }
264:
265:
266: void
1.21 deraadt 267: childsig(int signo)
1.15 pjanzen 268: {
1.1 deraadt 269: }