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 --- |