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