[9] | 1 | /* crontab 1.2 - user crontab manipulation Author: Kees J. Bot
|
---|
| 2 | * 12 Jan 1997
|
---|
| 3 | */
|
---|
| 4 | #define nil ((void*)0)
|
---|
| 5 | #include <sys/types.h>
|
---|
| 6 | #include <stdio.h>
|
---|
| 7 | #include <stdlib.h>
|
---|
| 8 | #include <string.h>
|
---|
| 9 | #include <signal.h>
|
---|
| 10 | #include <time.h>
|
---|
| 11 | #include <errno.h>
|
---|
| 12 | #include <unistd.h>
|
---|
| 13 | #include <fcntl.h>
|
---|
| 14 | #include <pwd.h>
|
---|
| 15 | #include <sys/stat.h>
|
---|
| 16 | #include "misc.h"
|
---|
| 17 | #include "tab.h"
|
---|
| 18 |
|
---|
| 19 | #if __minix && !__minix_vmd
|
---|
| 20 | #define seteuid(uid) ((uid),0) /* Minix can't fiddle with uids. */
|
---|
| 21 | #endif
|
---|
| 22 |
|
---|
| 23 | static int opentab(int uid, char *file, int how)
|
---|
| 24 | /* Open a crontab file under the given uid. How is 'r' or 'w'. Return
|
---|
| 25 | * the result of open(2).
|
---|
| 26 | */
|
---|
| 27 | {
|
---|
| 28 | uid_t safe_uid;
|
---|
| 29 | int flags, r, err;
|
---|
| 30 |
|
---|
| 31 | switch (how) {
|
---|
| 32 | case 'r': flags= O_RDONLY; break;
|
---|
| 33 | case 'w': flags= O_WRONLY | O_CREAT | O_TRUNC; break;
|
---|
| 34 | default: errno= EINVAL; return -1;
|
---|
| 35 | }
|
---|
| 36 |
|
---|
| 37 | #if __minix && !__minix_vmd
|
---|
| 38 | /* Standard Minix has no saved uid, so use the lousy old access(). */
|
---|
| 39 | if (uid != 0) {
|
---|
| 40 | if (access(file, how == 'r' ? R_OK : W_OK) < 0) return -1;
|
---|
| 41 | }
|
---|
| 42 | #endif
|
---|
| 43 |
|
---|
| 44 | safe_uid= geteuid();
|
---|
| 45 | seteuid(uid);
|
---|
| 46 | r= open(file, flags, 0666);
|
---|
| 47 | err= errno;
|
---|
| 48 | seteuid(safe_uid);
|
---|
| 49 | errno= err;
|
---|
| 50 | return r;
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | static void copytab(int fd_in, char *file_in, int fd_out, char *file_out)
|
---|
| 54 | /* Copy one open file to another. Complain and exit on errors. */
|
---|
| 55 | {
|
---|
| 56 | ssize_t r, w;
|
---|
| 57 | char buf[1024];
|
---|
| 58 |
|
---|
| 59 | while ((r= read(fd_in, buf, sizeof(buf))) > 0) {
|
---|
| 60 | w= 0;
|
---|
| 61 | while (w < r) {
|
---|
| 62 | if ((r= write(fd_out, buf+w, r-w)) <= 0) {
|
---|
| 63 | fprintf(stderr,
|
---|
| 64 | "%s: Write error on %s: %s\n",
|
---|
| 65 | prog_name,
|
---|
| 66 | file_out,
|
---|
| 67 | r == 0 ? "End of file"
|
---|
| 68 | : strerror(errno));
|
---|
| 69 | exit(1);
|
---|
| 70 | }
|
---|
| 71 | w+= r;
|
---|
| 72 | }
|
---|
| 73 | }
|
---|
| 74 | if (r < 0) {
|
---|
| 75 | fprintf(stderr, "%s: Read error on %s: %s\n",
|
---|
| 76 | prog_name, file_in, strerror(errno));
|
---|
| 77 | exit(1);
|
---|
| 78 | }
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | static void usage(void)
|
---|
| 82 | {
|
---|
| 83 | fprintf(stderr,
|
---|
| 84 | "Usage: %s -c [user] file # Change crontab\n"
|
---|
| 85 | " %s -l [user] # List crontab\n"
|
---|
| 86 | " %s -r [user] # Remove crontab\n"
|
---|
| 87 | " %s -p # Tell cron to reload\n",
|
---|
| 88 | prog_name, prog_name, prog_name, prog_name);
|
---|
| 89 | exit(1);
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | int main(int argc, char **argv)
|
---|
| 93 | {
|
---|
| 94 | int i;
|
---|
| 95 | int cflag, lflag, rflag, pflag;
|
---|
| 96 | uid_t uid;
|
---|
| 97 | char *user, *file;
|
---|
| 98 | struct passwd *pw;
|
---|
| 99 | static char SPOOLDIR[]= "/usr/spool/crontabs";
|
---|
| 100 | char tabfile[sizeof(SPOOLDIR) + NAME_MAX];
|
---|
| 101 |
|
---|
| 102 | prog_name= strrchr(argv[0], '/');
|
---|
| 103 | if (prog_name == nil) prog_name= argv[0]; else prog_name++;
|
---|
| 104 |
|
---|
| 105 | cflag= lflag= rflag= pflag= 0;
|
---|
| 106 | i= 1;
|
---|
| 107 | while (i < argc && argv[i][0] == '-') {
|
---|
| 108 | char *opt= argv[i++] + 1;
|
---|
| 109 |
|
---|
| 110 | if (opt[0] == '-' && opt[1] == 0) break; /* -- */
|
---|
| 111 |
|
---|
| 112 | while (*opt != 0) switch (*opt++) {
|
---|
| 113 | case 'c': cflag= 1; break;
|
---|
| 114 | case 'l': lflag= 1; break;
|
---|
| 115 | case 'r': rflag= 1; break;
|
---|
| 116 | case 'p': pflag= 1; break;
|
---|
| 117 | default: usage();
|
---|
| 118 | }
|
---|
| 119 | }
|
---|
| 120 | if (cflag + lflag + rflag + pflag != 1) usage();
|
---|
| 121 |
|
---|
| 122 | user= file= nil;
|
---|
| 123 | if (!pflag && i < argc) user= argv[i++];
|
---|
| 124 | if (cflag) {
|
---|
| 125 | if (user == nil) usage();
|
---|
| 126 | if (i < argc) {
|
---|
| 127 | file= argv[i++];
|
---|
| 128 | } else {
|
---|
| 129 | file= user;
|
---|
| 130 | user= nil;
|
---|
| 131 | }
|
---|
| 132 | }
|
---|
| 133 | if (i != argc) usage();
|
---|
| 134 |
|
---|
| 135 | if (geteuid() != 0) {
|
---|
| 136 | fprintf(stderr, "%s: No root privileges?\n", prog_name);
|
---|
| 137 | }
|
---|
| 138 | uid= getuid();
|
---|
| 139 | if (user == nil) {
|
---|
| 140 | if ((pw= getpwuid(uid)) == nil) {
|
---|
| 141 | fprintf(stderr,
|
---|
| 142 | "%s: Don't know who you (uid %lu) are!\n",
|
---|
| 143 | prog_name, (unsigned long) uid);
|
---|
| 144 | exit(1);
|
---|
| 145 | }
|
---|
| 146 | } else {
|
---|
| 147 | if ((pw= getpwnam(user)) == nil) {
|
---|
| 148 | fprintf(stderr,
|
---|
| 149 | "%s: Don't know who you (%s) are!\n",
|
---|
| 150 | prog_name, user);
|
---|
| 151 | exit(1);
|
---|
| 152 | }
|
---|
| 153 | }
|
---|
| 154 | if (uid != 0 && pw->pw_uid != uid) {
|
---|
| 155 | fprintf(stderr,
|
---|
| 156 | "%s: Only root can change the crontabs of others!\n",
|
---|
| 157 | prog_name);
|
---|
| 158 | exit(1);
|
---|
| 159 | }
|
---|
| 160 | user= pw->pw_name;
|
---|
| 161 | uid= pw->pw_uid;
|
---|
| 162 | seteuid(uid);
|
---|
| 163 | umask(0077);
|
---|
| 164 |
|
---|
| 165 | selectlog(STDERR);
|
---|
| 166 | sprintf(tabfile, "%s/%s", SPOOLDIR, user);
|
---|
| 167 |
|
---|
| 168 | if (lflag) {
|
---|
| 169 | int fd;
|
---|
| 170 |
|
---|
| 171 | if ((fd= opentab(0, tabfile, 'r')) < 0) {
|
---|
| 172 | fprintf(stderr, "%s: Can't open %s: %s\n",
|
---|
| 173 | prog_name, tabfile, strerror(errno));
|
---|
| 174 | exit(1);
|
---|
| 175 | }
|
---|
| 176 | copytab(fd, tabfile, 1, "stdout");
|
---|
| 177 | close(fd);
|
---|
| 178 | }
|
---|
| 179 |
|
---|
| 180 | if (rflag) {
|
---|
| 181 | seteuid(0);
|
---|
| 182 | if (unlink(tabfile) < 0) {
|
---|
| 183 | fprintf(stderr, "%s: Can't remove %s: %s\n",
|
---|
| 184 | prog_name, tabfile, strerror(errno));
|
---|
| 185 | exit(1);
|
---|
| 186 | }
|
---|
| 187 | seteuid(uid);
|
---|
| 188 | printf("Crontab of %s removed\n", user);
|
---|
| 189 | pflag= 1;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | /* Initialize current Time */
|
---|
| 193 | time(&now);
|
---|
| 194 |
|
---|
| 195 | if (cflag) {
|
---|
| 196 | int fd1, fd2;
|
---|
| 197 |
|
---|
| 198 | if ((fd1= opentab(uid, file, 'r')) < 0) {
|
---|
| 199 | fprintf(stderr, "%s: Can't open %s: %s\n",
|
---|
| 200 | prog_name, file, strerror(errno));
|
---|
| 201 | exit(1);
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | /* Try to parse the new crontab file. If the parsing
|
---|
| 205 | * succeeds then 'crontabs' will be non-null.
|
---|
| 206 | */
|
---|
| 207 | tab_parse(file, user);
|
---|
| 208 | tab_purge();
|
---|
| 209 | if (crontabs == nil) exit(1);
|
---|
| 210 |
|
---|
| 211 | if ((fd2= opentab(0, tabfile, 'w')) < 0) {
|
---|
| 212 | fprintf(stderr, "%s: Can't open %s: %s\n",
|
---|
| 213 | prog_name, tabfile, strerror(errno));
|
---|
| 214 | exit(1);
|
---|
| 215 | }
|
---|
| 216 | copytab(fd1, file, fd2, tabfile);
|
---|
| 217 | close(fd1);
|
---|
| 218 | close(fd2);
|
---|
| 219 | printf("New crontab for %s installed\n", user);
|
---|
| 220 | pflag= 1;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | if (pflag) {
|
---|
| 224 | /* Alert cron to the new situation. */
|
---|
| 225 | FILE *fp;
|
---|
| 226 |
|
---|
| 227 | seteuid(0);
|
---|
| 228 | if ((fp= fopen(PIDFILE, "r")) != NULL) {
|
---|
| 229 | unsigned long pid;
|
---|
| 230 | int c;
|
---|
| 231 |
|
---|
| 232 | pid= 0;
|
---|
| 233 | while ((c= fgetc(fp)) != EOF && c != '\n') {
|
---|
| 234 | if ((unsigned) (c - '0') >= 10) {
|
---|
| 235 | pid= 0; break;
|
---|
| 236 | }
|
---|
| 237 | pid= 10*pid + (c - '0');
|
---|
| 238 | if (pid >= 30000) { pid= 0; break; }
|
---|
| 239 | }
|
---|
| 240 | if (pid > 1 && kill((pid_t) pid, SIGHUP) == 0) {
|
---|
| 241 | pflag= 0;
|
---|
| 242 | }
|
---|
| 243 | }
|
---|
| 244 | seteuid(uid);
|
---|
| 245 | if (pflag) {
|
---|
| 246 | fprintf(stderr,
|
---|
| 247 | "%s: Alerting cron has failed; cron still running?\n",
|
---|
| 248 | prog_name);
|
---|
| 249 | exit(1);
|
---|
| 250 | }
|
---|
| 251 | printf("Cron signalled to reload tables\n");
|
---|
| 252 | }
|
---|
| 253 | return 0;
|
---|
| 254 | }
|
---|
| 255 |
|
---|
| 256 | /*
|
---|
| 257 | * $PchId: crontab.c,v 1.4 2000/07/17 18:54:50 philip Exp $
|
---|
| 258 | */
|
---|