xref: /minix3/minix/commands/crontab/crontab.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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  */
259