diff options
author | Christian Neukirchen <chneukirchen@gmail.com> | 2014-07-31 19:47:55 +0200 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2014-07-31 19:47:55 +0200 |
commit | 59765bdd480ba2ebc1b0aa9dadc203adf296047d (patch) | |
tree | ae3772555c3093bc3f53eb396a8508c8048f8757 /src/usr.bin/calendar/calendar.c | |
parent | f6f0484131f91f397492ecbbab16c5bce5acdb82 (diff) | |
download | outils-59765bdd480ba2ebc1b0aa9dadc203adf296047d.tar.gz outils-59765bdd480ba2ebc1b0aa9dadc203adf296047d.tar.xz outils-59765bdd480ba2ebc1b0aa9dadc203adf296047d.zip |
import calendar
Diffstat (limited to 'src/usr.bin/calendar/calendar.c')
-rw-r--r-- | src/usr.bin/calendar/calendar.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/usr.bin/calendar/calendar.c b/src/usr.bin/calendar/calendar.c new file mode 100644 index 0000000..05b0d26 --- /dev/null +++ b/src/usr.bin/calendar/calendar.c @@ -0,0 +1,261 @@ +/* $OpenBSD: calendar.c,v 1.28 2012/01/31 08:29:25 otto Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <err.h> +#include <errno.h> +#include <locale.h> +#include <login_cap.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <tzfile.h> +#include <unistd.h> + +#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 */ +int f_SetdayAfter = 0; /* calendar invoked with -A */ + +struct specialev spev[NUMEV]; + +void childsig(int); + +int +main(int argc, char *argv[]) +{ + int ch; + char *caldir; + + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "abf:t:A:B:-")) != -1) + switch (ch) { + case '-': /* backward contemptible */ + case 'a': + if (getuid()) + errx(1, "%s", strerror(EPERM)); + doall = 1; + break; + + case 'b': + bodun_always++; + break; + + case 'f': /* other calendar file */ + calendarFile = optarg; + break; + + case 't': /* other date, undocumented, for tests */ + if ((f_time = Mktime(optarg)) <= 0) + errx(1, "specified date is outside allowed range"); + break; + + case 'A': /* days after current date */ + f_dayAfter = atoi(optarg); + f_SetdayAfter = 1; + break; + + case 'B': /* days before current date */ + f_dayBefore = atoi(optarg); + break; + + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc) + usage(); + + /* use current time */ + if (f_time <= 0) + (void)time(&f_time); + + if (f_dayBefore) { + /* Move back in time and only look forwards */ + f_dayAfter += f_dayBefore; + f_time -= SECSPERDAY * f_dayBefore; + f_dayBefore = 0; + } + 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) { + 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)setpgid(getpid(), getpid()); + (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(); + exit(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. + */ + if (getpgid(kid) != getpgrp()) + (void)killpg(getpgid(kid), SIGTERM); + else + (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)) + cal(); + } else + cal(); + + exit(0); +} + + +void +usage(void) +{ + (void)fprintf(stderr, + "usage: calendar [-ab] [-A num] [-B num] [-f calendarfile] " + "[-t [[[cc]yy]mm]dd]\n"); + exit(1); +} + + +void +childsig(int signo) +{ +} |