Deleted Added
full compact
cmds.c (78146) cmds.c (78750)
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 29 unchanged lines hidden (view full) ---

38 The Regents of the University of California. All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42/*
43static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
44*/
45static const char rcsid[] =
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 29 unchanged lines hidden (view full) ---

38 The Regents of the University of California. All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42/*
43static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
44*/
45static const char rcsid[] =
46 "$FreeBSD: head/usr.sbin/lpr/lpc/cmds.c 78146 2001-06-12 16:38:20Z gad $";
46 "$FreeBSD: head/usr.sbin/lpr/lpc/cmds.c 78750 2001-06-25 02:05:03Z gad $";
47#endif /* not lint */
48
49/*
50 * lpc -- line printer control program -- commands:
51 */
52
53#include <sys/param.h>
54#include <sys/time.h>

--- 19 unchanged lines hidden (view full) ---

74static int doarg(char *_job);
75static int doselect(struct dirent *_d);
76static void putmsg(struct printer *_pp, int _argc, char **_argv);
77static int sortq(const void *_a, const void *_b);
78static void startpr(struct printer *_pp, int _chgenable);
79static int touch(struct jobqueue *_jq);
80static void unlinkf(char *_name);
81static void upstat(struct printer *_pp, const char *_msg);
47#endif /* not lint */
48
49/*
50 * lpc -- line printer control program -- commands:
51 */
52
53#include <sys/param.h>
54#include <sys/time.h>

--- 19 unchanged lines hidden (view full) ---

