1dea673e9SRodney W. Grimes /* 2dea673e9SRodney W. Grimes * Copyright (c) 1983, 1993 3dea673e9SRodney W. Grimes * The Regents of the University of California. All rights reserved. 4dea673e9SRodney W. Grimes * 5dea673e9SRodney W. Grimes * 6dea673e9SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 7dea673e9SRodney W. Grimes * modification, are permitted provided that the following conditions 8dea673e9SRodney W. Grimes * are met: 9dea673e9SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 10dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 11dea673e9SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 12dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 13dea673e9SRodney W. Grimes * documentation and/or other materials provided with the distribution. 14dea673e9SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 15dea673e9SRodney W. Grimes * must display the following acknowledgement: 16dea673e9SRodney W. Grimes * This product includes software developed by the University of 17dea673e9SRodney W. Grimes * California, Berkeley and its contributors. 18dea673e9SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 19dea673e9SRodney W. Grimes * may be used to endorse or promote products derived from this software 20dea673e9SRodney W. Grimes * without specific prior written permission. 21dea673e9SRodney W. Grimes * 22dea673e9SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23dea673e9SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24dea673e9SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25dea673e9SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26dea673e9SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27dea673e9SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28dea673e9SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29dea673e9SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30dea673e9SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31dea673e9SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32dea673e9SRodney W. Grimes * SUCH DAMAGE. 33dea673e9SRodney W. Grimes */ 34dea673e9SRodney W. Grimes 35dea673e9SRodney W. Grimes #ifndef lint 364a1a0dbeSGarrett Wollman static const char copyright[] = 37dea673e9SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 38dea673e9SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 39dea673e9SRodney W. Grimes #endif /* not lint */ 40dea673e9SRodney W. Grimes 41dea673e9SRodney W. Grimes #ifndef lint 424a1a0dbeSGarrett Wollman /* 435458e2f4SJoerg Wunsch static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; 444a1a0dbeSGarrett Wollman */ 454a1a0dbeSGarrett Wollman static const char rcsid[] = 4697d92980SPeter Wemm "$FreeBSD$"; 47dea673e9SRodney W. Grimes #endif /* not lint */ 48dea673e9SRodney W. Grimes 49dea673e9SRodney W. Grimes /* 50dea673e9SRodney W. Grimes * lpc -- line printer control program -- commands: 51dea673e9SRodney W. Grimes */ 52dea673e9SRodney W. Grimes 53dea673e9SRodney W. Grimes #include <sys/param.h> 54dea673e9SRodney W. Grimes #include <sys/time.h> 55dea673e9SRodney W. Grimes #include <sys/stat.h> 565458e2f4SJoerg Wunsch #include <sys/file.h> 57dea673e9SRodney W. Grimes 58dea673e9SRodney W. Grimes #include <signal.h> 59dea673e9SRodney W. Grimes #include <fcntl.h> 60dea673e9SRodney W. Grimes #include <errno.h> 61dea673e9SRodney W. Grimes #include <dirent.h> 62dea673e9SRodney W. Grimes #include <unistd.h> 63dea673e9SRodney W. Grimes #include <stdlib.h> 64dea673e9SRodney W. Grimes #include <stdio.h> 65dea673e9SRodney W. Grimes #include <ctype.h> 66dea673e9SRodney W. Grimes #include <string.h> 67dea673e9SRodney W. Grimes #include "lp.h" 68dea673e9SRodney W. Grimes #include "lp.local.h" 69dea673e9SRodney W. Grimes #include "lpc.h" 70dea673e9SRodney W. Grimes #include "extern.h" 71dea673e9SRodney W. Grimes #include "pathnames.h" 72dea673e9SRodney W. Grimes 73ba7a1ad7SGarance A Drosehn static void abortpr(struct printer *_pp, int _dis); 74ba7a1ad7SGarance A Drosehn static int doarg(char *_job); 75ba7a1ad7SGarance A Drosehn static int doselect(struct dirent *_d); 76ba7a1ad7SGarance A Drosehn static void putmsg(struct printer *_pp, int _argc, char **_argv); 77ba7a1ad7SGarance A Drosehn static int sortq(const void *_a, const void *_b); 78ba7a1ad7SGarance A Drosehn static void startpr(struct printer *_pp, int _chgenable); 79ba7a1ad7SGarance A Drosehn static int touch(struct jobqueue *_jq); 80ba7a1ad7SGarance A Drosehn static void unlinkf(char *_name); 81ba7a1ad7SGarance A Drosehn static void upstat(struct printer *_pp, const char *_msg); 82004c9c5dSGarance A Drosehn static void wrapup_clean(int _laststatus); 834a1a0dbeSGarrett Wollman 844a1a0dbeSGarrett Wollman /* 854a1a0dbeSGarrett Wollman * generic framework for commands which operate on all or a specified 864a1a0dbeSGarrett Wollman * set of printers 874a1a0dbeSGarrett Wollman */ 88004c9c5dSGarance A Drosehn enum qsel_val { /* how a given ptr was selected */ 89004c9c5dSGarance A Drosehn QSEL_UNKNOWN = -1, /* ... not selected yet */ 90004c9c5dSGarance A Drosehn QSEL_BYNAME = 0, /* ... user specifed it by name */ 91004c9c5dSGarance A Drosehn QSEL_ALL = 1 /* ... user wants "all" printers */ 92004c9c5dSGarance A Drosehn /* (with more to come) */ 93004c9c5dSGarance A Drosehn }; 94004c9c5dSGarance A Drosehn 95004c9c5dSGarance A Drosehn static enum qsel_val generic_qselect; /* indicates how ptr was selected */ 96004c9c5dSGarance A Drosehn static int generic_initerr; /* result of initrtn processing */ 97004c9c5dSGarance A Drosehn static char *generic_nullarg; 98004c9c5dSGarance A Drosehn static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */ 99004c9c5dSGarance A Drosehn 1004a1a0dbeSGarrett Wollman void 101004c9c5dSGarance A Drosehn generic(void (*specificrtn)(struct printer *_pp), 102004c9c5dSGarance A Drosehn void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[]) 1034a1a0dbeSGarrett Wollman { 104004c9c5dSGarance A Drosehn int cmdstatus, more, targc; 105004c9c5dSGarance A Drosehn struct printer myprinter, *pp; 106004c9c5dSGarance A Drosehn char **targv; 1074a1a0dbeSGarrett Wollman 1084a1a0dbeSGarrett Wollman if (argc == 1) { 109d3974088SDag-Erling Smørgrav printf("usage: %s {all | printer ...}\n", argv[0]); 1104a1a0dbeSGarrett Wollman return; 1114a1a0dbeSGarrett Wollman } 112004c9c5dSGarance A Drosehn 113004c9c5dSGarance A Drosehn /* 114004c9c5dSGarance A Drosehn * The initialization routine for a command might set a generic 115004c9c5dSGarance A Drosehn * "wrapup" routine, which should be called after processing all 116004c9c5dSGarance A Drosehn * the printers in the command. This might print summary info. 117004c9c5dSGarance A Drosehn * 118004c9c5dSGarance A Drosehn * Note that the initialization routine may also parse (and 119004c9c5dSGarance A Drosehn * nullify) some of the parameters given on the command, leaving 120004c9c5dSGarance A Drosehn * only the parameters which have to do with printer names. 121004c9c5dSGarance A Drosehn */ 122004c9c5dSGarance A Drosehn pp = &myprinter; 123004c9c5dSGarance A Drosehn generic_wrapup = NULL; 124004c9c5dSGarance A Drosehn generic_qselect = QSEL_UNKNOWN; 125004c9c5dSGarance A Drosehn cmdstatus = 0; 126004c9c5dSGarance A Drosehn /* this just needs to be a distinct value of type 'char *' */ 127004c9c5dSGarance A Drosehn if (generic_nullarg == NULL) 128004c9c5dSGarance A Drosehn generic_nullarg = strdup(""); 129004c9c5dSGarance A Drosehn 130004c9c5dSGarance A Drosehn /* call initialization routine, if there is one for this cmd */ 131004c9c5dSGarance A Drosehn if (initrtn != NULL) { 132004c9c5dSGarance A Drosehn generic_initerr = 0; 133004c9c5dSGarance A Drosehn (*initrtn)(argc, argv); 134004c9c5dSGarance A Drosehn if (generic_initerr) 135004c9c5dSGarance A Drosehn return; 136004c9c5dSGarance A Drosehn /* skip any initial arguments null-ified by initrtn */ 137004c9c5dSGarance A Drosehn targc = argc; 138004c9c5dSGarance A Drosehn targv = argv; 139004c9c5dSGarance A Drosehn while (--targc) { 140004c9c5dSGarance A Drosehn if (targv[1] != generic_nullarg) 141004c9c5dSGarance A Drosehn break; 142004c9c5dSGarance A Drosehn ++targv; 143004c9c5dSGarance A Drosehn } 144004c9c5dSGarance A Drosehn if (targv != argv) { 145004c9c5dSGarance A Drosehn targv[0] = argv[0]; /* copy the command-name */ 146004c9c5dSGarance A Drosehn argv = targv; 147004c9c5dSGarance A Drosehn argc = targc + 1; 148004c9c5dSGarance A Drosehn } 149004c9c5dSGarance A Drosehn } 150004c9c5dSGarance A Drosehn 1514a1a0dbeSGarrett Wollman if (argc == 2 && strcmp(argv[1], "all") == 0) { 152004c9c5dSGarance A Drosehn generic_qselect = QSEL_ALL; 153ba7a1ad7SGarance A Drosehn more = firstprinter(pp, &cmdstatus); 154ba7a1ad7SGarance A Drosehn if (cmdstatus) 1554a1a0dbeSGarrett Wollman goto looperr; 1564a1a0dbeSGarrett Wollman while (more) { 157ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 1584a1a0dbeSGarrett Wollman do { 159ba7a1ad7SGarance A Drosehn more = nextprinter(pp, &cmdstatus); 1604a1a0dbeSGarrett Wollman looperr: 161ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 1624a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 1634a1a0dbeSGarrett Wollman printf("warning: %s: unresolved " 1644a1a0dbeSGarrett Wollman "tc= reference(s) ", 1654a1a0dbeSGarrett Wollman pp->printer); 1664a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 1674a1a0dbeSGarrett Wollman break; 1684a1a0dbeSGarrett Wollman default: 1696d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 1704a1a0dbeSGarrett Wollman } 171ba7a1ad7SGarance A Drosehn } while (more && cmdstatus); 1724a1a0dbeSGarrett Wollman } 173004c9c5dSGarance A Drosehn goto wrapup; 1744a1a0dbeSGarrett Wollman } 175004c9c5dSGarance A Drosehn 176004c9c5dSGarance A Drosehn generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */ 1774a1a0dbeSGarrett Wollman while (--argc) { 1784a1a0dbeSGarrett Wollman ++argv; 179004c9c5dSGarance A Drosehn if (*argv == generic_nullarg) 180004c9c5dSGarance A Drosehn continue; 1814a1a0dbeSGarrett Wollman init_printer(pp); 182ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 183ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 1844a1a0dbeSGarrett Wollman default: 1856d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 1864a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 1874a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 1884a1a0dbeSGarrett Wollman continue; 1894a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 1904a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)\n", 1914a1a0dbeSGarrett Wollman *argv); 1924a1a0dbeSGarrett Wollman break; 1934a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 1944a1a0dbeSGarrett Wollman break; 1954a1a0dbeSGarrett Wollman } 196ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 1974a1a0dbeSGarrett Wollman } 198004c9c5dSGarance A Drosehn 199004c9c5dSGarance A Drosehn wrapup: 200004c9c5dSGarance A Drosehn if (generic_wrapup) { 201004c9c5dSGarance A Drosehn (*generic_wrapup)(cmdstatus); 202004c9c5dSGarance A Drosehn } 203004c9c5dSGarance A Drosehn 2044a1a0dbeSGarrett Wollman } 205dea673e9SRodney W. Grimes 206dea673e9SRodney W. Grimes /* 207dea673e9SRodney W. Grimes * kill an existing daemon and disable printing. 208dea673e9SRodney W. Grimes */ 209dea673e9SRodney W. Grimes void 210ba7a1ad7SGarance A Drosehn doabort(struct printer *pp) 211dea673e9SRodney W. Grimes { 2124a1a0dbeSGarrett Wollman abortpr(pp, 1); 213dea673e9SRodney W. Grimes } 214dea673e9SRodney W. Grimes 215dea673e9SRodney W. Grimes static void 216ba7a1ad7SGarance A Drosehn abortpr(struct printer *pp, int dis) 217dea673e9SRodney W. Grimes { 218dea673e9SRodney W. Grimes register FILE *fp; 219dea673e9SRodney W. Grimes struct stat stbuf; 220dea673e9SRodney W. Grimes int pid, fd; 2214a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 222dea673e9SRodney W. Grimes 2234a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 2244a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 225dea673e9SRodney W. Grimes 226dea673e9SRodney W. Grimes /* 227dea673e9SRodney W. Grimes * Turn on the owner execute bit of the lock file to disable printing. 228dea673e9SRodney W. Grimes */ 229dea673e9SRodney W. Grimes if (dis) { 230360d4ad5SWarner Losh seteuid(euid); 2314a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 2324a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 2334a1a0dbeSGarrett Wollman printf("\tcannot disable printing: %s\n", 2344a1a0dbeSGarrett Wollman strerror(errno)); 235dea673e9SRodney W. Grimes else { 2364a1a0dbeSGarrett Wollman upstat(pp, "printing disabled\n"); 237dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 238dea673e9SRodney W. Grimes } 239dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 2404a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 2414a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 2424a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 2434a1a0dbeSGarrett Wollman strerror(errno)); 244dea673e9SRodney W. Grimes else { 245dea673e9SRodney W. Grimes (void) close(fd); 2464a1a0dbeSGarrett Wollman upstat(pp, "printing disabled\n"); 247dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 248dea673e9SRodney W. Grimes printf("\tno daemon to abort\n"); 249dea673e9SRodney W. Grimes } 250360d4ad5SWarner Losh goto out; 251dea673e9SRodney W. Grimes } else { 252dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 253360d4ad5SWarner Losh goto out; 254dea673e9SRodney W. Grimes } 255dea673e9SRodney W. Grimes } 256dea673e9SRodney W. Grimes /* 257dea673e9SRodney W. Grimes * Kill the current daemon to stop printing now. 258dea673e9SRodney W. Grimes */ 2594a1a0dbeSGarrett Wollman if ((fp = fopen(lf, "r")) == NULL) { 260dea673e9SRodney W. Grimes printf("\tcannot open lock file\n"); 261360d4ad5SWarner Losh goto out; 262dea673e9SRodney W. Grimes } 263dea673e9SRodney W. Grimes if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 264dea673e9SRodney W. Grimes (void) fclose(fp); /* unlocks as well */ 265dea673e9SRodney W. Grimes printf("\tno daemon to abort\n"); 266360d4ad5SWarner Losh goto out; 267dea673e9SRodney W. Grimes } 268dea673e9SRodney W. Grimes (void) fclose(fp); 269360d4ad5SWarner Losh if (kill(pid = atoi(line), SIGTERM) < 0) { 270360d4ad5SWarner Losh if (errno == ESRCH) 271360d4ad5SWarner Losh printf("\tno daemon to abort\n"); 272dea673e9SRodney W. Grimes else 273360d4ad5SWarner Losh printf("\tWarning: daemon (pid %d) not killed\n", pid); 274360d4ad5SWarner Losh } else 275dea673e9SRodney W. Grimes printf("\tdaemon (pid %d) killed\n", pid); 276360d4ad5SWarner Losh out: 277360d4ad5SWarner Losh seteuid(uid); 278dea673e9SRodney W. Grimes } 279dea673e9SRodney W. Grimes 280dea673e9SRodney W. Grimes /* 281dea673e9SRodney W. Grimes * Write a message into the status file. 282dea673e9SRodney W. Grimes */ 283dea673e9SRodney W. Grimes static void 284ba7a1ad7SGarance A Drosehn upstat(struct printer *pp, const char *msg) 285dea673e9SRodney W. Grimes { 286dea673e9SRodney W. Grimes register int fd; 2875f87a7b6SWarner Losh char statfile[MAXPATHLEN]; 288dea673e9SRodney W. Grimes 2894a1a0dbeSGarrett Wollman status_file_name(pp, statfile, sizeof statfile); 290dea673e9SRodney W. Grimes umask(0); 2914a1a0dbeSGarrett Wollman fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 2924a1a0dbeSGarrett Wollman if (fd < 0) { 2934a1a0dbeSGarrett Wollman printf("\tcannot create status file: %s\n", strerror(errno)); 294dea673e9SRodney W. Grimes return; 295dea673e9SRodney W. Grimes } 296dea673e9SRodney W. Grimes (void) ftruncate(fd, 0); 297dea673e9SRodney W. Grimes if (msg == (char *)NULL) 298dea673e9SRodney W. Grimes (void) write(fd, "\n", 1); 299dea673e9SRodney W. Grimes else 300dea673e9SRodney W. Grimes (void) write(fd, msg, strlen(msg)); 301dea673e9SRodney W. Grimes (void) close(fd); 302dea673e9SRodney W. Grimes } 303dea673e9SRodney W. Grimes 304004c9c5dSGarance A Drosehn /* 305004c9c5dSGarance A Drosehn * "global" variables for all the routines related to 'clean' and 'tclean' 306004c9c5dSGarance A Drosehn */ 307004c9c5dSGarance A Drosehn static time_t cln_now; /* current time */ 308004c9c5dSGarance A Drosehn static double cln_minage; /* minimum age before file is removed */ 309004c9c5dSGarance A Drosehn static long cln_sizecnt; /* amount of space freed up */ 310004c9c5dSGarance A Drosehn static int cln_debug; /* print extra debugging msgs */ 311004c9c5dSGarance A Drosehn static int cln_filecnt; /* number of files destroyed */ 312004c9c5dSGarance A Drosehn static int cln_foundcore; /* found a core file! */ 313004c9c5dSGarance A Drosehn static int cln_queuecnt; /* number of queues checked */ 314004c9c5dSGarance A Drosehn static int cln_testonly; /* remove-files vs just-print-info */ 315004c9c5dSGarance A Drosehn 316dea673e9SRodney W. Grimes static int 317ba7a1ad7SGarance A Drosehn doselect(struct dirent *d) 318dea673e9SRodney W. Grimes { 319dea673e9SRodney W. Grimes int c = d->d_name[0]; 320dea673e9SRodney W. Grimes 3211fd731faSGarance A Drosehn if ((c == 'c' || c == 'd' || c == 'r' || c == 't') && 3221fd731faSGarance A Drosehn d->d_name[1] == 'f') 323004c9c5dSGarance A Drosehn return 1; 324004c9c5dSGarance A Drosehn if (c == 'c') { 325004c9c5dSGarance A Drosehn if (!strcmp(d->d_name, "core")) 326004c9c5dSGarance A Drosehn cln_foundcore = 1; 327004c9c5dSGarance A Drosehn } 328004c9c5dSGarance A Drosehn if (c == 'e') { 329004c9c5dSGarance A Drosehn if (!strncmp(d->d_name, "errs.", 5)) 330004c9c5dSGarance A Drosehn return 1; 331004c9c5dSGarance A Drosehn } 332004c9c5dSGarance A Drosehn return 0; 333dea673e9SRodney W. Grimes } 334dea673e9SRodney W. Grimes 335dea673e9SRodney W. Grimes /* 336ceeaedd3SGarance A Drosehn * Comparison routine that clean_q() uses for scandir. 337ceeaedd3SGarance A Drosehn * 338ceeaedd3SGarance A Drosehn * The purpose of this sort is to have all `df' files end up immediately 3391fd731faSGarance A Drosehn * after the matching `cf' file. For files matching `cf', `df', `rf', or 3401fd731faSGarance A Drosehn * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or 3411fd731faSGarance A Drosehn * `tf', and then by the sequence letter (which is A-Z, or a-z). This 3421fd731faSGarance A Drosehn * routine may also see filenames which do not start with `cf', `df', `rf', 3431fd731faSGarance A Drosehn * or `tf' (such as `errs.*'), and those are simply sorted by the full 3441fd731faSGarance A Drosehn * filename. 3451fd731faSGarance A Drosehn * 3461fd731faSGarance A Drosehn * XXX 3471fd731faSGarance A Drosehn * This assumes that all control files start with `cfA*', and it turns 3481fd731faSGarance A Drosehn * out there are a few implementations of lpr which will create `cfB*' 3491fd731faSGarance A Drosehn * filenames (they will have datafile names which start with `dfB*'). 350dea673e9SRodney W. Grimes */ 351dea673e9SRodney W. Grimes static int 352ba7a1ad7SGarance A Drosehn sortq(const void *a, const void *b) 353dea673e9SRodney W. Grimes { 354ceeaedd3SGarance A Drosehn const int a_lt_b = -1, a_gt_b = 1, cat_other = 10; 355ceeaedd3SGarance A Drosehn const char *fname_a, *fname_b, *jnum_a, *jnum_b; 356ceeaedd3SGarance A Drosehn int cat_a, cat_b, ch, res, seq_a, seq_b; 357dea673e9SRodney W. Grimes 358ceeaedd3SGarance A Drosehn fname_a = (*(const struct dirent **)a)->d_name; 359ceeaedd3SGarance A Drosehn fname_b = (*(const struct dirent **)b)->d_name; 360ceeaedd3SGarance A Drosehn 361ceeaedd3SGarance A Drosehn /* 362ceeaedd3SGarance A Drosehn * First separate filenames into cagatories. Catagories are 3631fd731faSGarance A Drosehn * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in 3641fd731faSGarance A Drosehn * that order. It is critical that the mapping be exactly the 3651fd731faSGarance A Drosehn * same for 'a' vs 'b', so define a macro for the job. 366ceeaedd3SGarance A Drosehn * 367ceeaedd3SGarance A Drosehn * [aside: the standard `cf' file has the jobnumber start in 368ceeaedd3SGarance A Drosehn * position 4, but some implementations have that as an extra 369ceeaedd3SGarance A Drosehn * file-sequence letter, and start the job number in position 5.] 370ceeaedd3SGarance A Drosehn */ 371ceeaedd3SGarance A Drosehn #define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \ 372ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 373ceeaedd3SGarance A Drosehn ch = *(fname_X + 2); \ 374ceeaedd3SGarance A Drosehn jnum_X = fname_X + 3; \ 3754f7f8234SGarance A Drosehn seq_X = 0; \ 376ceeaedd3SGarance A Drosehn if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \ 377ceeaedd3SGarance A Drosehn seq_X = ch; \ 378ceeaedd3SGarance A Drosehn if (*fname_X == 'c') \ 379ceeaedd3SGarance A Drosehn cat_X = 1; \ 380ceeaedd3SGarance A Drosehn else if (*fname_X == 'd') \ 381ceeaedd3SGarance A Drosehn cat_X = 2; \ 3821fd731faSGarance A Drosehn else if (*fname_X == 'r') \ 383ceeaedd3SGarance A Drosehn cat_X = 3; \ 3841fd731faSGarance A Drosehn else if (*fname_X == 't') \ 3851fd731faSGarance A Drosehn cat_X = 4; \ 386ceeaedd3SGarance A Drosehn if (cat_X != cat_other) { \ 387ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 388ceeaedd3SGarance A Drosehn if (!isdigit(ch)) { \ 389ceeaedd3SGarance A Drosehn if (isalpha(ch)) { \ 390ceeaedd3SGarance A Drosehn jnum_X++; \ 391ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 392ceeaedd3SGarance A Drosehn seq_X = (seq_X << 8) + ch; \ 393ceeaedd3SGarance A Drosehn } \ 394ceeaedd3SGarance A Drosehn if (!isdigit(ch)) \ 395ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 396ceeaedd3SGarance A Drosehn } \ 397ceeaedd3SGarance A Drosehn } \ 398ceeaedd3SGarance A Drosehn } \ 399ceeaedd3SGarance A Drosehn } while (0) 400ceeaedd3SGarance A Drosehn 401ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a); 402ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b); 403ceeaedd3SGarance A Drosehn 404ceeaedd3SGarance A Drosehn #undef MAP_TO_CAT 405ceeaedd3SGarance A Drosehn 406ceeaedd3SGarance A Drosehn /* First handle all cases which have "other" files */ 407ceeaedd3SGarance A Drosehn if ((cat_a >= cat_other) || (cat_b >= cat_other)) { 408ceeaedd3SGarance A Drosehn /* for two "other" files, just compare the full name */ 409ceeaedd3SGarance A Drosehn if (cat_a == cat_b) 410ceeaedd3SGarance A Drosehn res = strcmp(fname_a, fname_b); 411ceeaedd3SGarance A Drosehn else if (cat_a < cat_b) 412ceeaedd3SGarance A Drosehn res = a_lt_b; 413ceeaedd3SGarance A Drosehn else 414ceeaedd3SGarance A Drosehn res = a_gt_b; 415ceeaedd3SGarance A Drosehn goto have_res; 416ceeaedd3SGarance A Drosehn } 417ceeaedd3SGarance A Drosehn 418ceeaedd3SGarance A Drosehn /* 4191fd731faSGarance A Drosehn * At this point, we know both files are legitimate `cf', `df', `rf', 420ceeaedd3SGarance A Drosehn * or `tf' files. Compare them by job-number and machine name. 421ceeaedd3SGarance A Drosehn */ 422ceeaedd3SGarance A Drosehn res = strcmp(jnum_a, jnum_b); 423ceeaedd3SGarance A Drosehn if (res != 0) 424ceeaedd3SGarance A Drosehn goto have_res; 425ceeaedd3SGarance A Drosehn 426ceeaedd3SGarance A Drosehn /* 427ceeaedd3SGarance A Drosehn * We have two files which belong to the same job. Sort based 428ceeaedd3SGarance A Drosehn * on the catagory of file (`c' before `d', etc). 429ceeaedd3SGarance A Drosehn */ 430ceeaedd3SGarance A Drosehn if (cat_a < cat_b) { 431ceeaedd3SGarance A Drosehn res = a_lt_b; 432ceeaedd3SGarance A Drosehn goto have_res; 433ceeaedd3SGarance A Drosehn } else if (cat_a > cat_b) { 434ceeaedd3SGarance A Drosehn res = a_gt_b; 435ceeaedd3SGarance A Drosehn goto have_res; 436ceeaedd3SGarance A Drosehn } 437ceeaedd3SGarance A Drosehn 438ceeaedd3SGarance A Drosehn /* 439ceeaedd3SGarance A Drosehn * Two files in the same catagory for a single job. Sort based 440ceeaedd3SGarance A Drosehn * on the sequence letter(s). (usually `A' thru `Z', etc). 441ceeaedd3SGarance A Drosehn */ 442ceeaedd3SGarance A Drosehn if (seq_a < seq_b) { 443ceeaedd3SGarance A Drosehn res = a_lt_b; 444ceeaedd3SGarance A Drosehn goto have_res; 445ceeaedd3SGarance A Drosehn } else if (seq_a > seq_b) { 446ceeaedd3SGarance A Drosehn res = a_gt_b; 447ceeaedd3SGarance A Drosehn goto have_res; 448ceeaedd3SGarance A Drosehn } 449ceeaedd3SGarance A Drosehn 450ceeaedd3SGarance A Drosehn /* 451ceeaedd3SGarance A Drosehn * Given that the filenames in a directory are unique, this SHOULD 452ceeaedd3SGarance A Drosehn * never happen (unless there are logic errors in this routine). 453ceeaedd3SGarance A Drosehn * But if it does happen, we must return "is equal" or the caller 454ceeaedd3SGarance A Drosehn * might see inconsistent results in the sorting order, and that 455ceeaedd3SGarance A Drosehn * can trigger other problems. 456ceeaedd3SGarance A Drosehn */ 457ceeaedd3SGarance A Drosehn printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b); 458ceeaedd3SGarance A Drosehn printf("\t*** cat %d == %d ; seq = %d %d\n", cat_a, cat_b, 459ceeaedd3SGarance A Drosehn seq_a, seq_b); 460ceeaedd3SGarance A Drosehn res = 0; 461ceeaedd3SGarance A Drosehn 462ceeaedd3SGarance A Drosehn have_res: 463ceeaedd3SGarance A Drosehn return res; 464dea673e9SRodney W. Grimes } 465dea673e9SRodney W. Grimes 466dea673e9SRodney W. Grimes /* 4674a1a0dbeSGarrett Wollman * Remove all spool files and temporaries from the spooling area. 4684a1a0dbeSGarrett Wollman * Or, perhaps: 469dea673e9SRodney W. Grimes * Remove incomplete jobs from spooling area. 470dea673e9SRodney W. Grimes */ 471dea673e9SRodney W. Grimes 472004c9c5dSGarance A Drosehn void 473004c9c5dSGarance A Drosehn init_clean(int argc, char *argv[]) 474004c9c5dSGarance A Drosehn { 475004c9c5dSGarance A Drosehn 476004c9c5dSGarance A Drosehn /* init some fields before 'clean' is called for each queue */ 477004c9c5dSGarance A Drosehn cln_queuecnt = 0; 478004c9c5dSGarance A Drosehn cln_now = time(NULL); 479004c9c5dSGarance A Drosehn cln_minage = 3600.0; /* only delete files >1h old */ 480004c9c5dSGarance A Drosehn cln_filecnt = 0; 481004c9c5dSGarance A Drosehn cln_sizecnt = 0; 482004c9c5dSGarance A Drosehn cln_debug = 0; 483004c9c5dSGarance A Drosehn cln_testonly = 0; 484004c9c5dSGarance A Drosehn generic_wrapup = &wrapup_clean; 485004c9c5dSGarance A Drosehn 486004c9c5dSGarance A Drosehn /* see if there are any options specified before the ptr list */ 487004c9c5dSGarance A Drosehn while (--argc) { 488004c9c5dSGarance A Drosehn ++argv; 489004c9c5dSGarance A Drosehn if (**argv != '-') 490004c9c5dSGarance A Drosehn break; 491004c9c5dSGarance A Drosehn if (strcmp(*argv, "-d") == 0) { 492004c9c5dSGarance A Drosehn /* just an example of an option... */ 493ceeaedd3SGarance A Drosehn cln_debug++; 494004c9c5dSGarance A Drosehn *argv = generic_nullarg; /* "erase" it */ 495004c9c5dSGarance A Drosehn } else { 496004c9c5dSGarance A Drosehn printf("Invalid option '%s'\n", *argv); 497004c9c5dSGarance A Drosehn generic_initerr = 1; 498004c9c5dSGarance A Drosehn } 499004c9c5dSGarance A Drosehn } 500004c9c5dSGarance A Drosehn 501004c9c5dSGarance A Drosehn return; 502004c9c5dSGarance A Drosehn } 503004c9c5dSGarance A Drosehn 504004c9c5dSGarance A Drosehn void 505004c9c5dSGarance A Drosehn init_tclean(int argc, char *argv[]) 506004c9c5dSGarance A Drosehn { 507004c9c5dSGarance A Drosehn 508004c9c5dSGarance A Drosehn /* only difference between 'clean' and 'tclean' is one value */ 509004c9c5dSGarance A Drosehn /* (...and the fact that 'clean' is priv and 'tclean' is not) */ 510004c9c5dSGarance A Drosehn init_clean(argc, argv); 511004c9c5dSGarance A Drosehn cln_testonly = 1; 512004c9c5dSGarance A Drosehn 513004c9c5dSGarance A Drosehn return; 514004c9c5dSGarance A Drosehn } 515004c9c5dSGarance A Drosehn 516004c9c5dSGarance A Drosehn void 517004c9c5dSGarance A Drosehn clean_q(struct printer *pp) 518004c9c5dSGarance A Drosehn { 519004c9c5dSGarance A Drosehn char *cp, *cp1, *lp; 520004c9c5dSGarance A Drosehn struct dirent **queue; 521004c9c5dSGarance A Drosehn size_t linerem; 522004c9c5dSGarance A Drosehn int didhead, i, n, nitems, rmcp; 523004c9c5dSGarance A Drosehn 524004c9c5dSGarance A Drosehn cln_queuecnt++; 525004c9c5dSGarance A Drosehn 526004c9c5dSGarance A Drosehn didhead = 0; 527004c9c5dSGarance A Drosehn if (generic_qselect == QSEL_BYNAME) { 5284a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 529004c9c5dSGarance A Drosehn didhead = 1; 530004c9c5dSGarance A Drosehn } 531dea673e9SRodney W. Grimes 5324a1a0dbeSGarrett Wollman lp = line; 5334a1a0dbeSGarrett Wollman cp = pp->spool_dir; 5344a1a0dbeSGarrett Wollman while (lp < &line[sizeof(line) - 1]) { 5354a1a0dbeSGarrett Wollman if ((*lp++ = *cp++) == 0) 5364a1a0dbeSGarrett Wollman break; 5374a1a0dbeSGarrett Wollman } 538dea673e9SRodney W. Grimes lp[-1] = '/'; 539004c9c5dSGarance A Drosehn linerem = sizeof(line) - (lp - line); 540dea673e9SRodney W. Grimes 541004c9c5dSGarance A Drosehn cln_foundcore = 0; 542360d4ad5SWarner Losh seteuid(euid); 5434a1a0dbeSGarrett Wollman nitems = scandir(pp->spool_dir, &queue, doselect, sortq); 544360d4ad5SWarner Losh seteuid(uid); 545dea673e9SRodney W. Grimes if (nitems < 0) { 546004c9c5dSGarance A Drosehn if (!didhead) { 547004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 548004c9c5dSGarance A Drosehn didhead = 1; 549004c9c5dSGarance A Drosehn } 550dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 551dea673e9SRodney W. Grimes return; 552dea673e9SRodney W. Grimes } 553004c9c5dSGarance A Drosehn if (cln_foundcore) { 554004c9c5dSGarance A Drosehn if (!didhead) { 555004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 556004c9c5dSGarance A Drosehn didhead = 1; 557004c9c5dSGarance A Drosehn } 558004c9c5dSGarance A Drosehn printf("\t** found a core file in %s !\n", pp->spool_dir); 559004c9c5dSGarance A Drosehn } 560dea673e9SRodney W. Grimes if (nitems == 0) 561dea673e9SRodney W. Grimes return; 562004c9c5dSGarance A Drosehn if (!didhead) 563004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 564ceeaedd3SGarance A Drosehn if (cln_debug) { 565ceeaedd3SGarance A Drosehn printf("\t** ----- Sorted list of files being checked:\n"); 566ceeaedd3SGarance A Drosehn i = 0; 567ceeaedd3SGarance A Drosehn do { 568ceeaedd3SGarance A Drosehn cp = queue[i]->d_name; 569ceeaedd3SGarance A Drosehn printf("\t** [%3d] = %s\n", i, cp); 570ceeaedd3SGarance A Drosehn } while (++i < nitems); 571ceeaedd3SGarance A Drosehn printf("\t** ----- end of sorted list\n"); 572ceeaedd3SGarance A Drosehn } 573dea673e9SRodney W. Grimes i = 0; 574dea673e9SRodney W. Grimes do { 575dea673e9SRodney W. Grimes cp = queue[i]->d_name; 576004c9c5dSGarance A Drosehn rmcp = 0; 577dea673e9SRodney W. Grimes if (*cp == 'c') { 578004c9c5dSGarance A Drosehn /* 579004c9c5dSGarance A Drosehn * A control file. Look for matching data-files. 580004c9c5dSGarance A Drosehn */ 581004c9c5dSGarance A Drosehn /* XXX 582004c9c5dSGarance A Drosehn * Note the logic here assumes that the hostname 583004c9c5dSGarance A Drosehn * part of cf-filenames match the hostname part 584004c9c5dSGarance A Drosehn * in df-filenames, and that is not necessarily 585004c9c5dSGarance A Drosehn * true (eg: for multi-homed hosts). This needs 586004c9c5dSGarance A Drosehn * some further thought... 587004c9c5dSGarance A Drosehn */ 588dea673e9SRodney W. Grimes n = 0; 589dea673e9SRodney W. Grimes while (i + 1 < nitems) { 590dea673e9SRodney W. Grimes cp1 = queue[i + 1]->d_name; 591dea673e9SRodney W. Grimes if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 592dea673e9SRodney W. Grimes break; 593dea673e9SRodney W. Grimes i++; 594dea673e9SRodney W. Grimes n++; 595dea673e9SRodney W. Grimes } 596dea673e9SRodney W. Grimes if (n == 0) { 597004c9c5dSGarance A Drosehn rmcp = 1; 598dea673e9SRodney W. Grimes } 599004c9c5dSGarance A Drosehn } else if (*cp == 'e') { 600004c9c5dSGarance A Drosehn /* 601004c9c5dSGarance A Drosehn * Must be an errrs or email temp file. 602004c9c5dSGarance A Drosehn */ 603004c9c5dSGarance A Drosehn rmcp = 1; 604dea673e9SRodney W. Grimes } else { 605dea673e9SRodney W. Grimes /* 606dea673e9SRodney W. Grimes * Must be a df with no cf (otherwise, it would have 6071fd731faSGarance A Drosehn * been skipped above) or an rf or tf file (which can 6081fd731faSGarance A Drosehn * always be removed if it is old enough). 609dea673e9SRodney W. Grimes */ 610004c9c5dSGarance A Drosehn rmcp = 1; 611004c9c5dSGarance A Drosehn } 612004c9c5dSGarance A Drosehn if (rmcp) { 613004c9c5dSGarance A Drosehn if (strlen(cp) >= linerem) { 614004c9c5dSGarance A Drosehn printf("\t** internal error: 'line' overflow!\n"); 615004c9c5dSGarance A Drosehn printf("\t** spooldir = %s\n", pp->spool_dir); 616004c9c5dSGarance A Drosehn printf("\t** cp = %s\n", cp); 617004c9c5dSGarance A Drosehn return; 618004c9c5dSGarance A Drosehn } 619004c9c5dSGarance A Drosehn strlcpy(lp, cp, linerem); 620dea673e9SRodney W. Grimes unlinkf(line); 621dea673e9SRodney W. Grimes } 622dea673e9SRodney W. Grimes } while (++i < nitems); 623dea673e9SRodney W. Grimes } 624dea673e9SRodney W. Grimes 625dea673e9SRodney W. Grimes static void 626004c9c5dSGarance A Drosehn wrapup_clean(int laststatus __unused) 627004c9c5dSGarance A Drosehn { 628004c9c5dSGarance A Drosehn 629004c9c5dSGarance A Drosehn printf("Checked %d queues, and ", cln_queuecnt); 630004c9c5dSGarance A Drosehn if (cln_filecnt < 1) { 631004c9c5dSGarance A Drosehn printf("no cruft was found\n"); 632004c9c5dSGarance A Drosehn return; 633004c9c5dSGarance A Drosehn } 634004c9c5dSGarance A Drosehn if (cln_testonly) { 635004c9c5dSGarance A Drosehn printf("would have "); 636004c9c5dSGarance A Drosehn } 637004c9c5dSGarance A Drosehn printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt); 638004c9c5dSGarance A Drosehn } 639004c9c5dSGarance A Drosehn 640004c9c5dSGarance A Drosehn static void 641ba7a1ad7SGarance A Drosehn unlinkf(char *name) 642dea673e9SRodney W. Grimes { 643004c9c5dSGarance A Drosehn struct stat stbuf; 644004c9c5dSGarance A Drosehn double agemod, agestat; 645004c9c5dSGarance A Drosehn int res; 646004c9c5dSGarance A Drosehn char linkbuf[BUFSIZ]; 647004c9c5dSGarance A Drosehn 648004c9c5dSGarance A Drosehn /* 649004c9c5dSGarance A Drosehn * We have to use lstat() instead of stat(), in case this is a df* 650004c9c5dSGarance A Drosehn * "file" which is really a symlink due to 'lpr -s' processing. In 651004c9c5dSGarance A Drosehn * that case, we need to check the last-mod time of the symlink, and 652004c9c5dSGarance A Drosehn * not the file that the symlink is pointed at. 653004c9c5dSGarance A Drosehn */ 654360d4ad5SWarner Losh seteuid(euid); 655004c9c5dSGarance A Drosehn res = lstat(name, &stbuf); 656004c9c5dSGarance A Drosehn seteuid(uid); 657004c9c5dSGarance A Drosehn if (res < 0) { 658004c9c5dSGarance A Drosehn printf("\terror return from stat(%s):\n", name); 659004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 660004c9c5dSGarance A Drosehn return; 661004c9c5dSGarance A Drosehn } 662004c9c5dSGarance A Drosehn 663004c9c5dSGarance A Drosehn agemod = difftime(cln_now, stbuf.st_mtime); 664004c9c5dSGarance A Drosehn agestat = difftime(cln_now, stbuf.st_ctime); 665ceeaedd3SGarance A Drosehn if (cln_debug > 1) { 666004c9c5dSGarance A Drosehn /* this debugging-aid probably is not needed any more... */ 667004c9c5dSGarance A Drosehn printf("\t\t modify age=%g secs, stat age=%g secs\n", 668004c9c5dSGarance A Drosehn agemod, agestat); 669004c9c5dSGarance A Drosehn } 670004c9c5dSGarance A Drosehn if ((agemod <= cln_minage) && (agestat <= cln_minage)) 671004c9c5dSGarance A Drosehn return; 672004c9c5dSGarance A Drosehn 673004c9c5dSGarance A Drosehn /* 674004c9c5dSGarance A Drosehn * if this file is a symlink, then find out the target of the 675004c9c5dSGarance A Drosehn * symlink before unlink-ing the file itself 676004c9c5dSGarance A Drosehn */ 677004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 678004c9c5dSGarance A Drosehn seteuid(euid); 679004c9c5dSGarance A Drosehn res = readlink(name, linkbuf, sizeof(linkbuf)); 680004c9c5dSGarance A Drosehn seteuid(uid); 681004c9c5dSGarance A Drosehn if (res < 0) { 682004c9c5dSGarance A Drosehn printf("\terror return from readlink(%s):\n", name); 683004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 684004c9c5dSGarance A Drosehn return; 685004c9c5dSGarance A Drosehn } 686004c9c5dSGarance A Drosehn if (res == sizeof(linkbuf)) 687004c9c5dSGarance A Drosehn res--; 688004c9c5dSGarance A Drosehn linkbuf[res] = '\0'; 689004c9c5dSGarance A Drosehn } 690004c9c5dSGarance A Drosehn 691004c9c5dSGarance A Drosehn cln_filecnt++; 692004c9c5dSGarance A Drosehn cln_sizecnt += stbuf.st_size; 693004c9c5dSGarance A Drosehn 694004c9c5dSGarance A Drosehn if (cln_testonly) { 695004c9c5dSGarance A Drosehn printf("\twould remove %s\n", name); 696004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 697004c9c5dSGarance A Drosehn printf("\t (which is a symlink to %s)\n", linkbuf); 698004c9c5dSGarance A Drosehn } 699004c9c5dSGarance A Drosehn } else { 700004c9c5dSGarance A Drosehn seteuid(euid); 701004c9c5dSGarance A Drosehn res = unlink(name); 702004c9c5dSGarance A Drosehn seteuid(uid); 703004c9c5dSGarance A Drosehn if (res < 0) 704004c9c5dSGarance A Drosehn printf("\tcannot remove %s (!)\n", name); 705dea673e9SRodney W. Grimes else 706dea673e9SRodney W. Grimes printf("\tremoved %s\n", name); 707004c9c5dSGarance A Drosehn /* XXX 708004c9c5dSGarance A Drosehn * Note that for a df* file, this code should also check to see 709004c9c5dSGarance A Drosehn * if it is a symlink to some other file, and if the original 710004c9c5dSGarance A Drosehn * lpr command included '-r' ("remove file"). Of course, this 711004c9c5dSGarance A Drosehn * code would not be removing the df* file unless there was no 712004c9c5dSGarance A Drosehn * matching cf* file, and without the cf* file it is currently 713004c9c5dSGarance A Drosehn * impossible to determine if '-r' had been specified... 714004c9c5dSGarance A Drosehn * 715004c9c5dSGarance A Drosehn * As a result of this quandry, we may be leaving behind a 716004c9c5dSGarance A Drosehn * user's file that was supposed to have been removed after 717004c9c5dSGarance A Drosehn * being printed. This may effect services such as CAP or 718004c9c5dSGarance A Drosehn * samba, if they were configured to use 'lpr -r', and if 719004c9c5dSGarance A Drosehn * datafiles are not being properly removed. 720004c9c5dSGarance A Drosehn */ 721004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 722004c9c5dSGarance A Drosehn printf("\t (which was a symlink to %s)\n", linkbuf); 723004c9c5dSGarance A Drosehn } 724004c9c5dSGarance A Drosehn } 725dea673e9SRodney W. Grimes } 726dea673e9SRodney W. Grimes 727dea673e9SRodney W. Grimes /* 728dea673e9SRodney W. Grimes * Enable queuing to the printer (allow lpr's). 729dea673e9SRodney W. Grimes */ 730dea673e9SRodney W. Grimes void 731ba7a1ad7SGarance A Drosehn enable(struct printer *pp) 732dea673e9SRodney W. Grimes { 733dea673e9SRodney W. Grimes struct stat stbuf; 7344a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 735dea673e9SRodney W. Grimes 7364a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 7374a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 738dea673e9SRodney W. Grimes 739dea673e9SRodney W. Grimes /* 740dea673e9SRodney W. Grimes * Turn off the group execute bit of the lock file to enable queuing. 741dea673e9SRodney W. Grimes */ 742360d4ad5SWarner Losh seteuid(euid); 7434a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 7444a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0) 745dea673e9SRodney W. Grimes printf("\tcannot enable queuing\n"); 746dea673e9SRodney W. Grimes else 747dea673e9SRodney W. Grimes printf("\tqueuing enabled\n"); 748dea673e9SRodney W. Grimes } 749360d4ad5SWarner Losh seteuid(uid); 750dea673e9SRodney W. Grimes } 751dea673e9SRodney W. Grimes 752dea673e9SRodney W. Grimes /* 753dea673e9SRodney W. Grimes * Disable queuing. 754dea673e9SRodney W. Grimes */ 755dea673e9SRodney W. Grimes void 756ba7a1ad7SGarance A Drosehn disable(struct printer *pp) 757dea673e9SRodney W. Grimes { 758dea673e9SRodney W. Grimes register int fd; 759dea673e9SRodney W. Grimes struct stat stbuf; 7604a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 761dea673e9SRodney W. Grimes 7624a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 7634a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 764dea673e9SRodney W. Grimes /* 765dea673e9SRodney W. Grimes * Turn on the group execute bit of the lock file to disable queuing. 766dea673e9SRodney W. Grimes */ 767360d4ad5SWarner Losh seteuid(euid); 7684a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 7694a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0) 7704a1a0dbeSGarrett Wollman printf("\tcannot disable queuing: %s\n", 7714a1a0dbeSGarrett Wollman strerror(errno)); 772dea673e9SRodney W. Grimes else 773dea673e9SRodney W. Grimes printf("\tqueuing disabled\n"); 774dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 7754a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 7764a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0) 7774a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 7784a1a0dbeSGarrett Wollman strerror(errno)); 779dea673e9SRodney W. Grimes else { 780dea673e9SRodney W. Grimes (void) close(fd); 781dea673e9SRodney W. Grimes printf("\tqueuing disabled\n"); 782dea673e9SRodney W. Grimes } 783dea673e9SRodney W. Grimes } else 784dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 785360d4ad5SWarner Losh seteuid(uid); 786dea673e9SRodney W. Grimes } 787dea673e9SRodney W. Grimes 788dea673e9SRodney W. Grimes /* 789dea673e9SRodney W. Grimes * Disable queuing and printing and put a message into the status file 790dea673e9SRodney W. Grimes * (reason for being down). 791dea673e9SRodney W. Grimes */ 792dea673e9SRodney W. Grimes void 793ba7a1ad7SGarance A Drosehn down(int argc, char *argv[]) 794dea673e9SRodney W. Grimes { 795ba7a1ad7SGarance A Drosehn int cmdstatus, more; 7964a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 797dea673e9SRodney W. Grimes 798dea673e9SRodney W. Grimes if (argc == 1) { 799d3974088SDag-Erling Smørgrav printf("usage: down {all | printer} [message ...]\n"); 800dea673e9SRodney W. Grimes return; 801dea673e9SRodney W. Grimes } 802dea673e9SRodney W. Grimes if (!strcmp(argv[1], "all")) { 803ba7a1ad7SGarance A Drosehn more = firstprinter(pp, &cmdstatus); 804ba7a1ad7SGarance A Drosehn if (cmdstatus) 8054a1a0dbeSGarrett Wollman goto looperr; 8064a1a0dbeSGarrett Wollman while (more) { 8074a1a0dbeSGarrett Wollman putmsg(pp, argc - 2, argv + 2); 8084a1a0dbeSGarrett Wollman do { 809ba7a1ad7SGarance A Drosehn more = nextprinter(pp, &cmdstatus); 8104a1a0dbeSGarrett Wollman looperr: 811ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 8124a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 8134a1a0dbeSGarrett Wollman printf("warning: %s: unresolved " 8144a1a0dbeSGarrett Wollman "tc= reference(s) ", 8154a1a0dbeSGarrett Wollman pp->printer); 8164a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 8174a1a0dbeSGarrett Wollman break; 8184a1a0dbeSGarrett Wollman default: 8196d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 8204a1a0dbeSGarrett Wollman } 821ba7a1ad7SGarance A Drosehn } while (more && cmdstatus); 822dea673e9SRodney W. Grimes } 823dea673e9SRodney W. Grimes return; 824dea673e9SRodney W. Grimes } 8254a1a0dbeSGarrett Wollman init_printer(pp); 826ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(argv[1], pp); 827ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 8284a1a0dbeSGarrett Wollman default: 8296d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 8304a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 8314a1a0dbeSGarrett Wollman printf("unknown printer %s\n", argv[1]); 832dea673e9SRodney W. Grimes return; 8334a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 8344a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)", argv[1]); 8354a1a0dbeSGarrett Wollman break; 8364a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 8374a1a0dbeSGarrett Wollman break; 8384a1a0dbeSGarrett Wollman } 8394a1a0dbeSGarrett Wollman putmsg(pp, argc - 2, argv + 2); 840dea673e9SRodney W. Grimes } 841dea673e9SRodney W. Grimes 842dea673e9SRodney W. Grimes static void 843ba7a1ad7SGarance A Drosehn putmsg(struct printer *pp, int argc, char **argv) 844dea673e9SRodney W. Grimes { 845dea673e9SRodney W. Grimes register int fd; 846dea673e9SRodney W. Grimes register char *cp1, *cp2; 847dea673e9SRodney W. Grimes char buf[1024]; 8484a1a0dbeSGarrett Wollman char file[MAXPATHLEN]; 849dea673e9SRodney W. Grimes struct stat stbuf; 850dea673e9SRodney W. Grimes 8514a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 852dea673e9SRodney W. Grimes /* 8534a1a0dbeSGarrett Wollman * Turn on the group execute bit of the lock file to disable queuing; 854dea673e9SRodney W. Grimes * turn on the owner execute bit of the lock file to disable printing. 855dea673e9SRodney W. Grimes */ 8564a1a0dbeSGarrett Wollman lock_file_name(pp, file, sizeof file); 857360d4ad5SWarner Losh seteuid(euid); 8584a1a0dbeSGarrett Wollman if (stat(file, &stbuf) >= 0) { 8594a1a0dbeSGarrett Wollman if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0) 8604a1a0dbeSGarrett Wollman printf("\tcannot disable queuing: %s\n", 8614a1a0dbeSGarrett Wollman strerror(errno)); 862dea673e9SRodney W. Grimes else 863dea673e9SRodney W. Grimes printf("\tprinter and queuing disabled\n"); 864dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 8654a1a0dbeSGarrett Wollman if ((fd = open(file, O_WRONLY|O_CREAT, 8664a1a0dbeSGarrett Wollman LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0) 8674a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 8684a1a0dbeSGarrett Wollman strerror(errno)); 869dea673e9SRodney W. Grimes else { 870dea673e9SRodney W. Grimes (void) close(fd); 871dea673e9SRodney W. Grimes printf("\tprinter and queuing disabled\n"); 872dea673e9SRodney W. Grimes } 873360d4ad5SWarner Losh seteuid(uid); 874dea673e9SRodney W. Grimes return; 875dea673e9SRodney W. Grimes } else 876dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 877dea673e9SRodney W. Grimes /* 878dea673e9SRodney W. Grimes * Write the message into the status file. 879dea673e9SRodney W. Grimes */ 8804a1a0dbeSGarrett Wollman status_file_name(pp, file, sizeof file); 8814a1a0dbeSGarrett Wollman fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 8824a1a0dbeSGarrett Wollman if (fd < 0) { 8834a1a0dbeSGarrett Wollman printf("\tcannot create status file: %s\n", strerror(errno)); 884360d4ad5SWarner Losh seteuid(uid); 885dea673e9SRodney W. Grimes return; 886dea673e9SRodney W. Grimes } 887360d4ad5SWarner Losh seteuid(uid); 888dea673e9SRodney W. Grimes (void) ftruncate(fd, 0); 889dea673e9SRodney W. Grimes if (argc <= 0) { 890dea673e9SRodney W. Grimes (void) write(fd, "\n", 1); 891dea673e9SRodney W. Grimes (void) close(fd); 892dea673e9SRodney W. Grimes return; 893dea673e9SRodney W. Grimes } 894dea673e9SRodney W. Grimes cp1 = buf; 895dea673e9SRodney W. Grimes while (--argc >= 0) { 896dea673e9SRodney W. Grimes cp2 = *argv++; 89779c96a6cSGarance A Drosehn while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 898dea673e9SRodney W. Grimes ; 899dea673e9SRodney W. Grimes cp1[-1] = ' '; 900dea673e9SRodney W. Grimes } 901dea673e9SRodney W. Grimes cp1[-1] = '\n'; 902dea673e9SRodney W. Grimes *cp1 = '\0'; 903dea673e9SRodney W. Grimes (void) write(fd, buf, strlen(buf)); 904dea673e9SRodney W. Grimes (void) close(fd); 905dea673e9SRodney W. Grimes } 906dea673e9SRodney W. Grimes 907dea673e9SRodney W. Grimes /* 908dea673e9SRodney W. Grimes * Exit lpc 909dea673e9SRodney W. Grimes */ 910dea673e9SRodney W. Grimes void 911ba7a1ad7SGarance A Drosehn quit(int argc __unused, char *argv[] __unused) 912dea673e9SRodney W. Grimes { 913dea673e9SRodney W. Grimes exit(0); 914dea673e9SRodney W. Grimes } 915dea673e9SRodney W. Grimes 916dea673e9SRodney W. Grimes /* 917dea673e9SRodney W. Grimes * Kill and restart the daemon. 918dea673e9SRodney W. Grimes */ 919dea673e9SRodney W. Grimes void 920ba7a1ad7SGarance A Drosehn restart(struct printer *pp) 921dea673e9SRodney W. Grimes { 9224a1a0dbeSGarrett Wollman abortpr(pp, 0); 9234a1a0dbeSGarrett Wollman startpr(pp, 0); 924dea673e9SRodney W. Grimes } 925dea673e9SRodney W. Grimes 926dea673e9SRodney W. Grimes /* 927dea673e9SRodney W. Grimes * Enable printing on the specified printer and startup the daemon. 928dea673e9SRodney W. Grimes */ 929dea673e9SRodney W. Grimes void 930ba7a1ad7SGarance A Drosehn startcmd(struct printer *pp) 931dea673e9SRodney W. Grimes { 9324a1a0dbeSGarrett Wollman startpr(pp, 1); 933dea673e9SRodney W. Grimes } 934dea673e9SRodney W. Grimes 935dea673e9SRodney W. Grimes static void 936ba7a1ad7SGarance A Drosehn startpr(struct printer *pp, int chgenable) 937dea673e9SRodney W. Grimes { 938dea673e9SRodney W. Grimes struct stat stbuf; 9394a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 940dea673e9SRodney W. Grimes 9414a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 9424a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 943dea673e9SRodney W. Grimes 944dea673e9SRodney W. Grimes /* 945ba7a1ad7SGarance A Drosehn * For chgenable==1 ('start'), turn off the LFM_PRINT_DIS bit of the 946ba7a1ad7SGarance A Drosehn * lock file to re-enable printing. For chgenable==2 ('up'), also 9471bd87e1bSMatthew Dillon * turn off the LFM_QUEUE_DIS bit to re-enable queueing. 948dea673e9SRodney W. Grimes */ 949360d4ad5SWarner Losh seteuid(euid); 950ba7a1ad7SGarance A Drosehn if (chgenable && stat(lf, &stbuf) >= 0) { 951ba7a1ad7SGarance A Drosehn mode_t bits = (chgenable == 2 ? 0 : LFM_QUEUE_DIS); 9524a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) 953dea673e9SRodney W. Grimes printf("\tcannot enable printing\n"); 954dea673e9SRodney W. Grimes else 955dea673e9SRodney W. Grimes printf("\tprinting enabled\n"); 956dea673e9SRodney W. Grimes } 9574a1a0dbeSGarrett Wollman if (!startdaemon(pp)) 958dea673e9SRodney W. Grimes printf("\tcouldn't start daemon\n"); 959dea673e9SRodney W. Grimes else 960dea673e9SRodney W. Grimes printf("\tdaemon started\n"); 961360d4ad5SWarner Losh seteuid(uid); 962dea673e9SRodney W. Grimes } 963dea673e9SRodney W. Grimes 964dea673e9SRodney W. Grimes /* 965dea673e9SRodney W. Grimes * Print the status of the printer queue. 966dea673e9SRodney W. Grimes */ 9674a1a0dbeSGarrett Wollman void 968ba7a1ad7SGarance A Drosehn status(struct printer *pp) 969dea673e9SRodney W. Grimes { 970dea673e9SRodney W. Grimes struct stat stbuf; 971dea673e9SRodney W. Grimes register int fd, i; 972dea673e9SRodney W. Grimes register struct dirent *dp; 973dea673e9SRodney W. Grimes DIR *dirp; 9744a1a0dbeSGarrett Wollman char file[MAXPATHLEN]; 975dea673e9SRodney W. Grimes 9764a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 9774a1a0dbeSGarrett Wollman lock_file_name(pp, file, sizeof file); 9784a1a0dbeSGarrett Wollman if (stat(file, &stbuf) >= 0) { 979dea673e9SRodney W. Grimes printf("\tqueuing is %s\n", 9804a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 9814a1a0dbeSGarrett Wollman : "enabled")); 982dea673e9SRodney W. Grimes printf("\tprinting is %s\n", 9834a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 9844a1a0dbeSGarrett Wollman : "enabled")); 985dea673e9SRodney W. Grimes } else { 986dea673e9SRodney W. Grimes printf("\tqueuing is enabled\n"); 987dea673e9SRodney W. Grimes printf("\tprinting is enabled\n"); 988dea673e9SRodney W. Grimes } 9894a1a0dbeSGarrett Wollman if ((dirp = opendir(pp->spool_dir)) == NULL) { 990dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 991dea673e9SRodney W. Grimes return; 992dea673e9SRodney W. Grimes } 993dea673e9SRodney W. Grimes i = 0; 994dea673e9SRodney W. Grimes while ((dp = readdir(dirp)) != NULL) { 995dea673e9SRodney W. Grimes if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 996dea673e9SRodney W. Grimes i++; 997dea673e9SRodney W. Grimes } 998dea673e9SRodney W. Grimes closedir(dirp); 999dea673e9SRodney W. Grimes if (i == 0) 10004a1a0dbeSGarrett Wollman printf("\tno entries in spool area\n"); 1001dea673e9SRodney W. Grimes else if (i == 1) 1002dea673e9SRodney W. Grimes printf("\t1 entry in spool area\n"); 1003dea673e9SRodney W. Grimes else 1004dea673e9SRodney W. Grimes printf("\t%d entries in spool area\n", i); 10054a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY); 1006dea673e9SRodney W. Grimes if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 1007dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1008bc407914SWarner Losh printf("\tprinter idle\n"); 1009dea673e9SRodney W. Grimes return; 1010dea673e9SRodney W. Grimes } 1011dea673e9SRodney W. Grimes (void) close(fd); 101236abea5dSBrian Somers /* print out the contents of the status file, if it exists */ 10134a1a0dbeSGarrett Wollman status_file_name(pp, file, sizeof file); 10144a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY|O_SHLOCK); 1015dea673e9SRodney W. Grimes if (fd >= 0) { 101636abea5dSBrian Somers (void) fstat(fd, &stbuf); 101736abea5dSBrian Somers if (stbuf.st_size > 0) { 101836abea5dSBrian Somers putchar('\t'); 1019dea673e9SRodney W. Grimes while ((i = read(fd, line, sizeof(line))) > 0) 1020dea673e9SRodney W. Grimes (void) fwrite(line, 1, i, stdout); 102136abea5dSBrian Somers } 1022dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1023dea673e9SRodney W. Grimes } 1024dea673e9SRodney W. Grimes } 1025dea673e9SRodney W. Grimes 1026dea673e9SRodney W. Grimes /* 1027dea673e9SRodney W. Grimes * Stop the specified daemon after completing the current job and disable 1028dea673e9SRodney W. Grimes * printing. 1029dea673e9SRodney W. Grimes */ 1030dea673e9SRodney W. Grimes void 1031ba7a1ad7SGarance A Drosehn stop(struct printer *pp) 1032dea673e9SRodney W. Grimes { 1033dea673e9SRodney W. Grimes register int fd; 1034dea673e9SRodney W. Grimes struct stat stbuf; 10354a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 1036dea673e9SRodney W. Grimes 10374a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 10384a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1039dea673e9SRodney W. Grimes 1040dea673e9SRodney W. Grimes /* 1041dea673e9SRodney W. Grimes * Turn on the owner execute bit of the lock file to disable printing. 1042dea673e9SRodney W. Grimes */ 1043360d4ad5SWarner Losh seteuid(euid); 10444a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 10454a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 10464a1a0dbeSGarrett Wollman printf("\tcannot disable printing: %s\n", 10474a1a0dbeSGarrett Wollman strerror(errno)); 1048dea673e9SRodney W. Grimes else { 10494a1a0dbeSGarrett Wollman upstat(pp, "printing disabled\n"); 1050dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 1051dea673e9SRodney W. Grimes } 1052dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 10534a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 10544a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 10554a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 10564a1a0dbeSGarrett Wollman strerror(errno)); 1057dea673e9SRodney W. Grimes else { 1058dea673e9SRodney W. Grimes (void) close(fd); 10594a1a0dbeSGarrett Wollman upstat(pp, "printing disabled\n"); 1060dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 1061dea673e9SRodney W. Grimes } 1062dea673e9SRodney W. Grimes } else 1063dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 1064360d4ad5SWarner Losh seteuid(uid); 1065dea673e9SRodney W. Grimes } 1066dea673e9SRodney W. Grimes 106730b4b758SGarance A Drosehn struct jobqueue **queue; 1068dea673e9SRodney W. Grimes int nitems; 1069dea673e9SRodney W. Grimes time_t mtime; 1070dea673e9SRodney W. Grimes 1071dea673e9SRodney W. Grimes /* 1072dea673e9SRodney W. Grimes * Put the specified jobs at the top of printer queue. 1073dea673e9SRodney W. Grimes */ 1074dea673e9SRodney W. Grimes void 1075ba7a1ad7SGarance A Drosehn topq(int argc, char *argv[]) 1076dea673e9SRodney W. Grimes { 1077dea673e9SRodney W. Grimes register int i; 1078dea673e9SRodney W. Grimes struct stat stbuf; 1079ba7a1ad7SGarance A Drosehn int cmdstatus, changed; 10804a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 1081dea673e9SRodney W. Grimes 1082dea673e9SRodney W. Grimes if (argc < 3) { 1083d3974088SDag-Erling Smørgrav printf("usage: topq printer [jobnum ...] [user ...]\n"); 1084dea673e9SRodney W. Grimes return; 1085dea673e9SRodney W. Grimes } 1086dea673e9SRodney W. Grimes 1087dea673e9SRodney W. Grimes --argc; 10884a1a0dbeSGarrett Wollman ++argv; 10894a1a0dbeSGarrett Wollman init_printer(pp); 1090ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 1091ba7a1ad7SGarance A Drosehn switch(cmdstatus) { 10924a1a0dbeSGarrett Wollman default: 10936d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 10944a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 10954a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 1096dea673e9SRodney W. Grimes return; 10974a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 10984a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)", *argv); 10994a1a0dbeSGarrett Wollman break; 11004a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 11014a1a0dbeSGarrett Wollman break; 11024a1a0dbeSGarrett Wollman } 11034a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1104dea673e9SRodney W. Grimes 1105360d4ad5SWarner Losh seteuid(euid); 11064a1a0dbeSGarrett Wollman if (chdir(pp->spool_dir) < 0) { 11074a1a0dbeSGarrett Wollman printf("\tcannot chdir to %s\n", pp->spool_dir); 1108360d4ad5SWarner Losh goto out; 1109dea673e9SRodney W. Grimes } 1110360d4ad5SWarner Losh seteuid(uid); 11114a1a0dbeSGarrett Wollman nitems = getq(pp, &queue); 1112dea673e9SRodney W. Grimes if (nitems == 0) 1113dea673e9SRodney W. Grimes return; 1114dea673e9SRodney W. Grimes changed = 0; 111530b4b758SGarance A Drosehn mtime = queue[0]->job_time; 1116dea673e9SRodney W. Grimes for (i = argc; --i; ) { 1117dea673e9SRodney W. Grimes if (doarg(argv[i]) == 0) { 1118dea673e9SRodney W. Grimes printf("\tjob %s is not in the queue\n", argv[i]); 1119dea673e9SRodney W. Grimes continue; 1120dea673e9SRodney W. Grimes } else 1121dea673e9SRodney W. Grimes changed++; 1122dea673e9SRodney W. Grimes } 1123dea673e9SRodney W. Grimes for (i = 0; i < nitems; i++) 1124dea673e9SRodney W. Grimes free(queue[i]); 1125dea673e9SRodney W. Grimes free(queue); 1126dea673e9SRodney W. Grimes if (!changed) { 1127dea673e9SRodney W. Grimes printf("\tqueue order unchanged\n"); 1128dea673e9SRodney W. Grimes return; 1129dea673e9SRodney W. Grimes } 1130dea673e9SRodney W. Grimes /* 1131dea673e9SRodney W. Grimes * Turn on the public execute bit of the lock file to 1132dea673e9SRodney W. Grimes * get lpd to rebuild the queue after the current job. 1133dea673e9SRodney W. Grimes */ 1134360d4ad5SWarner Losh seteuid(euid); 11354a1a0dbeSGarrett Wollman if (changed && stat(pp->lock_file, &stbuf) >= 0) 11364a1a0dbeSGarrett Wollman (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 1137360d4ad5SWarner Losh 1138360d4ad5SWarner Losh out: 1139360d4ad5SWarner Losh seteuid(uid); 1140dea673e9SRodney W. Grimes } 1141dea673e9SRodney W. Grimes 1142dea673e9SRodney W. Grimes /* 1143dea673e9SRodney W. Grimes * Reposition the job by changing the modification time of 1144dea673e9SRodney W. Grimes * the control file. 1145dea673e9SRodney W. Grimes */ 1146dea673e9SRodney W. Grimes static int 1147ba7a1ad7SGarance A Drosehn touch(struct jobqueue *jq) 1148dea673e9SRodney W. Grimes { 1149dea673e9SRodney W. Grimes struct timeval tvp[2]; 1150360d4ad5SWarner Losh int ret; 1151dea673e9SRodney W. Grimes 1152dea673e9SRodney W. Grimes tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1153dea673e9SRodney W. Grimes tvp[0].tv_usec = tvp[1].tv_usec = 0; 1154360d4ad5SWarner Losh seteuid(euid); 1155ba7a1ad7SGarance A Drosehn ret = utimes(jq->job_cfname, tvp); 1156360d4ad5SWarner Losh seteuid(uid); 1157360d4ad5SWarner Losh return (ret); 1158dea673e9SRodney W. Grimes } 1159dea673e9SRodney W. Grimes 1160dea673e9SRodney W. Grimes /* 1161dea673e9SRodney W. Grimes * Checks if specified job name is in the printer's queue. 1162dea673e9SRodney W. Grimes * Returns: negative (-1) if argument name is not in the queue. 1163dea673e9SRodney W. Grimes */ 1164dea673e9SRodney W. Grimes static int 1165ba7a1ad7SGarance A Drosehn doarg(char *job) 1166dea673e9SRodney W. Grimes { 116730b4b758SGarance A Drosehn register struct jobqueue **qq; 1168dea673e9SRodney W. Grimes register int jobnum, n; 1169dea673e9SRodney W. Grimes register char *cp, *machine; 1170dea673e9SRodney W. Grimes int cnt = 0; 1171dea673e9SRodney W. Grimes FILE *fp; 1172dea673e9SRodney W. Grimes 1173dea673e9SRodney W. Grimes /* 1174dea673e9SRodney W. Grimes * Look for a job item consisting of system name, colon, number 1175dea673e9SRodney W. Grimes * (example: ucbarpa:114) 1176dea673e9SRodney W. Grimes */ 1177f8eb25daSWarner Losh if ((cp = strchr(job, ':')) != NULL) { 1178dea673e9SRodney W. Grimes machine = job; 1179dea673e9SRodney W. Grimes *cp++ = '\0'; 1180dea673e9SRodney W. Grimes job = cp; 1181dea673e9SRodney W. Grimes } else 1182dea673e9SRodney W. Grimes machine = NULL; 1183dea673e9SRodney W. Grimes 1184dea673e9SRodney W. Grimes /* 1185dea673e9SRodney W. Grimes * Check for job specified by number (example: 112 or 235ucbarpa). 1186dea673e9SRodney W. Grimes */ 1187dea673e9SRodney W. Grimes if (isdigit(*job)) { 1188dea673e9SRodney W. Grimes jobnum = 0; 1189dea673e9SRodney W. Grimes do 1190dea673e9SRodney W. Grimes jobnum = jobnum * 10 + (*job++ - '0'); 1191dea673e9SRodney W. Grimes while (isdigit(*job)); 1192dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1193dea673e9SRodney W. Grimes n = 0; 119430b4b758SGarance A Drosehn for (cp = (*qq)->job_cfname+3; isdigit(*cp); ) 1195dea673e9SRodney W. Grimes n = n * 10 + (*cp++ - '0'); 1196dea673e9SRodney W. Grimes if (jobnum != n) 1197dea673e9SRodney W. Grimes continue; 1198dea673e9SRodney W. Grimes if (*job && strcmp(job, cp) != 0) 1199dea673e9SRodney W. Grimes continue; 1200dea673e9SRodney W. Grimes if (machine != NULL && strcmp(machine, cp) != 0) 1201dea673e9SRodney W. Grimes continue; 1202dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 120330b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1204dea673e9SRodney W. Grimes cnt++; 1205dea673e9SRodney W. Grimes } 1206dea673e9SRodney W. Grimes } 1207dea673e9SRodney W. Grimes return(cnt); 1208dea673e9SRodney W. Grimes } 1209dea673e9SRodney W. Grimes /* 1210dea673e9SRodney W. Grimes * Process item consisting of owner's name (example: henry). 1211dea673e9SRodney W. Grimes */ 1212dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1213360d4ad5SWarner Losh seteuid(euid); 121430b4b758SGarance A Drosehn fp = fopen((*qq)->job_cfname, "r"); 1215360d4ad5SWarner Losh seteuid(uid); 1216360d4ad5SWarner Losh if (fp == NULL) 1217dea673e9SRodney W. Grimes continue; 1218dea673e9SRodney W. Grimes while (getline(fp) > 0) 1219dea673e9SRodney W. Grimes if (line[0] == 'P') 1220dea673e9SRodney W. Grimes break; 1221dea673e9SRodney W. Grimes (void) fclose(fp); 1222dea673e9SRodney W. Grimes if (line[0] != 'P' || strcmp(job, line+1) != 0) 1223dea673e9SRodney W. Grimes continue; 1224dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 122530b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1226dea673e9SRodney W. Grimes cnt++; 1227dea673e9SRodney W. Grimes } 1228dea673e9SRodney W. Grimes } 1229dea673e9SRodney W. Grimes return(cnt); 1230dea673e9SRodney W. Grimes } 1231dea673e9SRodney W. Grimes 1232dea673e9SRodney W. Grimes /* 1233dea673e9SRodney W. Grimes * Enable everything and start printer (undo `down'). 1234dea673e9SRodney W. Grimes */ 1235dea673e9SRodney W. Grimes void 1236ba7a1ad7SGarance A Drosehn up(struct printer *pp) 1237dea673e9SRodney W. Grimes { 12384a1a0dbeSGarrett Wollman startpr(pp, 2); 1239dea673e9SRodney W. Grimes } 1240