Annotation of src/usr.bin/calendar/calendar.c, Revision 1.26
1.26 ! deraadt 1: /* $OpenBSD: calendar.c,v 1.25 2005/11/16 16:45:11 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:
1.15 pjanzen 32: #include <sys/stat.h>
33: #include <sys/types.h>
34: #include <sys/wait.h>
1.1 deraadt 35: #include <err.h>
36: #include <errno.h>
1.5 millert 37: #include <locale.h>
1.15 pjanzen 38: #include <login_cap.h>
1.1 deraadt 39: #include <pwd.h>
1.15 pjanzen 40: #include <signal.h>
1.1 deraadt 41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
1.5 millert 44: #include <time.h>
1.12 pjanzen 45: #include <tzfile.h>
1.1 deraadt 46: #include <unistd.h>
47:
48: #include "pathnames.h"
1.5 millert 49: #include "calendar.h"
1.1 deraadt 50:
1.15 pjanzen 51: char *calendarFile = "calendar"; /* default calendar file */
52: char *calendarHome = ".calendar"; /* HOME */
53: char *calendarNoMail = "nomail"; /* don't sent mail if this file exists */
54:
1.1 deraadt 55: struct passwd *pw;
1.5 millert 56: int doall = 0;
57: time_t f_time = 0;
1.16 mickey 58: int bodun_always = 0;
1.1 deraadt 59:
1.5 millert 60: int f_dayAfter = 0; /* days after current date */
61: int f_dayBefore = 0; /* days before current date */
1.24 mickey 62: int f_SetdayAfter = 0; /* calendar invoked with -A */
1.1 deraadt 63:
1.12 pjanzen 64: struct specialev spev[NUMEV];
65:
1.17 millert 66: void childsig(int);
1.15 pjanzen 67:
1.1 deraadt 68: int
1.21 deraadt 69: main(int argc, char *argv[])
1.1 deraadt 70: {
1.15 pjanzen 71: int ch;
1.1 deraadt 72: char *caldir;
73:
1.12 pjanzen 74: (void)setlocale(LC_ALL, "");
1.5 millert 75:
1.19 millert 76: while ((ch = getopt(argc, argv, "abf:t:A:B:-")) != -1)
1.1 deraadt 77: switch (ch) {
78: case '-': /* backward contemptible */
79: case 'a':
1.5 millert 80: if (getuid())
1.13 millert 81: errx(1, "%s", strerror(EPERM));
1.1 deraadt 82: doall = 1;
83: break;
1.5 millert 84:
1.16 mickey 85: case 'b':
86: bodun_always++;
87: break;
88:
1.5 millert 89: case 'f': /* other calendar file */
90: calendarFile = optarg;
91: break;
92:
93: case 't': /* other date, undocumented, for tests */
1.12 pjanzen 94: if ((f_time = Mktime(optarg)) <= 0)
1.11 pjanzen 95: errx(1, "specified date is outside allowed range");
1.5 millert 96: break;
97:
98: case 'A': /* days after current date */
99: f_dayAfter = atoi(optarg);
1.24 mickey 100: f_SetdayAfter = 1;
1.5 millert 101: break;
102:
103: case 'B': /* days before current date */
104: f_dayBefore = atoi(optarg);
105: break;
106:
1.1 deraadt 107: default:
108: usage();
109: }
110: argc -= optind;
111: argv += optind;
112:
113: if (argc)
114: usage();
115:
1.5 millert 116: /* use current time */
117: if (f_time <= 0)
118: (void)time(&f_time);
119:
1.12 pjanzen 120: if (f_dayBefore) {
121: /* Move back in time and only look forwards */
122: f_dayAfter += f_dayBefore;
123: f_time -= SECSPERDAY * f_dayBefore;
124: f_dayBefore = 0;
125: }
126: settime(&f_time);
1.5 millert 127:
1.10 millert 128: if (doall) {
1.15 pjanzen 129: pid_t kid, deadkid;
130: int kidstat, kidreaped, runningkids;
131: int acstat;
132: struct stat sbuf;
133: time_t t;
134: unsigned int sleeptime;
135:
136: signal(SIGCHLD, childsig);
137: runningkids = 0;
138: t = time(NULL);
1.1 deraadt 139: while ((pw = getpwent()) != NULL) {
1.15 pjanzen 140: acstat = 0;
141: /* Avoid unnecessary forks. The calendar file is only
142: * opened as the user later; if it can't be opened,
143: * it's no big deal. Also, get to correct directory.
144: * Note that in an NFS environment root may get EACCES
145: * on a chdir(), in which case we have to fork. As long as
146: * we can chdir() we can stat(), unless the user is
147: * modifying permissions while this is running.
148: */
149: if (chdir(pw->pw_dir)) {
150: if (errno == EACCES)
151: acstat = 1;
152: else
153: continue;
154: }
155: if (stat(calendarFile, &sbuf) != 0) {
156: if (chdir(calendarHome)) {
157: if (errno == EACCES)
158: acstat = 1;
159: else
160: continue;
161: }
162: if (stat(calendarNoMail, &sbuf) == 0 ||
163: stat(calendarFile, &sbuf) != 0)
164: continue;
165: }
166: sleeptime = USERTIMEOUT;
167: switch ((kid = fork())) {
168: case -1: /* error */
169: warn("fork");
170: continue;
171: case 0: /* child */
172: (void)setlocale(LC_ALL, "");
173: if (setusercontext(NULL, pw, pw->pw_uid,
174: LOGIN_SETALL ^ LOGIN_SETLOGIN))
1.18 deraadt 175: err(1, "unable to set user context (uid %u)",
176: pw->pw_uid);
1.15 pjanzen 177: if (acstat) {
178: if (chdir(pw->pw_dir) ||
179: stat(calendarFile, &sbuf) != 0 ||
180: chdir(calendarHome) ||
181: stat(calendarNoMail, &sbuf) == 0 ||
182: stat(calendarFile, &sbuf) != 0)
183: exit(0);
184: }
1.1 deraadt 185: cal();
1.15 pjanzen 186: exit(0);
187: }
188: /* parent: wait a reasonable time, then kill child if
189: * necessary.
190: */
191: runningkids++;
192: kidreaped = 0;
193: do {
194: sleeptime = sleep(sleeptime);
195: /* Note that there is the possibility, if the sleep
196: * stops early due to some other signal, of the child
197: * terminating and not getting detected during the next
198: * sleep. In that unlikely worst case, we just sleep
199: * too long for that user.
200: */
201: for (;;) {
202: deadkid = waitpid(-1, &kidstat, WNOHANG);
203: if (deadkid <= 0)
204: break;
205: runningkids--;
206: if (deadkid == kid) {
207: kidreaped = 1;
208: sleeptime = 0;
209: }
210: }
211: } while (sleeptime);
212:
213: if (!kidreaped) {
214: /* It doesn't _really_ matter if the kill fails, e.g.
215: * if there's only a zombie now.
216: */
217: (void)kill(kid, SIGTERM);
1.18 deraadt 218: warnx("uid %u did not finish in time", pw->pw_uid);
1.12 pjanzen 219: }
1.15 pjanzen 220: if (time(NULL) - t >= SECSPERDAY)
1.25 deraadt 221: errx(2, "'calendar -a' took more than a day; "
222: "stopped at uid %u",
1.18 deraadt 223: pw->pw_uid);
1.15 pjanzen 224: }
225: for (;;) {
226: deadkid = waitpid(-1, &kidstat, WNOHANG);
227: if (deadkid <= 0)
228: break;
229: runningkids--;
1.1 deraadt 230: }
1.15 pjanzen 231: if (runningkids)
1.25 deraadt 232: warnx("%d child processes still running when "
233: "'calendar -a' finished", runningkids);
234: } else if ((caldir = getenv("CALENDAR_DIR")) != NULL) {
1.5 millert 235: if(!chdir(caldir))
236: cal();
1.1 deraadt 237: } else
238: cal();
1.5 millert 239:
1.1 deraadt 240: exit(0);
241: }
242:
243:
244: void
1.21 deraadt 245: usage(void)
1.1 deraadt 246: {
1.5 millert 247: (void)fprintf(stderr,
1.22 jmc 248: "usage: calendar [-ab] [-A num] [-B num] [-f calendarfile] "
249: "[-t [[[cc]yy][mm]]dd]\n");
1.1 deraadt 250: exit(1);
1.15 pjanzen 251: }
252:
253:
254: void
1.21 deraadt 255: childsig(int signo)
1.15 pjanzen 256: {
1.1 deraadt 257: }