74static int doarg(char *_job);
75static int doselect(struct dirent *_d);
76static void putmsg(struct printer *_pp, int _argc, char **_argv);
77static int sortq(const void *_a, const void *_b);
78static void startpr(struct printer *_pp, int _chgenable);
79static int touch(struct jobqueue *_jq);
80static void unlinkf(char *_name);
81static void upstat(struct printer *_pp, const char *_msg);
82static void wrapup_clean(int _laststatus);
82
83/*
84 * generic framework for commands which operate on all or a specified
85 * set of printers
86 */
83
84/*
85 * generic framework for commands which operate on all or a specified
86 * set of printers
87 */
88enum qsel_val { /* how a given ptr was selected */
89 QSEL_UNKNOWN = -1, /* ... not selected yet */
90 QSEL_BYNAME = 0, /* ... user specifed it by name */
91 QSEL_ALL = 1 /* ... user wants "all" printers */
92 /* (with more to come) */
93};
94
95static enum qsel_val generic_qselect; /* indicates how ptr was selected */
96static int generic_initerr; /* result of initrtn processing */
97static char *generic_nullarg;
98static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */
99
87void
100void
88generic(void (*specificrtn)(struct printer *_pp), int argc, char *argv[])
101generic(void (*specificrtn)(struct printer *_pp),
102 void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[])
89{
103{
90 int cmdstatus, more;
91 struct printer myprinter, *pp = &myprinter;
104 int cmdstatus, more, targc;
105 struct printer myprinter, *pp;
106 char **targv;
92
93 if (argc == 1) {
94 printf("Usage: %s {all | printer ...}\n", argv[0]);
95 return;
96 }
107
108 if (argc == 1) {
109 printf("Usage: %s {all | printer ...}\n", argv[0]);
110 return;
111 }
112
113 /*
114 * The initialization routine for a command might set a generic
115 * "wrapup" routine, which should be called after processing all
116 * the printers in the command. This might print summary info.
117 *
118 * Note that the initialization routine may also parse (and
119 * nullify) some of the parameters given on the command, leaving
120 * only the parameters which have to do with printer names.
121 */
122 pp = &myprinter;
123 generic_wrapup = NULL;
124 generic_qselect = QSEL_UNKNOWN;
125 cmdstatus = 0;
126 /* this just needs to be a distinct value of type 'char *' */
127 if (generic_nullarg == NULL)
128 generic_nullarg = strdup("");
129
130 /* call initialization routine, if there is one for this cmd */
131 if (initrtn != NULL) {
132 generic_initerr = 0;
133 (*initrtn)(argc, argv);
134 if (generic_initerr)
135 return;
136 /* skip any initial arguments null-ified by initrtn */
137 targc = argc;
138 targv = argv;
139 while (--targc) {
140 if (targv[1] != generic_nullarg)
141 break;
142 ++targv;
143 }
144 if (targv != argv) {
145 targv[0] = argv[0]; /* copy the command-name */
146 argv = targv;
147 argc = targc + 1;
148 }
149 }
150
97 if (argc == 2 && strcmp(argv[1], "all") == 0) {
151 if (argc == 2 && strcmp(argv[1], "all") == 0) {
152 generic_qselect = QSEL_ALL;
98 more = firstprinter(pp, &cmdstatus);
99 if (cmdstatus)
100 goto looperr;
101 while (more) {
102 (*specificrtn)(pp);
103 do {
104 more = nextprinter(pp, &cmdstatus);
105looperr:

--- 4 unchanged lines hidden (view full) ---

110 pp->printer);
111 case PCAPERR_SUCCESS:
112 break;
113 default:
114 fatal(pp, pcaperr(cmdstatus));
115 }
116 } while (more && cmdstatus);
117 }
153 more = firstprinter(pp, &cmdstatus);
154 if (cmdstatus)
155 goto looperr;
156 while (more) {
157 (*specificrtn)(pp);
158 do {
159 more = nextprinter(pp, &cmdstatus);
160looperr:

--- 4 unchanged lines hidden (view full) ---

165 pp->printer);
166 case PCAPERR_SUCCESS:
167 break;
168 default:
169 fatal(pp, pcaperr(cmdstatus));
170 }
171 } while (more && cmdstatus);
172 }
118 return;
173 goto wrapup;
119 }
174 }
175
176 generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */
120 while (--argc) {
121 ++argv;
177 while (--argc) {
178 ++argv;
179 if (*argv == generic_nullarg)
180 continue;
122 init_printer(pp);
123 cmdstatus = getprintcap(*argv, pp);
124 switch (cmdstatus) {
125 default:
126 fatal(pp, pcaperr(cmdstatus));
127 case PCAPERR_NOTFOUND:
128 printf("unknown printer %s\n", *argv);
129 continue;
130 case PCAPERR_TCOPEN:
131 printf("warning: %s: unresolved tc= reference(s)\n",
132 *argv);
133 break;
134 case PCAPERR_SUCCESS:
135 break;
136 }
137 (*specificrtn)(pp);
138 }
181 init_printer(pp);
182 cmdstatus = getprintcap(*argv, pp);
183 switch (cmdstatus) {
184 default:
185 fatal(pp, pcaperr(cmdstatus));
186 case PCAPERR_NOTFOUND:
187 printf("unknown printer %s\n", *argv);
188 continue;
189 case PCAPERR_TCOPEN:
190 printf("warning: %s: unresolved tc= reference(s)\n",
191 *argv);
192 break;
193 case PCAPERR_SUCCESS:
194 break;
195 }
196 (*specificrtn)(pp);
197 }
198
199wrapup:
200 if (generic_wrapup) {
201 (*generic_wrapup)(cmdstatus);
202 }
203
139}
140
141/*
142 * kill an existing daemon and disable printing.
143 */
144void
145doabort(struct printer *pp)
146{

--- 84 unchanged lines hidden (view full) ---

231 (void) ftruncate(fd, 0);
232 if (msg == (char *)NULL)
233 (void) write(fd, "\n", 1);
234 else
235 (void) write(fd, msg, strlen(msg));
236 (void) close(fd);
237}
238
204}
205
206/*
207 * kill an existing daemon and disable printing.
208 */
209void
210doabort(struct printer *pp)
211{

--- 84 unchanged lines hidden (view full) ---

296 (void) ftruncate(fd, 0);
297 if (msg == (char *)NULL)
298 (void) write(fd, "\n", 1);
299 else
300 (void) write(fd, msg, strlen(msg));
301 (void) close(fd);
302}
303
304/*
305 * "global" variables for all the routines related to 'clean' and 'tclean'
306 */
307static time_t cln_now; /* current time */
308static double cln_minage; /* minimum age before file is removed */
309static long cln_sizecnt; /* amount of space freed up */
310static int cln_debug; /* print extra debugging msgs */
311static int cln_filecnt; /* number of files destroyed */
312static int cln_foundcore; /* found a core file! */
313static int cln_queuecnt; /* number of queues checked */
314static int cln_testonly; /* remove-files vs just-print-info */
315
239static int
240doselect(struct dirent *d)
241{
242 int c = d->d_name[0];
243
244 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
316static int
317doselect(struct dirent *d)
318{
319 int c = d->d_name[0];
320
321 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
245 return(1);
246 return(0);
322 return 1;
323 if (c == 'c') {
324 if (!strcmp(d->d_name, "core"))
325 cln_foundcore = 1;
326 }
327 if (c == 'e') {
328 if (!strncmp(d->d_name, "errs.", 5))
329 return 1;
330 }
331 return 0;
247}
248
249/*
250 * Comparison routine for scandir. Sort by job number and machine, then
251 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
252 */
253static int
254sortq(const void *a, const void *b)

--- 16 unchanged lines hidden (view full) ---

271 return(-1);
272}
273
274/*
275 * Remove all spool files and temporaries from the spooling area.
276 * Or, perhaps:
277 * Remove incomplete jobs from spooling area.
278 */
332}
333
334/*
335 * Comparison routine for scandir. Sort by job number and machine, then
336 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
337 */
338static int
339sortq(const void *a, const void *b)

