1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)rmjob.c	5.1 (Berkeley) 06/06/85";
9 #endif not lint
10 
11 /*
12  * rmjob - remove the specified jobs from the queue.
13  */
14 
15 #include "lp.h"
16 
17 /*
18  * Stuff for handling lprm specifications
19  */
20 extern char	*user[];		/* users to process */
21 extern int	users;			/* # of users in user array */
22 extern int	requ[];			/* job number of spool entries */
23 extern int	requests;		/* # of spool requests */
24 extern char	*person;		/* name of person doing lprm */
25 
26 char	root[] = "root";
27 int	all = 0;		/* eliminate all files (root only) */
28 int	cur_daemon;		/* daemon's pid */
29 char	current[40];		/* active control file name */
30 
31 int	iscf();
32 
33 rmjob()
34 {
35 	register int i, nitems;
36 	int assasinated = 0;
37 	struct direct **files;
38 
39 	if ((i = pgetent(line, printer)) < 0)
40 		fatal("cannot open printer description file");
41 	else if (i == 0)
42 		fatal("unknown printer");
43 	if ((SD = pgetstr("sd", &bp)) == NULL)
44 		SD = DEFSPOOL;
45 	if ((LO = pgetstr("lo", &bp)) == NULL)
46 		LO = DEFLOCK;
47 	if ((LP = pgetstr("lp", &bp)) == NULL)
48 		LP = DEFDEVLP;
49 	if ((RP = pgetstr("rp", &bp)) == NULL)
50 		RP = DEFLP;
51 	RM = pgetstr("rm", &bp);
52 
53 	/*
54 	 * If the format was `lprm -' and the user isn't the super-user,
55 	 *  then fake things to look like he said `lprm user'.
56 	 */
57 	if (users < 0) {
58 		if (getuid() == 0)
59 			all = 1;	/* all files in local queue */
60 		else {
61 			user[0] = person;
62 			users = 1;
63 		}
64 	}
65 	if (!strcmp(person, "-all")) {
66 		if (from == host)
67 			fatal("The login name \"-all\" is reserved");
68 		all = 1;	/* all those from 'from' */
69 		person = root;
70 	}
71 
72 	if (chdir(SD) < 0)
73 		fatal("cannot chdir to spool directory");
74 	if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
75 		fatal("cannot access spool directory");
76 
77 	if (nitems) {
78 		/*
79 		 * Check for an active printer daemon (in which case we
80 		 *  kill it if it is reading our file) then remove stuff
81 		 *  (after which we have to restart the daemon).
82 		 */
83 		if (lockchk(LO) && chk(current)) {
84 			assasinated = kill(cur_daemon, SIGINT) == 0;
85 			if (!assasinated)
86 				fatal("cannot kill printer daemon");
87 		}
88 		/*
89 		 * process the files
90 		 */
91 		for (i = 0; i < nitems; i++)
92 			process(files[i]->d_name);
93 	}
94 	chkremote();
95 	/*
96 	 * Restart the printer daemon if it was killed
97 	 */
98 	if (assasinated && !startdaemon(printer))
99 		fatal("cannot restart printer daemon\n");
100 	exit(0);
101 }
102 
103 /*
104  * Process a lock file: collect the pid of the active
105  *  daemon and the file name of the active spool entry.
106  * Return boolean indicating existence of a lock file.
107  */
108 lockchk(s)
109 	char *s;
110 {
111 	register FILE *fp;
112 	register int i, n;
113 
114 	if ((fp = fopen(s, "r")) == NULL)
115 		if (errno == EACCES)
116 			fatal("can't access lock file");
117 		else
118 			return(0);
119 	if (!getline(fp)) {
120 		(void) fclose(fp);
121 		return(0);		/* no daemon present */
122 	}
123 	cur_daemon = atoi(line);
124 	if (kill(cur_daemon, 0) < 0) {
125 		(void) fclose(fp);
126 		return(0);		/* no daemon present */
127 	}
128 	for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
129 		if (i > 5) {
130 			n = 1;
131 			break;
132 		}
133 		sleep(i);
134 	}
135 	current[n-1] = '\0';
136 	(void) fclose(fp);
137 	return(1);
138 }
139 
140 /*
141  * Process a control file.
142  */
143 process(file)
144 	char *file;
145 {
146 	FILE *cfp;
147 
148 	if (!chk(file))
149 		return;
150 	if ((cfp = fopen(file, "r")) == NULL)
151 		fatal("cannot open %s", file);
152 	while (getline(cfp)) {
153 		switch (line[0]) {
154 		case 'U':  /* unlink associated files */
155 			if (from != host)
156 				printf("%s: ", host);
157 			printf(unlink(line+1) ? "cannot dequeue %s\n" :
158 				"%s dequeued\n", line+1);
159 		}
160 	}
161 	(void) fclose(cfp);
162 	if (from != host)
163 		printf("%s: ", host);
164 	printf(unlink(file) ? "cannot dequeue %s\n" : "%s dequeued\n", file);
165 }
166 
167 /*
168  * Do the dirty work in checking
169  */
170 chk(file)
171 	char *file;
172 {
173 	register int *r, n;
174 	register char **u, *cp;
175 	FILE *cfp;
176 
177 	/*
178 	 * Check for valid cf file name (mostly checking current).
179 	 */
180 	if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
181 		return(0);
182 
183 	if (all && (from == host || !strcmp(from, file+6)))
184 		return(1);
185 
186 	/*
187 	 * get the owner's name from the control file.
188 	 */
189 	if ((cfp = fopen(file, "r")) == NULL)
190 		return(0);
191 	while (getline(cfp)) {
192 		if (line[0] == 'P')
193 			break;
194 	}
195 	(void) fclose(cfp);
196 	if (line[0] != 'P')
197 		return(0);
198 
199 	if (users == 0 && requests == 0)
200 		return(!strcmp(file, current) && isowner(line+1, file));
201 	/*
202 	 * Check the request list
203 	 */
204 	for (n = 0, cp = file+3; isdigit(*cp); )
205 		n = n * 10 + (*cp++ - '0');
206 	for (r = requ; r < &requ[requests]; r++)
207 		if (*r == n && isowner(line+1, file))
208 			return(1);
209 	/*
210 	 * Check to see if it's in the user list
211 	 */
212 	for (u = user; u < &user[users]; u++)
213 		if (!strcmp(*u, line+1) && isowner(line+1, file))
214 			return(1);
215 	return(0);
216 }
217 
218 /*
219  * If root is removing a file on the local machine, allow it.
220  * If root is removing a file from a remote machine, only allow
221  * files sent from the remote machine to be removed.
222  * Normal users can only remove the file from where it was sent.
223  */
224 isowner(owner, file)
225 	char *owner, *file;
226 {
227 	if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
228 		return(1);
229 	if (!strcmp(person, owner) && !strcmp(from, file+6))
230 		return(1);
231 	if (from != host)
232 		printf("%s: ", host);
233 	printf("%s: Permission denied\n", file);
234 	return(0);
235 }
236 
237 /*
238  * Check to see if we are sending files to a remote machine. If we are,
239  * then try removing files on the remote machine.
240  */
241 chkremote()
242 {
243 	register char *cp;
244 	register int i, rem;
245 	char buf[BUFSIZ];
246 
247 	if (*LP || RM == NULL)
248 		return;	/* not sending to a remote machine */
249 
250 	/*
251 	 * Flush stdout so the user can see what has been deleted
252 	 * while we wait (possibly) for the connection.
253 	 */
254 	fflush(stdout);
255 
256 	sprintf(buf, "\5%s %s", RP, all ? "-all" : person);
257 	cp = buf;
258 	for (i = 0; i < users; i++) {
259 		cp += strlen(cp);
260 		*cp++ = ' ';
261 		strcpy(cp, user[i]);
262 	}
263 	for (i = 0; i < requests; i++) {
264 		cp += strlen(cp);
265 		(void) sprintf(cp, " %d", requ[i]);
266 	}
267 	strcat(cp, "\n");
268 	rem = getport(RM);
269 	if (rem < 0) {
270 		if (from != host)
271 			printf("%s: ", host);
272 		printf("connection to %s is down\n", RM);
273 	} else {
274 		i = strlen(buf);
275 		if (write(rem, buf, i) != i)
276 			fatal("Lost connection");
277 		while ((i = read(rem, buf, sizeof(buf))) > 0)
278 			(void) fwrite(buf, 1, i, stdout);
279 		(void) close(rem);
280 	}
281 }
282 
283 /*
284  * Return 1 if the filename begins with 'cf'
285  */
286 iscf(d)
287 	struct direct *d;
288 {
289 	return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
290 }
291