--- 16 unchanged lines hidden (view full) ---

356 return(-1);
357}
358
359/*
360 * Remove all spool files and temporaries from the spooling area.
361 * Or, perhaps:
362 * Remove incomplete jobs from spooling area.
363 */
364
279void
365void
280clean(struct printer *pp)
366init_clean(int argc, char *argv[])
281{
367{
282 register int i, n;
283 register char *cp, *cp1, *lp;
368
369 /* init some fields before 'clean' is called for each queue */
370 cln_queuecnt = 0;
371 cln_now = time(NULL);
372 cln_minage = 3600.0; /* only delete files >1h old */
373 cln_filecnt = 0;
374 cln_sizecnt = 0;
375 cln_debug = 0;
376 cln_testonly = 0;
377 generic_wrapup = &wrapup_clean;
378
379 /* see if there are any options specified before the ptr list */
380 while (--argc) {
381 ++argv;
382 if (**argv != '-')
383 break;
384 if (strcmp(*argv, "-d") == 0) {
385 /* just an example of an option... */
386 cln_debug = 1;
387 *argv = generic_nullarg; /* "erase" it */
388 } else {
389 printf("Invalid option '%s'\n", *argv);
390 generic_initerr = 1;
391 }
392 }
393
394 return;
395}
396
397void
398init_tclean(int argc, char *argv[])
399{
400
401 /* only difference between 'clean' and 'tclean' is one value */
402 /* (...and the fact that 'clean' is priv and 'tclean' is not) */
403 init_clean(argc, argv);
404 cln_testonly = 1;
405
406 return;
407}
408
409void
410clean_q(struct printer *pp)
411{
412 char *cp, *cp1, *lp;
284 struct dirent **queue;
413 struct dirent **queue;
285 int nitems;
414 size_t linerem;
415 int didhead, i, n, nitems, rmcp;
286
416
287 printf("%s:\n", pp->printer);
417 cln_queuecnt++;
288
418
419 didhead = 0;
420 if (generic_qselect == QSEL_BYNAME) {
421 printf("%s:\n", pp->printer);
422 didhead = 1;
423 }
424
289 lp = line;
290 cp = pp->spool_dir;
291 while (lp < &line[sizeof(line) - 1]) {
292 if ((*lp++ = *cp++) == 0)
293 break;
294 }
295 lp[-1] = '/';
425 lp = line;
426 cp = pp->spool_dir;
427 while (lp < &line[sizeof(line) - 1]) {
428 if ((*lp++ = *cp++) == 0)
429 break;
430 }
431 lp[-1] = '/';
432 linerem = sizeof(line) - (lp - line);
296
433
434 cln_foundcore = 0;
297 seteuid(euid);
298 nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
299 seteuid(uid);
300 if (nitems < 0) {
435 seteuid(euid);
436 nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
437 seteuid(uid);
438 if (nitems < 0) {
439 if (!didhead) {
440 printf("%s:\n", pp->printer);
441 didhead = 1;
442 }
301 printf("\tcannot examine spool directory\n");
302 return;
303 }
443 printf("\tcannot examine spool directory\n");
444 return;
445 }
446 if (cln_foundcore) {
447 if (!didhead) {
448 printf("%s:\n", pp->printer);
449 didhead = 1;
450 }
451 printf("\t** found a core file in %s !\n", pp->spool_dir);
452 }
304 if (nitems == 0)
305 return;
453 if (nitems == 0)
454 return;
455 if (!didhead)
456 printf("%s:\n", pp->printer);
306 i = 0;
307 do {
308 cp = queue[i]->d_name;
457 i = 0;
458 do {
459 cp = queue[i]->d_name;
460 rmcp = 0;
309 if (*cp == 'c') {
461 if (*cp == 'c') {
462 /*
463 * A control file. Look for matching data-files.
464 */
465 /* XXX
466 * Note the logic here assumes that the hostname
467 * part of cf-filenames match the hostname part
468 * in df-filenames, and that is not necessarily
469 * true (eg: for multi-homed hosts). This needs
470 * some further thought...
471 */
310 n = 0;
311 while (i + 1 < nitems) {
312 cp1 = queue[i + 1]->d_name;
313 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
314 break;
315 i++;
316 n++;
317 }
318 if (n == 0) {
472 n = 0;
473 while (i + 1 < nitems) {
474 cp1 = queue[i + 1]->d_name;
475 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
476 break;
477 i++;
478 n++;
479 }
480 if (n == 0) {
319 strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
320 line[sizeof(line) - 1] = '\0';
321 unlinkf(line);
481 rmcp = 1;
322 }
482 }
483 } else if (*cp == 'e') {
484 /*
485 * Must be an errrs or email temp file.
486 */
487 rmcp = 1;
323 } else {
324 /*
325 * Must be a df with no cf (otherwise, it would have
326 * been skipped above) or a tf file (which can always
488 } else {
489 /*
490 * Must be a df with no cf (otherwise, it would have
491 * been skipped above) or a tf file (which can always
327 * be removed).
492 * be removed if it's old enough).
328 */
493 */
329 strncpy(lp, cp, sizeof(line) - strlen(line) - 1);
330 line[sizeof(line) - 1] = '\0';
494 rmcp = 1;
495 }
496 if (rmcp) {
497 if (strlen(cp) >= linerem) {
498 printf("\t** internal error: 'line' overflow!\n");
499 printf("\t** spooldir = %s\n", pp->spool_dir);
500 printf("\t** cp = %s\n", cp);
501 return;
502 }
503 strlcpy(lp, cp, linerem);
331 unlinkf(line);
332 }
333 } while (++i < nitems);
334}
504 unlinkf(line);
505 }
506 } while (++i < nitems);
507}
508
509static void
510wrapup_clean(int laststatus __unused)
511{
512
513 printf("Checked %d queues, and ", cln_queuecnt);
514 if (cln_filecnt < 1) {
515 printf("no cruft was found\n");
516 return;
517 }
518 if (cln_testonly) {
519 printf("would have ");
520 }
521 printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt);
522}
335
336static void
337unlinkf(char *name)
338{
523
524static void
525unlinkf(char *name)
526{
527 struct stat stbuf;
528 double agemod, agestat;
529 int res;
530 char linkbuf[BUFSIZ];
531
532 /*
533 * We have to use lstat() instead of stat(), in case this is a df*
534 * "file" which is really a symlink due to 'lpr -s' processing. In
535 * that case, we need to check the last-mod time of the symlink, and
536 * not the file that the symlink is pointed at.
537 */
339 seteuid(euid);
538 seteuid(euid);
340 if (unlink(name) < 0)
341 printf("\tcannot remove %s\n", name);
342 else
343 printf("\tremoved %s\n", name);
539 res = lstat(name, &stbuf);
344 seteuid(uid);
540 seteuid(uid);
541 if (res < 0) {
542 printf("\terror return from stat(%s):\n", name);
543 printf("\t %s\n", strerror(errno));
544 return;
545 }
546
547 agemod = difftime(cln_now, stbuf.st_mtime);
548 agestat = difftime(cln_now, stbuf.st_ctime);
549 if (cln_debug) {
550 /* this debugging-aid probably is not needed any more... */
551 printf("\t\t modify age=%g secs, stat age=%g secs\n",
552 agemod, agestat);
553 }
554 if ((agemod <= cln_minage) && (agestat <= cln_minage))
555 return;
556
557 /*
558 * if this file is a symlink, then find out the target of the
559 * symlink before unlink-ing the file itself
560 */
561 if (S_ISLNK(stbuf.st_mode)) {
562 seteuid(euid);
563 res = readlink(name, linkbuf, sizeof(linkbuf));
564 seteuid(uid);
565 if (res < 0) {
566 printf("\terror return from readlink(%s):\n", name);
567 printf("\t %s\n", strerror(errno));
568 return;
569 }
570 if (res == sizeof(linkbuf))
571 res--;
572 linkbuf[res] = '\0';
573 }
574
575 cln_filecnt++;
576 cln_sizecnt += stbuf.st_size;
577
578 if (cln_testonly) {
579 printf("\twould remove %s\n", name);
580 if (S_ISLNK(stbuf.st_mode)) {
581 printf("\t (which is a symlink to %s)\n", linkbuf);
582 }
583 } else {
584 seteuid(euid);
585 res = unlink(name);
586 seteuid(uid);
587 if (res < 0)
588 printf("\tcannot remove %s (!)\n", name);
589 else
590 printf("\tremoved %s\n", name);
591 /* XXX
592 * Note that for a df* file, this code should also check to see
593 * if it is a symlink to some other file, and if the original
594 * lpr command included '-r' ("remove file"). Of course, this
595 * code would not be removing the df* file unless there was no
596 * matching cf* file, and without the cf* file it is currently
597 * impossible to determine if '-r' had been specified...
598 *
599 * As a result of this quandry, we may be leaving behind a
600 * user's file that was supposed to have been removed after
601 * being printed. This may effect services such as CAP or
602 * samba, if they were configured to use 'lpr -r', and if
603 * datafiles are not being properly removed.
604 */
605 if (S_ISLNK(stbuf.st_mode)) {
606 printf("\t (which was a symlink to %s)\n", linkbuf);
607 }
608 }
345}
346
347/*
348 * Enable queuing to the printer (allow lpr's).
349 */
350void
351enable(struct printer *pp)
352{

--- 507 unchanged lines hidden ---
609}
610
611/*
612 * Enable queuing to the printer (allow lpr's).
613 */
614void
615enable(struct printer *pp)
616{

--- 507 unchanged lines hidden ---