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 * 4. Neither the name of the University nor the names of its contributors 15dea673e9SRodney W. Grimes * may be used to endorse or promote products derived from this software 16dea673e9SRodney W. Grimes * without specific prior written permission. 17dea673e9SRodney W. Grimes * 18dea673e9SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19dea673e9SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20dea673e9SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21dea673e9SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22dea673e9SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23dea673e9SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24dea673e9SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25dea673e9SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26dea673e9SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27dea673e9SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28dea673e9SRodney W. Grimes * SUCH DAMAGE. 29dea673e9SRodney W. Grimes */ 30dea673e9SRodney W. Grimes 31dea673e9SRodney W. Grimes #ifndef lint 324a1a0dbeSGarrett Wollman static const char copyright[] = 33dea673e9SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 34dea673e9SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 35dea673e9SRodney W. Grimes #endif /* not lint */ 36dea673e9SRodney W. Grimes 37c44a6dceSGarance A Drosehn #if 0 38dea673e9SRodney W. Grimes #ifndef lint 395458e2f4SJoerg Wunsch static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; 40dea673e9SRodney W. Grimes #endif /* not lint */ 41c44a6dceSGarance A Drosehn #endif 42c44a6dceSGarance A Drosehn 43c44a6dceSGarance A Drosehn #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 44c44a6dceSGarance A Drosehn __FBSDID("$FreeBSD$"); 45dea673e9SRodney W. Grimes 46dea673e9SRodney W. Grimes /* 47dea673e9SRodney W. Grimes * lpc -- line printer control program -- commands: 48dea673e9SRodney W. Grimes */ 49dea673e9SRodney W. Grimes 50dea673e9SRodney W. Grimes #include <sys/param.h> 51dea673e9SRodney W. Grimes #include <sys/time.h> 52dea673e9SRodney W. Grimes #include <sys/stat.h> 535458e2f4SJoerg Wunsch #include <sys/file.h> 54dea673e9SRodney W. Grimes 55dea673e9SRodney W. Grimes #include <signal.h> 56dea673e9SRodney W. Grimes #include <fcntl.h> 57dea673e9SRodney W. Grimes #include <errno.h> 58dea673e9SRodney W. Grimes #include <dirent.h> 59dea673e9SRodney W. Grimes #include <unistd.h> 60dea673e9SRodney W. Grimes #include <stdlib.h> 61dea673e9SRodney W. Grimes #include <stdio.h> 62dea673e9SRodney W. Grimes #include <ctype.h> 63dea673e9SRodney W. Grimes #include <string.h> 64dea673e9SRodney W. Grimes #include "lp.h" 65dea673e9SRodney W. Grimes #include "lp.local.h" 66dea673e9SRodney W. Grimes #include "lpc.h" 67dea673e9SRodney W. Grimes #include "extern.h" 68dea673e9SRodney W. Grimes #include "pathnames.h" 69dea673e9SRodney W. Grimes 70e8e715faSGarance A Drosehn /* 71e8e715faSGarance A Drosehn * Return values from kill_qtask(). 72e8e715faSGarance A Drosehn */ 73e8e715faSGarance A Drosehn #define KQT_LFERROR -2 74e8e715faSGarance A Drosehn #define KQT_KILLFAIL -1 75e8e715faSGarance A Drosehn #define KQT_NODAEMON 0 76e8e715faSGarance A Drosehn #define KQT_KILLOK 1 77e8e715faSGarance A Drosehn 7854032d11SGarance A Drosehn static char *args2line(int argc, char **argv); 79ba7a1ad7SGarance A Drosehn static int doarg(char *_job); 806e807fa6SKevin Lo static int doselect(const struct dirent *_d); 81e8e715faSGarance A Drosehn static int kill_qtask(const char *lf); 822c81fb6aSXin LI static int sortq(const struct dirent **a, const struct dirent **b); 83ba7a1ad7SGarance A Drosehn static int touch(struct jobqueue *_jq); 84ba7a1ad7SGarance A Drosehn static void unlinkf(char *_name); 8554032d11SGarance A Drosehn static void upstat(struct printer *_pp, const char *_msg, int _notify); 86004c9c5dSGarance A Drosehn static void wrapup_clean(int _laststatus); 874a1a0dbeSGarrett Wollman 884a1a0dbeSGarrett Wollman /* 894a1a0dbeSGarrett Wollman * generic framework for commands which operate on all or a specified 904a1a0dbeSGarrett Wollman * set of printers 914a1a0dbeSGarrett Wollman */ 92004c9c5dSGarance A Drosehn enum qsel_val { /* how a given ptr was selected */ 93004c9c5dSGarance A Drosehn QSEL_UNKNOWN = -1, /* ... not selected yet */ 94004c9c5dSGarance A Drosehn QSEL_BYNAME = 0, /* ... user specifed it by name */ 95004c9c5dSGarance A Drosehn QSEL_ALL = 1 /* ... user wants "all" printers */ 96004c9c5dSGarance A Drosehn /* (with more to come) */ 97004c9c5dSGarance A Drosehn }; 98004c9c5dSGarance A Drosehn 99004c9c5dSGarance A Drosehn static enum qsel_val generic_qselect; /* indicates how ptr was selected */ 100004c9c5dSGarance A Drosehn static int generic_initerr; /* result of initrtn processing */ 101e7f478b2SGarance A Drosehn static char *generic_cmdname; 10254032d11SGarance A Drosehn static char *generic_msg; /* if a -msg was specified */ 103004c9c5dSGarance A Drosehn static char *generic_nullarg; 104004c9c5dSGarance A Drosehn static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */ 105004c9c5dSGarance A Drosehn 1064a1a0dbeSGarrett Wollman void 10754032d11SGarance A Drosehn generic(void (*specificrtn)(struct printer *_pp), int cmdopts, 108004c9c5dSGarance A Drosehn void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[]) 1094a1a0dbeSGarrett Wollman { 110004c9c5dSGarance A Drosehn int cmdstatus, more, targc; 111004c9c5dSGarance A Drosehn struct printer myprinter, *pp; 112e7f478b2SGarance A Drosehn char **margv, **targv; 1134a1a0dbeSGarrett Wollman 1144a1a0dbeSGarrett Wollman if (argc == 1) { 1155b1c34fbSGarance A Drosehn /* 1165b1c34fbSGarance A Drosehn * Usage needs a special case for 'down': The user must 1175b1c34fbSGarance A Drosehn * either include `-msg', or only the first parameter 1185b1c34fbSGarance A Drosehn * that they give will be processed as a printer name. 1195b1c34fbSGarance A Drosehn */ 12054032d11SGarance A Drosehn printf("usage: %s {all | printer ...}", argv[0]); 1215b1c34fbSGarance A Drosehn if (strcmp(argv[0], "down") == 0) { 1225b1c34fbSGarance A Drosehn printf(" -msg [<text> ...]\n"); 1235b1c34fbSGarance A Drosehn printf(" or: down {all | printer} [<text> ...]"); 1245b1c34fbSGarance A Drosehn } else if (cmdopts & LPC_MSGOPT) 12554032d11SGarance A Drosehn printf(" [-msg <text> ...]"); 12654032d11SGarance A Drosehn printf("\n"); 1274a1a0dbeSGarrett Wollman return; 1284a1a0dbeSGarrett Wollman } 129004c9c5dSGarance A Drosehn 130e7f478b2SGarance A Drosehn /* The first argument is the command name. */ 131e7f478b2SGarance A Drosehn generic_cmdname = *argv++; 132e7f478b2SGarance A Drosehn argc--; 133e7f478b2SGarance A Drosehn 134004c9c5dSGarance A Drosehn /* 135004c9c5dSGarance A Drosehn * The initialization routine for a command might set a generic 136004c9c5dSGarance A Drosehn * "wrapup" routine, which should be called after processing all 137004c9c5dSGarance A Drosehn * the printers in the command. This might print summary info. 138004c9c5dSGarance A Drosehn * 139004c9c5dSGarance A Drosehn * Note that the initialization routine may also parse (and 140004c9c5dSGarance A Drosehn * nullify) some of the parameters given on the command, leaving 141004c9c5dSGarance A Drosehn * only the parameters which have to do with printer names. 142004c9c5dSGarance A Drosehn */ 143004c9c5dSGarance A Drosehn pp = &myprinter; 144004c9c5dSGarance A Drosehn generic_wrapup = NULL; 145004c9c5dSGarance A Drosehn generic_qselect = QSEL_UNKNOWN; 146004c9c5dSGarance A Drosehn cmdstatus = 0; 147004c9c5dSGarance A Drosehn /* this just needs to be a distinct value of type 'char *' */ 148004c9c5dSGarance A Drosehn if (generic_nullarg == NULL) 149004c9c5dSGarance A Drosehn generic_nullarg = strdup(""); 150004c9c5dSGarance A Drosehn 15154032d11SGarance A Drosehn /* 15254032d11SGarance A Drosehn * Some commands accept a -msg argument, which indicates that 15354032d11SGarance A Drosehn * all remaining arguments should be combined into a string. 15454032d11SGarance A Drosehn */ 15554032d11SGarance A Drosehn generic_msg = NULL; 15654032d11SGarance A Drosehn if (cmdopts & LPC_MSGOPT) { 15754032d11SGarance A Drosehn targc = argc; 15854032d11SGarance A Drosehn targv = argv; 159e7f478b2SGarance A Drosehn for (; targc > 0; targc--, targv++) { 16054032d11SGarance A Drosehn if (strcmp(*targv, "-msg") == 0) { 16154032d11SGarance A Drosehn argc -= targc; 16254032d11SGarance A Drosehn generic_msg = args2line(targc - 1, targv + 1); 16354032d11SGarance A Drosehn break; 16454032d11SGarance A Drosehn } 16554032d11SGarance A Drosehn } 166aa318fd7SGarance A Drosehn if (argc < 1) { 167aa318fd7SGarance A Drosehn printf("error: No printer name(s) specified before" 168aa318fd7SGarance A Drosehn " '-msg'.\n"); 169aa318fd7SGarance A Drosehn printf("usage: %s {all | printer ...}", 170aa318fd7SGarance A Drosehn generic_cmdname); 171aa318fd7SGarance A Drosehn printf(" [-msg <text> ...]\n"); 172aa318fd7SGarance A Drosehn return; 173aa318fd7SGarance A Drosehn } 17454032d11SGarance A Drosehn } 17554032d11SGarance A Drosehn 176004c9c5dSGarance A Drosehn /* call initialization routine, if there is one for this cmd */ 177004c9c5dSGarance A Drosehn if (initrtn != NULL) { 178004c9c5dSGarance A Drosehn generic_initerr = 0; 179004c9c5dSGarance A Drosehn (*initrtn)(argc, argv); 180004c9c5dSGarance A Drosehn if (generic_initerr) 181004c9c5dSGarance A Drosehn return; 182e7f478b2SGarance A Drosehn /* 183e7f478b2SGarance A Drosehn * The initrtn may have null'ed out some of the parameters. 184e7f478b2SGarance A Drosehn * Compact the parameter list to remove those nulls, and 185e7f478b2SGarance A Drosehn * correct the arg-count. 186e7f478b2SGarance A Drosehn */ 187004c9c5dSGarance A Drosehn targc = argc; 188004c9c5dSGarance A Drosehn targv = argv; 189e7f478b2SGarance A Drosehn margv = argv; 190e7f478b2SGarance A Drosehn argc = 0; 191e7f478b2SGarance A Drosehn for (; targc > 0; targc--, targv++) { 192e7f478b2SGarance A Drosehn if (*targv != generic_nullarg) { 193e7f478b2SGarance A Drosehn if (targv != margv) 194e7f478b2SGarance A Drosehn *margv = *targv; 195e7f478b2SGarance A Drosehn margv++; 196e7f478b2SGarance A Drosehn argc++; 197004c9c5dSGarance A Drosehn } 198004c9c5dSGarance A Drosehn } 199004c9c5dSGarance A Drosehn } 200004c9c5dSGarance A Drosehn 201e7f478b2SGarance A Drosehn if (argc == 1 && strcmp(*argv, "all") == 0) { 202004c9c5dSGarance A Drosehn generic_qselect = QSEL_ALL; 203ba7a1ad7SGarance A Drosehn more = firstprinter(pp, &cmdstatus); 204ba7a1ad7SGarance A Drosehn if (cmdstatus) 2054a1a0dbeSGarrett Wollman goto looperr; 2064a1a0dbeSGarrett Wollman while (more) { 207ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 2084a1a0dbeSGarrett Wollman do { 209ba7a1ad7SGarance A Drosehn more = nextprinter(pp, &cmdstatus); 2104a1a0dbeSGarrett Wollman looperr: 211ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 2124a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 2134a1a0dbeSGarrett Wollman printf("warning: %s: unresolved " 2144a1a0dbeSGarrett Wollman "tc= reference(s) ", 2154a1a0dbeSGarrett Wollman pp->printer); 2164a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 2174a1a0dbeSGarrett Wollman break; 2184a1a0dbeSGarrett Wollman default: 2196d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 2204a1a0dbeSGarrett Wollman } 221ba7a1ad7SGarance A Drosehn } while (more && cmdstatus); 2224a1a0dbeSGarrett Wollman } 223004c9c5dSGarance A Drosehn goto wrapup; 2244a1a0dbeSGarrett Wollman } 225004c9c5dSGarance A Drosehn 226004c9c5dSGarance A Drosehn generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */ 227e7f478b2SGarance A Drosehn for (; argc > 0; argc--, argv++) { 2284a1a0dbeSGarrett Wollman init_printer(pp); 229ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 230ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 2314a1a0dbeSGarrett Wollman default: 2326d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 2334a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 2344a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 2354a1a0dbeSGarrett Wollman continue; 2364a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 2374a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)\n", 2384a1a0dbeSGarrett Wollman *argv); 2394a1a0dbeSGarrett Wollman break; 2404a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 2414a1a0dbeSGarrett Wollman break; 2424a1a0dbeSGarrett Wollman } 243ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 2444a1a0dbeSGarrett Wollman } 245004c9c5dSGarance A Drosehn 246004c9c5dSGarance A Drosehn wrapup: 247004c9c5dSGarance A Drosehn if (generic_wrapup) { 248004c9c5dSGarance A Drosehn (*generic_wrapup)(cmdstatus); 249004c9c5dSGarance A Drosehn } 250cc2b61b1SGarance A Drosehn free_printer(pp); 25154032d11SGarance A Drosehn if (generic_msg) 25254032d11SGarance A Drosehn free(generic_msg); 25354032d11SGarance A Drosehn } 254004c9c5dSGarance A Drosehn 25554032d11SGarance A Drosehn /* 25654032d11SGarance A Drosehn * Convert an argv-array of character strings into a single string. 25754032d11SGarance A Drosehn */ 25854032d11SGarance A Drosehn static char * 25954032d11SGarance A Drosehn args2line(int argc, char **argv) 26054032d11SGarance A Drosehn { 26154032d11SGarance A Drosehn char *cp1, *cend; 26254032d11SGarance A Drosehn const char *cp2; 26354032d11SGarance A Drosehn char buf[1024]; 26454032d11SGarance A Drosehn 26554032d11SGarance A Drosehn if (argc <= 0) 26654032d11SGarance A Drosehn return strdup("\n"); 26754032d11SGarance A Drosehn 26854032d11SGarance A Drosehn cp1 = buf; 26954032d11SGarance A Drosehn cend = buf + sizeof(buf) - 1; /* save room for '\0' */ 27054032d11SGarance A Drosehn while (--argc >= 0) { 27154032d11SGarance A Drosehn cp2 = *argv++; 27254032d11SGarance A Drosehn while ((cp1 < cend) && (*cp1++ = *cp2++)) 27354032d11SGarance A Drosehn ; 27454032d11SGarance A Drosehn cp1[-1] = ' '; 27554032d11SGarance A Drosehn } 27654032d11SGarance A Drosehn cp1[-1] = '\n'; 27754032d11SGarance A Drosehn *cp1 = '\0'; 27854032d11SGarance A Drosehn return strdup(buf); 2794a1a0dbeSGarrett Wollman } 280dea673e9SRodney W. Grimes 281dea673e9SRodney W. Grimes /* 282e8e715faSGarance A Drosehn * Kill the current daemon, to stop printing of the active job. 283e8e715faSGarance A Drosehn */ 284e8e715faSGarance A Drosehn static int 285e8e715faSGarance A Drosehn kill_qtask(const char *lf) 286e8e715faSGarance A Drosehn { 287e8e715faSGarance A Drosehn FILE *fp; 288e8e715faSGarance A Drosehn pid_t pid; 289e8e715faSGarance A Drosehn int errsav, killres, lockres, res; 290e8e715faSGarance A Drosehn 291e8e715faSGarance A Drosehn seteuid(euid); 292e8e715faSGarance A Drosehn fp = fopen(lf, "r"); 293e8e715faSGarance A Drosehn errsav = errno; 294e8e715faSGarance A Drosehn seteuid(uid); 295e8e715faSGarance A Drosehn res = KQT_NODAEMON; 296e8e715faSGarance A Drosehn if (fp == NULL) { 297e8e715faSGarance A Drosehn /* 298e8e715faSGarance A Drosehn * If there is no lock file, then there is no daemon to 299e8e715faSGarance A Drosehn * kill. Any other error return means there is some 300e8e715faSGarance A Drosehn * kind of problem with the lock file. 301e8e715faSGarance A Drosehn */ 302e8e715faSGarance A Drosehn if (errsav != ENOENT) 303e8e715faSGarance A Drosehn res = KQT_LFERROR; 304e8e715faSGarance A Drosehn goto killdone; 305e8e715faSGarance A Drosehn } 306e8e715faSGarance A Drosehn 307e8e715faSGarance A Drosehn /* If the lock file is empty, then there is no daemon to kill */ 308e8e715faSGarance A Drosehn if (getline(fp) == 0) 309e8e715faSGarance A Drosehn goto killdone; 310e8e715faSGarance A Drosehn 311e8e715faSGarance A Drosehn /* 312e8e715faSGarance A Drosehn * If the file can be locked without blocking, then there 313e8e715faSGarance A Drosehn * no daemon to kill, or we should not try to kill it. 314e8e715faSGarance A Drosehn * 315e8e715faSGarance A Drosehn * XXX - not sure I understand the reasoning behind this... 316e8e715faSGarance A Drosehn */ 317e8e715faSGarance A Drosehn lockres = flock(fileno(fp), LOCK_SH|LOCK_NB); 318e8e715faSGarance A Drosehn (void) fclose(fp); 319e8e715faSGarance A Drosehn if (lockres == 0) 320e8e715faSGarance A Drosehn goto killdone; 321e8e715faSGarance A Drosehn 322e8e715faSGarance A Drosehn pid = atoi(line); 323e8e715faSGarance A Drosehn if (pid < 0) { 324e8e715faSGarance A Drosehn /* 325e8e715faSGarance A Drosehn * If we got a negative pid, then the contents of the 326e8e715faSGarance A Drosehn * lock file is not valid. 327e8e715faSGarance A Drosehn */ 328e8e715faSGarance A Drosehn res = KQT_LFERROR; 329e8e715faSGarance A Drosehn goto killdone; 330e8e715faSGarance A Drosehn } 331e8e715faSGarance A Drosehn 332e8e715faSGarance A Drosehn seteuid(uid); 333e8e715faSGarance A Drosehn killres = kill(pid, SIGTERM); 334e8e715faSGarance A Drosehn errsav = errno; 335e8e715faSGarance A Drosehn seteuid(uid); 336e8e715faSGarance A Drosehn if (killres == 0) { 337e8e715faSGarance A Drosehn res = KQT_KILLOK; 338e8e715faSGarance A Drosehn printf("\tdaemon (pid %d) killed\n", pid); 339e8e715faSGarance A Drosehn } else if (errno == ESRCH) { 340e8e715faSGarance A Drosehn res = KQT_NODAEMON; 341e8e715faSGarance A Drosehn } else { 342e8e715faSGarance A Drosehn res = KQT_KILLFAIL; 343e8e715faSGarance A Drosehn printf("\tWarning: daemon (pid %d) not killed:\n", pid); 344e8e715faSGarance A Drosehn printf("\t %s\n", strerror(errsav)); 345e8e715faSGarance A Drosehn } 346e8e715faSGarance A Drosehn 347e8e715faSGarance A Drosehn killdone: 348e8e715faSGarance A Drosehn switch (res) { 349e8e715faSGarance A Drosehn case KQT_LFERROR: 350e8e715faSGarance A Drosehn printf("\tcannot open lock file: %s\n", 351e8e715faSGarance A Drosehn strerror(errsav)); 352e8e715faSGarance A Drosehn break; 353e8e715faSGarance A Drosehn case KQT_NODAEMON: 354e8e715faSGarance A Drosehn printf("\tno daemon to abort\n"); 355e8e715faSGarance A Drosehn break; 356e8e715faSGarance A Drosehn case KQT_KILLFAIL: 357e8e715faSGarance A Drosehn case KQT_KILLOK: 358e8e715faSGarance A Drosehn /* These two already printed messages to the user. */ 359e8e715faSGarance A Drosehn break; 360e8e715faSGarance A Drosehn default: 361e8e715faSGarance A Drosehn printf("\t<internal error in kill_qtask>\n"); 362e8e715faSGarance A Drosehn break; 363e8e715faSGarance A Drosehn } 364e8e715faSGarance A Drosehn 365e8e715faSGarance A Drosehn return (res); 366e8e715faSGarance A Drosehn } 367e8e715faSGarance A Drosehn 368e8e715faSGarance A Drosehn /* 369dea673e9SRodney W. Grimes * Write a message into the status file. 370dea673e9SRodney W. Grimes */ 371dea673e9SRodney W. Grimes static void 37254032d11SGarance A Drosehn upstat(struct printer *pp, const char *msg, int notifyuser) 373dea673e9SRodney W. Grimes { 37454032d11SGarance A Drosehn int fd; 3755f87a7b6SWarner Losh char statfile[MAXPATHLEN]; 376dea673e9SRodney W. Grimes 3774a1a0dbeSGarrett Wollman status_file_name(pp, statfile, sizeof statfile); 378dea673e9SRodney W. Grimes umask(0); 37954032d11SGarance A Drosehn seteuid(euid); 3804a1a0dbeSGarrett Wollman fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 38154032d11SGarance A Drosehn seteuid(uid); 3824a1a0dbeSGarrett Wollman if (fd < 0) { 3834a1a0dbeSGarrett Wollman printf("\tcannot create status file: %s\n", strerror(errno)); 384dea673e9SRodney W. Grimes return; 385dea673e9SRodney W. Grimes } 386dea673e9SRodney W. Grimes (void) ftruncate(fd, 0); 3876e807fa6SKevin Lo if (msg == NULL) 388dea673e9SRodney W. Grimes (void) write(fd, "\n", 1); 389dea673e9SRodney W. Grimes else 390dea673e9SRodney W. Grimes (void) write(fd, msg, strlen(msg)); 391dea673e9SRodney W. Grimes (void) close(fd); 39254032d11SGarance A Drosehn if (notifyuser) { 39354032d11SGarance A Drosehn if ((msg == (char *)NULL) || (strcmp(msg, "\n") == 0)) 39454032d11SGarance A Drosehn printf("\tstatus message is now set to nothing.\n"); 39554032d11SGarance A Drosehn else 39654032d11SGarance A Drosehn printf("\tstatus message is now: %s", msg); 39754032d11SGarance A Drosehn } 398dea673e9SRodney W. Grimes } 399dea673e9SRodney W. Grimes 400004c9c5dSGarance A Drosehn /* 401e8e715faSGarance A Drosehn * kill an existing daemon and disable printing. 402e8e715faSGarance A Drosehn */ 403e8e715faSGarance A Drosehn void 404e8e715faSGarance A Drosehn abort_q(struct printer *pp) 405e8e715faSGarance A Drosehn { 406e8e715faSGarance A Drosehn int killres, setres; 407e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 408e8e715faSGarance A Drosehn 409e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 410e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 411e8e715faSGarance A Drosehn 412e8e715faSGarance A Drosehn /* 413e8e715faSGarance A Drosehn * Turn on the owner execute bit of the lock file to disable printing. 414e8e715faSGarance A Drosehn */ 415e8e715faSGarance A Drosehn setres = set_qstate(SQS_STOPP, lf); 416e8e715faSGarance A Drosehn 417e8e715faSGarance A Drosehn /* 418e8e715faSGarance A Drosehn * If set_qstate found that there already was a lock file, then 419e8e715faSGarance A Drosehn * call a routine which will read that lock file and kill the 420e8e715faSGarance A Drosehn * lpd-process which is listed in that lock file. If the lock 421e8e715faSGarance A Drosehn * file did not exist, then either there is no daemon running 422e8e715faSGarance A Drosehn * for this queue, or there is one running but *it* could not 423e8e715faSGarance A Drosehn * write a lock file (which means we can not determine the 424e8e715faSGarance A Drosehn * process id of that lpd-process). 425e8e715faSGarance A Drosehn */ 426e8e715faSGarance A Drosehn switch (setres) { 427e8e715faSGarance A Drosehn case SQS_CHGOK: 428e8e715faSGarance A Drosehn case SQS_CHGFAIL: 429e8e715faSGarance A Drosehn /* Kill the process */ 430e8e715faSGarance A Drosehn killres = kill_qtask(lf); 431e8e715faSGarance A Drosehn break; 432e8e715faSGarance A Drosehn case SQS_CREOK: 433e8e715faSGarance A Drosehn case SQS_CREFAIL: 434e8e715faSGarance A Drosehn printf("\tno daemon to abort\n"); 435e8e715faSGarance A Drosehn break; 436e8e715faSGarance A Drosehn case SQS_STATFAIL: 437e8e715faSGarance A Drosehn printf("\tassuming no daemon to abort\n"); 438e8e715faSGarance A Drosehn break; 439e8e715faSGarance A Drosehn default: 440e8e715faSGarance A Drosehn printf("\t<unexpected result (%d) from set_qstate>\n", 441e8e715faSGarance A Drosehn setres); 442e8e715faSGarance A Drosehn break; 443e8e715faSGarance A Drosehn } 444e8e715faSGarance A Drosehn 44554032d11SGarance A Drosehn if (setres >= 0) 44654032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 447e8e715faSGarance A Drosehn } 448e8e715faSGarance A Drosehn 449e8e715faSGarance A Drosehn /* 450004c9c5dSGarance A Drosehn * "global" variables for all the routines related to 'clean' and 'tclean' 451004c9c5dSGarance A Drosehn */ 452004c9c5dSGarance A Drosehn static time_t cln_now; /* current time */ 453004c9c5dSGarance A Drosehn static double cln_minage; /* minimum age before file is removed */ 454004c9c5dSGarance A Drosehn static long cln_sizecnt; /* amount of space freed up */ 455004c9c5dSGarance A Drosehn static int cln_debug; /* print extra debugging msgs */ 456004c9c5dSGarance A Drosehn static int cln_filecnt; /* number of files destroyed */ 457004c9c5dSGarance A Drosehn static int cln_foundcore; /* found a core file! */ 458004c9c5dSGarance A Drosehn static int cln_queuecnt; /* number of queues checked */ 459004c9c5dSGarance A Drosehn static int cln_testonly; /* remove-files vs just-print-info */ 460004c9c5dSGarance A Drosehn 461dea673e9SRodney W. Grimes static int 4626e807fa6SKevin Lo doselect(const struct dirent *d) 463dea673e9SRodney W. Grimes { 464dea673e9SRodney W. Grimes int c = d->d_name[0]; 465dea673e9SRodney W. Grimes 4661fd731faSGarance A Drosehn if ((c == 'c' || c == 'd' || c == 'r' || c == 't') && 4671fd731faSGarance A Drosehn d->d_name[1] == 'f') 468004c9c5dSGarance A Drosehn return 1; 469004c9c5dSGarance A Drosehn if (c == 'c') { 470004c9c5dSGarance A Drosehn if (!strcmp(d->d_name, "core")) 471004c9c5dSGarance A Drosehn cln_foundcore = 1; 472004c9c5dSGarance A Drosehn } 473004c9c5dSGarance A Drosehn if (c == 'e') { 474004c9c5dSGarance A Drosehn if (!strncmp(d->d_name, "errs.", 5)) 475004c9c5dSGarance A Drosehn return 1; 476004c9c5dSGarance A Drosehn } 477004c9c5dSGarance A Drosehn return 0; 478dea673e9SRodney W. Grimes } 479dea673e9SRodney W. Grimes 480dea673e9SRodney W. Grimes /* 481ceeaedd3SGarance A Drosehn * Comparison routine that clean_q() uses for scandir. 482ceeaedd3SGarance A Drosehn * 483ceeaedd3SGarance A Drosehn * The purpose of this sort is to have all `df' files end up immediately 4841fd731faSGarance A Drosehn * after the matching `cf' file. For files matching `cf', `df', `rf', or 4851fd731faSGarance A Drosehn * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or 4861fd731faSGarance A Drosehn * `tf', and then by the sequence letter (which is A-Z, or a-z). This 4871fd731faSGarance A Drosehn * routine may also see filenames which do not start with `cf', `df', `rf', 4881fd731faSGarance A Drosehn * or `tf' (such as `errs.*'), and those are simply sorted by the full 4891fd731faSGarance A Drosehn * filename. 4901fd731faSGarance A Drosehn * 4911fd731faSGarance A Drosehn * XXX 4921fd731faSGarance A Drosehn * This assumes that all control files start with `cfA*', and it turns 4931fd731faSGarance A Drosehn * out there are a few implementations of lpr which will create `cfB*' 4941fd731faSGarance A Drosehn * filenames (they will have datafile names which start with `dfB*'). 495dea673e9SRodney W. Grimes */ 496dea673e9SRodney W. Grimes static int 4972c81fb6aSXin LI sortq(const struct dirent **a, const struct dirent **b) 498dea673e9SRodney W. Grimes { 499ceeaedd3SGarance A Drosehn const int a_lt_b = -1, a_gt_b = 1, cat_other = 10; 500ceeaedd3SGarance A Drosehn const char *fname_a, *fname_b, *jnum_a, *jnum_b; 501ceeaedd3SGarance A Drosehn int cat_a, cat_b, ch, res, seq_a, seq_b; 502dea673e9SRodney W. Grimes 5032c81fb6aSXin LI fname_a = (*a)->d_name; 5042c81fb6aSXin LI fname_b = (*b)->d_name; 505ceeaedd3SGarance A Drosehn 506ceeaedd3SGarance A Drosehn /* 5073df5ecacSUlrich Spörlein * First separate filenames into categories. Categories are 5081fd731faSGarance A Drosehn * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in 5091fd731faSGarance A Drosehn * that order. It is critical that the mapping be exactly the 5101fd731faSGarance A Drosehn * same for 'a' vs 'b', so define a macro for the job. 511ceeaedd3SGarance A Drosehn * 512ceeaedd3SGarance A Drosehn * [aside: the standard `cf' file has the jobnumber start in 513ceeaedd3SGarance A Drosehn * position 4, but some implementations have that as an extra 514ceeaedd3SGarance A Drosehn * file-sequence letter, and start the job number in position 5.] 515ceeaedd3SGarance A Drosehn */ 516ceeaedd3SGarance A Drosehn #define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \ 517ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 518ceeaedd3SGarance A Drosehn ch = *(fname_X + 2); \ 519ceeaedd3SGarance A Drosehn jnum_X = fname_X + 3; \ 5204f7f8234SGarance A Drosehn seq_X = 0; \ 521ceeaedd3SGarance A Drosehn if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \ 522ceeaedd3SGarance A Drosehn seq_X = ch; \ 523ceeaedd3SGarance A Drosehn if (*fname_X == 'c') \ 524ceeaedd3SGarance A Drosehn cat_X = 1; \ 525ceeaedd3SGarance A Drosehn else if (*fname_X == 'd') \ 526ceeaedd3SGarance A Drosehn cat_X = 2; \ 5271fd731faSGarance A Drosehn else if (*fname_X == 'r') \ 528ceeaedd3SGarance A Drosehn cat_X = 3; \ 5291fd731faSGarance A Drosehn else if (*fname_X == 't') \ 5301fd731faSGarance A Drosehn cat_X = 4; \ 531ceeaedd3SGarance A Drosehn if (cat_X != cat_other) { \ 532ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 533ceeaedd3SGarance A Drosehn if (!isdigit(ch)) { \ 534ceeaedd3SGarance A Drosehn if (isalpha(ch)) { \ 535ceeaedd3SGarance A Drosehn jnum_X++; \ 536ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 537ceeaedd3SGarance A Drosehn seq_X = (seq_X << 8) + ch; \ 538ceeaedd3SGarance A Drosehn } \ 539ceeaedd3SGarance A Drosehn if (!isdigit(ch)) \ 540ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 541ceeaedd3SGarance A Drosehn } \ 542ceeaedd3SGarance A Drosehn } \ 543ceeaedd3SGarance A Drosehn } \ 544ceeaedd3SGarance A Drosehn } while (0) 545ceeaedd3SGarance A Drosehn 546ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a); 547ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b); 548ceeaedd3SGarance A Drosehn 549ceeaedd3SGarance A Drosehn #undef MAP_TO_CAT 550ceeaedd3SGarance A Drosehn 551ceeaedd3SGarance A Drosehn /* First handle all cases which have "other" files */ 552ceeaedd3SGarance A Drosehn if ((cat_a >= cat_other) || (cat_b >= cat_other)) { 553ceeaedd3SGarance A Drosehn /* for two "other" files, just compare the full name */ 554ceeaedd3SGarance A Drosehn if (cat_a == cat_b) 555ceeaedd3SGarance A Drosehn res = strcmp(fname_a, fname_b); 556ceeaedd3SGarance A Drosehn else if (cat_a < cat_b) 557ceeaedd3SGarance A Drosehn res = a_lt_b; 558ceeaedd3SGarance A Drosehn else 559ceeaedd3SGarance A Drosehn res = a_gt_b; 560ceeaedd3SGarance A Drosehn goto have_res; 561ceeaedd3SGarance A Drosehn } 562ceeaedd3SGarance A Drosehn 563ceeaedd3SGarance A Drosehn /* 5641fd731faSGarance A Drosehn * At this point, we know both files are legitimate `cf', `df', `rf', 565ceeaedd3SGarance A Drosehn * or `tf' files. Compare them by job-number and machine name. 566ceeaedd3SGarance A Drosehn */ 567ceeaedd3SGarance A Drosehn res = strcmp(jnum_a, jnum_b); 568ceeaedd3SGarance A Drosehn if (res != 0) 569ceeaedd3SGarance A Drosehn goto have_res; 570ceeaedd3SGarance A Drosehn 571ceeaedd3SGarance A Drosehn /* 572ceeaedd3SGarance A Drosehn * We have two files which belong to the same job. Sort based 5733df5ecacSUlrich Spörlein * on the category of file (`c' before `d', etc). 574ceeaedd3SGarance A Drosehn */ 575ceeaedd3SGarance A Drosehn if (cat_a < cat_b) { 576ceeaedd3SGarance A Drosehn res = a_lt_b; 577ceeaedd3SGarance A Drosehn goto have_res; 578ceeaedd3SGarance A Drosehn } else if (cat_a > cat_b) { 579ceeaedd3SGarance A Drosehn res = a_gt_b; 580ceeaedd3SGarance A Drosehn goto have_res; 581ceeaedd3SGarance A Drosehn } 582ceeaedd3SGarance A Drosehn 583ceeaedd3SGarance A Drosehn /* 5843df5ecacSUlrich Spörlein * Two files in the same category for a single job. Sort based 5853df5ecacSUlrich Spörlein * on the sequence letter(s). (usually `A' through `Z', etc). 586ceeaedd3SGarance A Drosehn */ 587ceeaedd3SGarance A Drosehn if (seq_a < seq_b) { 588ceeaedd3SGarance A Drosehn res = a_lt_b; 589ceeaedd3SGarance A Drosehn goto have_res; 590ceeaedd3SGarance A Drosehn } else if (seq_a > seq_b) { 591ceeaedd3SGarance A Drosehn res = a_gt_b; 592ceeaedd3SGarance A Drosehn goto have_res; 593ceeaedd3SGarance A Drosehn } 594ceeaedd3SGarance A Drosehn 595ceeaedd3SGarance A Drosehn /* 596ceeaedd3SGarance A Drosehn * Given that the filenames in a directory are unique, this SHOULD 597ceeaedd3SGarance A Drosehn * never happen (unless there are logic errors in this routine). 598ceeaedd3SGarance A Drosehn * But if it does happen, we must return "is equal" or the caller 599ceeaedd3SGarance A Drosehn * might see inconsistent results in the sorting order, and that 600ceeaedd3SGarance A Drosehn * can trigger other problems. 601ceeaedd3SGarance A Drosehn */ 602ceeaedd3SGarance A Drosehn printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b); 603ceeaedd3SGarance A Drosehn printf("\t*** cat %d == %d ; seq = %d %d\n", cat_a, cat_b, 604ceeaedd3SGarance A Drosehn seq_a, seq_b); 605ceeaedd3SGarance A Drosehn res = 0; 606ceeaedd3SGarance A Drosehn 607ceeaedd3SGarance A Drosehn have_res: 608ceeaedd3SGarance A Drosehn return res; 609dea673e9SRodney W. Grimes } 610dea673e9SRodney W. Grimes 611dea673e9SRodney W. Grimes /* 6124a1a0dbeSGarrett Wollman * Remove all spool files and temporaries from the spooling area. 6134a1a0dbeSGarrett Wollman * Or, perhaps: 614dea673e9SRodney W. Grimes * Remove incomplete jobs from spooling area. 615dea673e9SRodney W. Grimes */ 616dea673e9SRodney W. Grimes 617004c9c5dSGarance A Drosehn void 618c9cb13a0SGarance A Drosehn clean_gi(int argc, char *argv[]) 619004c9c5dSGarance A Drosehn { 620004c9c5dSGarance A Drosehn 621004c9c5dSGarance A Drosehn /* init some fields before 'clean' is called for each queue */ 622004c9c5dSGarance A Drosehn cln_queuecnt = 0; 623004c9c5dSGarance A Drosehn cln_now = time(NULL); 624004c9c5dSGarance A Drosehn cln_minage = 3600.0; /* only delete files >1h old */ 625004c9c5dSGarance A Drosehn cln_filecnt = 0; 626004c9c5dSGarance A Drosehn cln_sizecnt = 0; 627004c9c5dSGarance A Drosehn cln_debug = 0; 628004c9c5dSGarance A Drosehn cln_testonly = 0; 629004c9c5dSGarance A Drosehn generic_wrapup = &wrapup_clean; 630004c9c5dSGarance A Drosehn 631004c9c5dSGarance A Drosehn /* see if there are any options specified before the ptr list */ 632e7f478b2SGarance A Drosehn for (; argc > 0; argc--, argv++) { 633004c9c5dSGarance A Drosehn if (**argv != '-') 634004c9c5dSGarance A Drosehn break; 635004c9c5dSGarance A Drosehn if (strcmp(*argv, "-d") == 0) { 636004c9c5dSGarance A Drosehn /* just an example of an option... */ 637ceeaedd3SGarance A Drosehn cln_debug++; 638004c9c5dSGarance A Drosehn *argv = generic_nullarg; /* "erase" it */ 639004c9c5dSGarance A Drosehn } else { 640004c9c5dSGarance A Drosehn printf("Invalid option '%s'\n", *argv); 641004c9c5dSGarance A Drosehn generic_initerr = 1; 642004c9c5dSGarance A Drosehn } 643004c9c5dSGarance A Drosehn } 644004c9c5dSGarance A Drosehn 645004c9c5dSGarance A Drosehn return; 646004c9c5dSGarance A Drosehn } 647004c9c5dSGarance A Drosehn 648004c9c5dSGarance A Drosehn void 649c9cb13a0SGarance A Drosehn tclean_gi(int argc, char *argv[]) 650004c9c5dSGarance A Drosehn { 651004c9c5dSGarance A Drosehn 652004c9c5dSGarance A Drosehn /* only difference between 'clean' and 'tclean' is one value */ 653004c9c5dSGarance A Drosehn /* (...and the fact that 'clean' is priv and 'tclean' is not) */ 654c9cb13a0SGarance A Drosehn clean_gi(argc, argv); 655004c9c5dSGarance A Drosehn cln_testonly = 1; 656004c9c5dSGarance A Drosehn 657004c9c5dSGarance A Drosehn return; 658004c9c5dSGarance A Drosehn } 659004c9c5dSGarance A Drosehn 660004c9c5dSGarance A Drosehn void 661004c9c5dSGarance A Drosehn clean_q(struct printer *pp) 662004c9c5dSGarance A Drosehn { 663004c9c5dSGarance A Drosehn char *cp, *cp1, *lp; 664004c9c5dSGarance A Drosehn struct dirent **queue; 665004c9c5dSGarance A Drosehn size_t linerem; 666004c9c5dSGarance A Drosehn int didhead, i, n, nitems, rmcp; 667004c9c5dSGarance A Drosehn 668004c9c5dSGarance A Drosehn cln_queuecnt++; 669004c9c5dSGarance A Drosehn 670004c9c5dSGarance A Drosehn didhead = 0; 671004c9c5dSGarance A Drosehn if (generic_qselect == QSEL_BYNAME) { 6724a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 673004c9c5dSGarance A Drosehn didhead = 1; 674004c9c5dSGarance A Drosehn } 675dea673e9SRodney W. Grimes 6764a1a0dbeSGarrett Wollman lp = line; 6774a1a0dbeSGarrett Wollman cp = pp->spool_dir; 6784a1a0dbeSGarrett Wollman while (lp < &line[sizeof(line) - 1]) { 6794a1a0dbeSGarrett Wollman if ((*lp++ = *cp++) == 0) 6804a1a0dbeSGarrett Wollman break; 6814a1a0dbeSGarrett Wollman } 682dea673e9SRodney W. Grimes lp[-1] = '/'; 683004c9c5dSGarance A Drosehn linerem = sizeof(line) - (lp - line); 684dea673e9SRodney W. Grimes 685004c9c5dSGarance A Drosehn cln_foundcore = 0; 686360d4ad5SWarner Losh seteuid(euid); 6874a1a0dbeSGarrett Wollman nitems = scandir(pp->spool_dir, &queue, doselect, sortq); 688360d4ad5SWarner Losh seteuid(uid); 689dea673e9SRodney W. Grimes if (nitems < 0) { 690004c9c5dSGarance A Drosehn if (!didhead) { 691004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 692004c9c5dSGarance A Drosehn didhead = 1; 693004c9c5dSGarance A Drosehn } 694dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 695dea673e9SRodney W. Grimes return; 696dea673e9SRodney W. Grimes } 697004c9c5dSGarance A Drosehn if (cln_foundcore) { 698004c9c5dSGarance A Drosehn if (!didhead) { 699004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 700004c9c5dSGarance A Drosehn didhead = 1; 701004c9c5dSGarance A Drosehn } 702004c9c5dSGarance A Drosehn printf("\t** found a core file in %s !\n", pp->spool_dir); 703004c9c5dSGarance A Drosehn } 704dea673e9SRodney W. Grimes if (nitems == 0) 705dea673e9SRodney W. Grimes return; 706004c9c5dSGarance A Drosehn if (!didhead) 707004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 708ceeaedd3SGarance A Drosehn if (cln_debug) { 709ceeaedd3SGarance A Drosehn printf("\t** ----- Sorted list of files being checked:\n"); 710ceeaedd3SGarance A Drosehn i = 0; 711ceeaedd3SGarance A Drosehn do { 712ceeaedd3SGarance A Drosehn cp = queue[i]->d_name; 713ceeaedd3SGarance A Drosehn printf("\t** [%3d] = %s\n", i, cp); 714ceeaedd3SGarance A Drosehn } while (++i < nitems); 715ceeaedd3SGarance A Drosehn printf("\t** ----- end of sorted list\n"); 716ceeaedd3SGarance A Drosehn } 717dea673e9SRodney W. Grimes i = 0; 718dea673e9SRodney W. Grimes do { 719dea673e9SRodney W. Grimes cp = queue[i]->d_name; 720004c9c5dSGarance A Drosehn rmcp = 0; 721dea673e9SRodney W. Grimes if (*cp == 'c') { 722004c9c5dSGarance A Drosehn /* 723004c9c5dSGarance A Drosehn * A control file. Look for matching data-files. 724004c9c5dSGarance A Drosehn */ 725004c9c5dSGarance A Drosehn /* XXX 726004c9c5dSGarance A Drosehn * Note the logic here assumes that the hostname 727004c9c5dSGarance A Drosehn * part of cf-filenames match the hostname part 728004c9c5dSGarance A Drosehn * in df-filenames, and that is not necessarily 729004c9c5dSGarance A Drosehn * true (eg: for multi-homed hosts). This needs 730004c9c5dSGarance A Drosehn * some further thought... 731004c9c5dSGarance A Drosehn */ 732dea673e9SRodney W. Grimes n = 0; 733dea673e9SRodney W. Grimes while (i + 1 < nitems) { 734dea673e9SRodney W. Grimes cp1 = queue[i + 1]->d_name; 735dea673e9SRodney W. Grimes if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 736dea673e9SRodney W. Grimes break; 737dea673e9SRodney W. Grimes i++; 738dea673e9SRodney W. Grimes n++; 739dea673e9SRodney W. Grimes } 740dea673e9SRodney W. Grimes if (n == 0) { 741004c9c5dSGarance A Drosehn rmcp = 1; 742dea673e9SRodney W. Grimes } 743004c9c5dSGarance A Drosehn } else if (*cp == 'e') { 744004c9c5dSGarance A Drosehn /* 745004c9c5dSGarance A Drosehn * Must be an errrs or email temp file. 746004c9c5dSGarance A Drosehn */ 747004c9c5dSGarance A Drosehn rmcp = 1; 748dea673e9SRodney W. Grimes } else { 749dea673e9SRodney W. Grimes /* 750dea673e9SRodney W. Grimes * Must be a df with no cf (otherwise, it would have 7511fd731faSGarance A Drosehn * been skipped above) or an rf or tf file (which can 7521fd731faSGarance A Drosehn * always be removed if it is old enough). 753dea673e9SRodney W. Grimes */ 754004c9c5dSGarance A Drosehn rmcp = 1; 755004c9c5dSGarance A Drosehn } 756004c9c5dSGarance A Drosehn if (rmcp) { 757004c9c5dSGarance A Drosehn if (strlen(cp) >= linerem) { 758004c9c5dSGarance A Drosehn printf("\t** internal error: 'line' overflow!\n"); 759004c9c5dSGarance A Drosehn printf("\t** spooldir = %s\n", pp->spool_dir); 760004c9c5dSGarance A Drosehn printf("\t** cp = %s\n", cp); 761004c9c5dSGarance A Drosehn return; 762004c9c5dSGarance A Drosehn } 763004c9c5dSGarance A Drosehn strlcpy(lp, cp, linerem); 764dea673e9SRodney W. Grimes unlinkf(line); 765dea673e9SRodney W. Grimes } 766dea673e9SRodney W. Grimes } while (++i < nitems); 767dea673e9SRodney W. Grimes } 768dea673e9SRodney W. Grimes 769dea673e9SRodney W. Grimes static void 770004c9c5dSGarance A Drosehn wrapup_clean(int laststatus __unused) 771004c9c5dSGarance A Drosehn { 772004c9c5dSGarance A Drosehn 773004c9c5dSGarance A Drosehn printf("Checked %d queues, and ", cln_queuecnt); 774004c9c5dSGarance A Drosehn if (cln_filecnt < 1) { 775004c9c5dSGarance A Drosehn printf("no cruft was found\n"); 776004c9c5dSGarance A Drosehn return; 777004c9c5dSGarance A Drosehn } 778004c9c5dSGarance A Drosehn if (cln_testonly) { 779004c9c5dSGarance A Drosehn printf("would have "); 780004c9c5dSGarance A Drosehn } 781004c9c5dSGarance A Drosehn printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt); 782004c9c5dSGarance A Drosehn } 783004c9c5dSGarance A Drosehn 784004c9c5dSGarance A Drosehn static void 785ba7a1ad7SGarance A Drosehn unlinkf(char *name) 786dea673e9SRodney W. Grimes { 787004c9c5dSGarance A Drosehn struct stat stbuf; 788004c9c5dSGarance A Drosehn double agemod, agestat; 789004c9c5dSGarance A Drosehn int res; 790004c9c5dSGarance A Drosehn char linkbuf[BUFSIZ]; 791004c9c5dSGarance A Drosehn 792004c9c5dSGarance A Drosehn /* 793004c9c5dSGarance A Drosehn * We have to use lstat() instead of stat(), in case this is a df* 794004c9c5dSGarance A Drosehn * "file" which is really a symlink due to 'lpr -s' processing. In 795004c9c5dSGarance A Drosehn * that case, we need to check the last-mod time of the symlink, and 796004c9c5dSGarance A Drosehn * not the file that the symlink is pointed at. 797004c9c5dSGarance A Drosehn */ 798360d4ad5SWarner Losh seteuid(euid); 799004c9c5dSGarance A Drosehn res = lstat(name, &stbuf); 800004c9c5dSGarance A Drosehn seteuid(uid); 801004c9c5dSGarance A Drosehn if (res < 0) { 802004c9c5dSGarance A Drosehn printf("\terror return from stat(%s):\n", name); 803004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 804004c9c5dSGarance A Drosehn return; 805004c9c5dSGarance A Drosehn } 806004c9c5dSGarance A Drosehn 807004c9c5dSGarance A Drosehn agemod = difftime(cln_now, stbuf.st_mtime); 808004c9c5dSGarance A Drosehn agestat = difftime(cln_now, stbuf.st_ctime); 809ceeaedd3SGarance A Drosehn if (cln_debug > 1) { 810004c9c5dSGarance A Drosehn /* this debugging-aid probably is not needed any more... */ 811004c9c5dSGarance A Drosehn printf("\t\t modify age=%g secs, stat age=%g secs\n", 812004c9c5dSGarance A Drosehn agemod, agestat); 813004c9c5dSGarance A Drosehn } 814004c9c5dSGarance A Drosehn if ((agemod <= cln_minage) && (agestat <= cln_minage)) 815004c9c5dSGarance A Drosehn return; 816004c9c5dSGarance A Drosehn 817004c9c5dSGarance A Drosehn /* 818004c9c5dSGarance A Drosehn * if this file is a symlink, then find out the target of the 819004c9c5dSGarance A Drosehn * symlink before unlink-ing the file itself 820004c9c5dSGarance A Drosehn */ 821004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 822004c9c5dSGarance A Drosehn seteuid(euid); 823004c9c5dSGarance A Drosehn res = readlink(name, linkbuf, sizeof(linkbuf)); 824004c9c5dSGarance A Drosehn seteuid(uid); 825004c9c5dSGarance A Drosehn if (res < 0) { 826004c9c5dSGarance A Drosehn printf("\terror return from readlink(%s):\n", name); 827004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 828004c9c5dSGarance A Drosehn return; 829004c9c5dSGarance A Drosehn } 830004c9c5dSGarance A Drosehn if (res == sizeof(linkbuf)) 831004c9c5dSGarance A Drosehn res--; 832004c9c5dSGarance A Drosehn linkbuf[res] = '\0'; 833004c9c5dSGarance A Drosehn } 834004c9c5dSGarance A Drosehn 835004c9c5dSGarance A Drosehn cln_filecnt++; 836004c9c5dSGarance A Drosehn cln_sizecnt += stbuf.st_size; 837004c9c5dSGarance A Drosehn 838004c9c5dSGarance A Drosehn if (cln_testonly) { 839004c9c5dSGarance A Drosehn printf("\twould remove %s\n", name); 840004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 841004c9c5dSGarance A Drosehn printf("\t (which is a symlink to %s)\n", linkbuf); 842004c9c5dSGarance A Drosehn } 843004c9c5dSGarance A Drosehn } else { 844004c9c5dSGarance A Drosehn seteuid(euid); 845004c9c5dSGarance A Drosehn res = unlink(name); 846004c9c5dSGarance A Drosehn seteuid(uid); 847004c9c5dSGarance A Drosehn if (res < 0) 848004c9c5dSGarance A Drosehn printf("\tcannot remove %s (!)\n", name); 849dea673e9SRodney W. Grimes else 850dea673e9SRodney W. Grimes printf("\tremoved %s\n", name); 851004c9c5dSGarance A Drosehn /* XXX 852004c9c5dSGarance A Drosehn * Note that for a df* file, this code should also check to see 853004c9c5dSGarance A Drosehn * if it is a symlink to some other file, and if the original 854004c9c5dSGarance A Drosehn * lpr command included '-r' ("remove file"). Of course, this 855004c9c5dSGarance A Drosehn * code would not be removing the df* file unless there was no 856004c9c5dSGarance A Drosehn * matching cf* file, and without the cf* file it is currently 857004c9c5dSGarance A Drosehn * impossible to determine if '-r' had been specified... 858004c9c5dSGarance A Drosehn * 859004c9c5dSGarance A Drosehn * As a result of this quandry, we may be leaving behind a 860004c9c5dSGarance A Drosehn * user's file that was supposed to have been removed after 861004c9c5dSGarance A Drosehn * being printed. This may effect services such as CAP or 862004c9c5dSGarance A Drosehn * samba, if they were configured to use 'lpr -r', and if 863004c9c5dSGarance A Drosehn * datafiles are not being properly removed. 864004c9c5dSGarance A Drosehn */ 865004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 866004c9c5dSGarance A Drosehn printf("\t (which was a symlink to %s)\n", linkbuf); 867004c9c5dSGarance A Drosehn } 868004c9c5dSGarance A Drosehn } 869dea673e9SRodney W. Grimes } 870dea673e9SRodney W. Grimes 871dea673e9SRodney W. Grimes /* 872e8e715faSGarance A Drosehn * Enable queuing to the printer (allow lpr to add new jobs to the queue). 873e8e715faSGarance A Drosehn */ 874e8e715faSGarance A Drosehn void 875e8e715faSGarance A Drosehn enable_q(struct printer *pp) 876e8e715faSGarance A Drosehn { 877e8e715faSGarance A Drosehn int setres; 878e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 879e8e715faSGarance A Drosehn 880e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 881e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 882e8e715faSGarance A Drosehn 883e8e715faSGarance A Drosehn setres = set_qstate(SQS_ENABLEQ, lf); 884e8e715faSGarance A Drosehn } 885e8e715faSGarance A Drosehn 886e8e715faSGarance A Drosehn /* 887dea673e9SRodney W. Grimes * Disable queuing. 888dea673e9SRodney W. Grimes */ 889dea673e9SRodney W. Grimes void 890e8e715faSGarance A Drosehn disable_q(struct printer *pp) 891e8e715faSGarance A Drosehn { 892e8e715faSGarance A Drosehn int setres; 893e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 894e8e715faSGarance A Drosehn 895e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 896e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 897e8e715faSGarance A Drosehn 898e8e715faSGarance A Drosehn setres = set_qstate(SQS_DISABLEQ, lf); 899e8e715faSGarance A Drosehn } 900e8e715faSGarance A Drosehn 901e8e715faSGarance A Drosehn /* 902dea673e9SRodney W. Grimes * Disable queuing and printing and put a message into the status file 9035b1c34fbSGarance A Drosehn * (reason for being down). If the user specified `-msg', then use 9045b1c34fbSGarance A Drosehn * everything after that as the message for the status file. If the 9055b1c34fbSGarance A Drosehn * user did NOT specify `-msg', then the command should take the first 9065b1c34fbSGarance A Drosehn * parameter as the printer name, and all remaining parameters as the 9075b1c34fbSGarance A Drosehn * message for the status file. (This is to be compatible with the 9085b1c34fbSGarance A Drosehn * original definition of 'down', which was implemented long before 9095b1c34fbSGarance A Drosehn * `-msg' was around). 9105b1c34fbSGarance A Drosehn */ 9115b1c34fbSGarance A Drosehn void 9125b1c34fbSGarance A Drosehn down_gi(int argc, char *argv[]) 9135b1c34fbSGarance A Drosehn { 9145b1c34fbSGarance A Drosehn 9155b1c34fbSGarance A Drosehn /* If `-msg' was specified, then this routine has nothing to do. */ 9165b1c34fbSGarance A Drosehn if (generic_msg != NULL) 9175b1c34fbSGarance A Drosehn return; 9185b1c34fbSGarance A Drosehn 9195b1c34fbSGarance A Drosehn /* 9205b1c34fbSGarance A Drosehn * If the user only gave one parameter, then use a default msg. 9215b1c34fbSGarance A Drosehn * (if argc == 1 at this point, then *argv == name of printer). 9225b1c34fbSGarance A Drosehn */ 9235b1c34fbSGarance A Drosehn if (argc == 1) { 9245b1c34fbSGarance A Drosehn generic_msg = strdup("printing disabled\n"); 9255b1c34fbSGarance A Drosehn return; 9265b1c34fbSGarance A Drosehn } 9275b1c34fbSGarance A Drosehn 9285b1c34fbSGarance A Drosehn /* 9295b1c34fbSGarance A Drosehn * The user specified multiple parameters, and did not specify 9305b1c34fbSGarance A Drosehn * `-msg'. Build a message from all the parameters after the 9315b1c34fbSGarance A Drosehn * first one (and nullify those parameters so generic-processing 9325b1c34fbSGarance A Drosehn * will not process them as printer-queue names). 9335b1c34fbSGarance A Drosehn */ 9345b1c34fbSGarance A Drosehn argc--; 9355b1c34fbSGarance A Drosehn argv++; 9365b1c34fbSGarance A Drosehn generic_msg = args2line(argc, argv); 9375b1c34fbSGarance A Drosehn for (; argc > 0; argc--, argv++) 9385b1c34fbSGarance A Drosehn *argv = generic_nullarg; /* "erase" it */ 9395b1c34fbSGarance A Drosehn } 9405b1c34fbSGarance A Drosehn 9415b1c34fbSGarance A Drosehn void 9425b1c34fbSGarance A Drosehn down_q(struct printer *pp) 9435b1c34fbSGarance A Drosehn { 9445b1c34fbSGarance A Drosehn int setres; 9455b1c34fbSGarance A Drosehn char lf[MAXPATHLEN]; 9465b1c34fbSGarance A Drosehn 9475b1c34fbSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 9485b1c34fbSGarance A Drosehn printf("%s:\n", pp->printer); 9495b1c34fbSGarance A Drosehn 9505b1c34fbSGarance A Drosehn setres = set_qstate(SQS_DISABLEQ+SQS_STOPP, lf); 9515b1c34fbSGarance A Drosehn if (setres >= 0) 9525b1c34fbSGarance A Drosehn upstat(pp, generic_msg, 1); 9535b1c34fbSGarance A Drosehn } 9545b1c34fbSGarance A Drosehn 9555b1c34fbSGarance A Drosehn /* 956dea673e9SRodney W. Grimes * Exit lpc 957dea673e9SRodney W. Grimes */ 958dea673e9SRodney W. Grimes void 959ba7a1ad7SGarance A Drosehn quit(int argc __unused, char *argv[] __unused) 960dea673e9SRodney W. Grimes { 961dea673e9SRodney W. Grimes exit(0); 962dea673e9SRodney W. Grimes } 963dea673e9SRodney W. Grimes 964dea673e9SRodney W. Grimes /* 965dea673e9SRodney W. Grimes * Kill and restart the daemon. 966dea673e9SRodney W. Grimes */ 967dea673e9SRodney W. Grimes void 968e8e715faSGarance A Drosehn restart_q(struct printer *pp) 969e8e715faSGarance A Drosehn { 970e8e715faSGarance A Drosehn int killres, setres, startok; 971e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 972e8e715faSGarance A Drosehn 973e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 974e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 975e8e715faSGarance A Drosehn 976e8e715faSGarance A Drosehn killres = kill_qtask(lf); 977e8e715faSGarance A Drosehn 978e8e715faSGarance A Drosehn /* 979e8e715faSGarance A Drosehn * XXX - if the kill worked, we should probably sleep for 980e8e715faSGarance A Drosehn * a second or so before trying to restart the queue. 981e8e715faSGarance A Drosehn */ 982e8e715faSGarance A Drosehn 983e8e715faSGarance A Drosehn /* make sure the queue is set to print jobs */ 984e8e715faSGarance A Drosehn setres = set_qstate(SQS_STARTP, lf); 985e8e715faSGarance A Drosehn 986e8e715faSGarance A Drosehn seteuid(euid); 987e8e715faSGarance A Drosehn startok = startdaemon(pp); 988e8e715faSGarance A Drosehn seteuid(uid); 989e8e715faSGarance A Drosehn if (!startok) 990e8e715faSGarance A Drosehn printf("\tcouldn't restart daemon\n"); 991e8e715faSGarance A Drosehn else 992e8e715faSGarance A Drosehn printf("\tdaemon restarted\n"); 993e8e715faSGarance A Drosehn } 994e8e715faSGarance A Drosehn 995e8e715faSGarance A Drosehn /* 99654032d11SGarance A Drosehn * Set the status message of each queue listed. Requires a "-msg" 99754032d11SGarance A Drosehn * parameter to indicate the end of the queue list and start of msg text. 99854032d11SGarance A Drosehn */ 99954032d11SGarance A Drosehn void 100054032d11SGarance A Drosehn setstatus_gi(int argc __unused, char *argv[] __unused) 100154032d11SGarance A Drosehn { 100254032d11SGarance A Drosehn 100354032d11SGarance A Drosehn if (generic_msg == NULL) { 100454032d11SGarance A Drosehn printf("You must specify '-msg' before the text of the new status message.\n"); 100554032d11SGarance A Drosehn generic_initerr = 1; 100654032d11SGarance A Drosehn } 100754032d11SGarance A Drosehn } 100854032d11SGarance A Drosehn 100954032d11SGarance A Drosehn void 101054032d11SGarance A Drosehn setstatus_q(struct printer *pp) 101154032d11SGarance A Drosehn { 1012*7574a1c1SGarance A Drosehn struct stat stbuf; 1013*7574a1c1SGarance A Drosehn int not_shown; 101454032d11SGarance A Drosehn char lf[MAXPATHLEN]; 101554032d11SGarance A Drosehn 101654032d11SGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 101754032d11SGarance A Drosehn printf("%s:\n", pp->printer); 101854032d11SGarance A Drosehn 101954032d11SGarance A Drosehn upstat(pp, generic_msg, 1); 1020*7574a1c1SGarance A Drosehn 1021*7574a1c1SGarance A Drosehn /* 1022*7574a1c1SGarance A Drosehn * Warn the user if 'lpq' will not display this new status-message. 1023*7574a1c1SGarance A Drosehn * Note that if lock file does not exist, then the queue is enabled 1024*7574a1c1SGarance A Drosehn * for both queuing and printing. 1025*7574a1c1SGarance A Drosehn */ 1026*7574a1c1SGarance A Drosehn not_shown = 1; 1027*7574a1c1SGarance A Drosehn if (stat(lf, &stbuf) >= 0) { 1028*7574a1c1SGarance A Drosehn if (stbuf.st_mode & LFM_PRINT_DIS) 1029*7574a1c1SGarance A Drosehn not_shown = 0; 1030*7574a1c1SGarance A Drosehn } 1031*7574a1c1SGarance A Drosehn if (not_shown) { 1032*7574a1c1SGarance A Drosehn printf("\tnote: This queue currently has printing enabled,\n"); 1033*7574a1c1SGarance A Drosehn printf("\t so this -msg will only be shown by 'lpq' if\n"); 1034*7574a1c1SGarance A Drosehn printf("\t a job is actively printing on it.\n"); 1035*7574a1c1SGarance A Drosehn } 103654032d11SGarance A Drosehn } 103754032d11SGarance A Drosehn 103854032d11SGarance A Drosehn /* 1039dea673e9SRodney W. Grimes * Enable printing on the specified printer and startup the daemon. 1040dea673e9SRodney W. Grimes */ 1041dea673e9SRodney W. Grimes void 1042e8e715faSGarance A Drosehn start_q(struct printer *pp) 1043e8e715faSGarance A Drosehn { 1044e8e715faSGarance A Drosehn int setres, startok; 1045e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1046e8e715faSGarance A Drosehn 1047e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1048e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1049e8e715faSGarance A Drosehn 1050e8e715faSGarance A Drosehn setres = set_qstate(SQS_STARTP, lf); 1051e8e715faSGarance A Drosehn 1052e8e715faSGarance A Drosehn seteuid(euid); 1053e8e715faSGarance A Drosehn startok = startdaemon(pp); 1054e8e715faSGarance A Drosehn seteuid(uid); 1055e8e715faSGarance A Drosehn if (!startok) 1056e8e715faSGarance A Drosehn printf("\tcouldn't start daemon\n"); 1057e8e715faSGarance A Drosehn else 1058e8e715faSGarance A Drosehn printf("\tdaemon started\n"); 1059e8e715faSGarance A Drosehn seteuid(uid); 1060e8e715faSGarance A Drosehn } 1061e8e715faSGarance A Drosehn 1062e8e715faSGarance A Drosehn /* 1063dea673e9SRodney W. Grimes * Print the status of the printer queue. 1064dea673e9SRodney W. Grimes */ 10654a1a0dbeSGarrett Wollman void 1066ba7a1ad7SGarance A Drosehn status(struct printer *pp) 1067dea673e9SRodney W. Grimes { 1068dea673e9SRodney W. Grimes struct stat stbuf; 1069dea673e9SRodney W. Grimes register int fd, i; 1070dea673e9SRodney W. Grimes register struct dirent *dp; 1071dea673e9SRodney W. Grimes DIR *dirp; 10724a1a0dbeSGarrett Wollman char file[MAXPATHLEN]; 1073dea673e9SRodney W. Grimes 10744a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 10754a1a0dbeSGarrett Wollman lock_file_name(pp, file, sizeof file); 10764a1a0dbeSGarrett Wollman if (stat(file, &stbuf) >= 0) { 1077dea673e9SRodney W. Grimes printf("\tqueuing is %s\n", 10784a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 10794a1a0dbeSGarrett Wollman : "enabled")); 1080dea673e9SRodney W. Grimes printf("\tprinting is %s\n", 10814a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 10824a1a0dbeSGarrett Wollman : "enabled")); 1083dea673e9SRodney W. Grimes } else { 1084dea673e9SRodney W. Grimes printf("\tqueuing is enabled\n"); 1085dea673e9SRodney W. Grimes printf("\tprinting is enabled\n"); 1086dea673e9SRodney W. Grimes } 10874a1a0dbeSGarrett Wollman if ((dirp = opendir(pp->spool_dir)) == NULL) { 1088dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 1089dea673e9SRodney W. Grimes return; 1090dea673e9SRodney W. Grimes } 1091dea673e9SRodney W. Grimes i = 0; 1092dea673e9SRodney W. Grimes while ((dp = readdir(dirp)) != NULL) { 1093dea673e9SRodney W. Grimes if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 1094dea673e9SRodney W. Grimes i++; 1095dea673e9SRodney W. Grimes } 1096dea673e9SRodney W. Grimes closedir(dirp); 1097dea673e9SRodney W. Grimes if (i == 0) 10984a1a0dbeSGarrett Wollman printf("\tno entries in spool area\n"); 1099dea673e9SRodney W. Grimes else if (i == 1) 1100dea673e9SRodney W. Grimes printf("\t1 entry in spool area\n"); 1101dea673e9SRodney W. Grimes else 1102dea673e9SRodney W. Grimes printf("\t%d entries in spool area\n", i); 11034a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY); 1104dea673e9SRodney W. Grimes if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 1105dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1106bc407914SWarner Losh printf("\tprinter idle\n"); 1107dea673e9SRodney W. Grimes return; 1108dea673e9SRodney W. Grimes } 1109dea673e9SRodney W. Grimes (void) close(fd); 111036abea5dSBrian Somers /* print out the contents of the status file, if it exists */ 11114a1a0dbeSGarrett Wollman status_file_name(pp, file, sizeof file); 11124a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY|O_SHLOCK); 1113dea673e9SRodney W. Grimes if (fd >= 0) { 111436abea5dSBrian Somers (void) fstat(fd, &stbuf); 111536abea5dSBrian Somers if (stbuf.st_size > 0) { 111636abea5dSBrian Somers putchar('\t'); 1117dea673e9SRodney W. Grimes while ((i = read(fd, line, sizeof(line))) > 0) 1118dea673e9SRodney W. Grimes (void) fwrite(line, 1, i, stdout); 111936abea5dSBrian Somers } 1120dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1121dea673e9SRodney W. Grimes } 1122dea673e9SRodney W. Grimes } 1123dea673e9SRodney W. Grimes 1124dea673e9SRodney W. Grimes /* 1125dea673e9SRodney W. Grimes * Stop the specified daemon after completing the current job and disable 1126dea673e9SRodney W. Grimes * printing. 1127dea673e9SRodney W. Grimes */ 1128dea673e9SRodney W. Grimes void 1129e8e715faSGarance A Drosehn stop_q(struct printer *pp) 1130e8e715faSGarance A Drosehn { 1131e8e715faSGarance A Drosehn int setres; 1132e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1133e8e715faSGarance A Drosehn 1134e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1135e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1136e8e715faSGarance A Drosehn 1137e8e715faSGarance A Drosehn setres = set_qstate(SQS_STOPP, lf); 1138e8e715faSGarance A Drosehn 113954032d11SGarance A Drosehn if (setres >= 0) 114054032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 1141e8e715faSGarance A Drosehn } 1142e8e715faSGarance A Drosehn 114330b4b758SGarance A Drosehn struct jobqueue **queue; 1144dea673e9SRodney W. Grimes int nitems; 1145dea673e9SRodney W. Grimes time_t mtime; 1146dea673e9SRodney W. Grimes 1147dea673e9SRodney W. Grimes /* 1148dea673e9SRodney W. Grimes * Put the specified jobs at the top of printer queue. 1149dea673e9SRodney W. Grimes */ 1150dea673e9SRodney W. Grimes void 1151ba7a1ad7SGarance A Drosehn topq(int argc, char *argv[]) 1152dea673e9SRodney W. Grimes { 1153dea673e9SRodney W. Grimes register int i; 1154dea673e9SRodney W. Grimes struct stat stbuf; 1155ba7a1ad7SGarance A Drosehn int cmdstatus, changed; 11564a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 1157dea673e9SRodney W. Grimes 1158dea673e9SRodney W. Grimes if (argc < 3) { 1159d3974088SDag-Erling Smørgrav printf("usage: topq printer [jobnum ...] [user ...]\n"); 1160dea673e9SRodney W. Grimes return; 1161dea673e9SRodney W. Grimes } 1162dea673e9SRodney W. Grimes 1163dea673e9SRodney W. Grimes --argc; 11644a1a0dbeSGarrett Wollman ++argv; 11654a1a0dbeSGarrett Wollman init_printer(pp); 1166ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 1167ba7a1ad7SGarance A Drosehn switch(cmdstatus) { 11684a1a0dbeSGarrett Wollman default: 11696d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 11704a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 11714a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 1172dea673e9SRodney W. Grimes return; 11734a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 11744a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)", *argv); 11754a1a0dbeSGarrett Wollman break; 11764a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 11774a1a0dbeSGarrett Wollman break; 11784a1a0dbeSGarrett Wollman } 11794a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1180dea673e9SRodney W. Grimes 1181360d4ad5SWarner Losh seteuid(euid); 11824a1a0dbeSGarrett Wollman if (chdir(pp->spool_dir) < 0) { 11834a1a0dbeSGarrett Wollman printf("\tcannot chdir to %s\n", pp->spool_dir); 1184360d4ad5SWarner Losh goto out; 1185dea673e9SRodney W. Grimes } 1186360d4ad5SWarner Losh seteuid(uid); 11874a1a0dbeSGarrett Wollman nitems = getq(pp, &queue); 1188dea673e9SRodney W. Grimes if (nitems == 0) 1189dea673e9SRodney W. Grimes return; 1190dea673e9SRodney W. Grimes changed = 0; 119130b4b758SGarance A Drosehn mtime = queue[0]->job_time; 1192dea673e9SRodney W. Grimes for (i = argc; --i; ) { 1193dea673e9SRodney W. Grimes if (doarg(argv[i]) == 0) { 1194dea673e9SRodney W. Grimes printf("\tjob %s is not in the queue\n", argv[i]); 1195dea673e9SRodney W. Grimes continue; 1196dea673e9SRodney W. Grimes } else 1197dea673e9SRodney W. Grimes changed++; 1198dea673e9SRodney W. Grimes } 1199dea673e9SRodney W. Grimes for (i = 0; i < nitems; i++) 1200dea673e9SRodney W. Grimes free(queue[i]); 1201dea673e9SRodney W. Grimes free(queue); 1202dea673e9SRodney W. Grimes if (!changed) { 1203dea673e9SRodney W. Grimes printf("\tqueue order unchanged\n"); 1204dea673e9SRodney W. Grimes return; 1205dea673e9SRodney W. Grimes } 1206dea673e9SRodney W. Grimes /* 1207dea673e9SRodney W. Grimes * Turn on the public execute bit of the lock file to 1208dea673e9SRodney W. Grimes * get lpd to rebuild the queue after the current job. 1209dea673e9SRodney W. Grimes */ 1210360d4ad5SWarner Losh seteuid(euid); 12114a1a0dbeSGarrett Wollman if (changed && stat(pp->lock_file, &stbuf) >= 0) 12124a1a0dbeSGarrett Wollman (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 1213360d4ad5SWarner Losh 1214360d4ad5SWarner Losh out: 1215360d4ad5SWarner Losh seteuid(uid); 1216dea673e9SRodney W. Grimes } 1217dea673e9SRodney W. Grimes 1218dea673e9SRodney W. Grimes /* 1219dea673e9SRodney W. Grimes * Reposition the job by changing the modification time of 1220dea673e9SRodney W. Grimes * the control file. 1221dea673e9SRodney W. Grimes */ 1222dea673e9SRodney W. Grimes static int 1223ba7a1ad7SGarance A Drosehn touch(struct jobqueue *jq) 1224dea673e9SRodney W. Grimes { 1225dea673e9SRodney W. Grimes struct timeval tvp[2]; 1226360d4ad5SWarner Losh int ret; 1227dea673e9SRodney W. Grimes 1228dea673e9SRodney W. Grimes tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1229dea673e9SRodney W. Grimes tvp[0].tv_usec = tvp[1].tv_usec = 0; 1230360d4ad5SWarner Losh seteuid(euid); 1231ba7a1ad7SGarance A Drosehn ret = utimes(jq->job_cfname, tvp); 1232360d4ad5SWarner Losh seteuid(uid); 1233360d4ad5SWarner Losh return (ret); 1234dea673e9SRodney W. Grimes } 1235dea673e9SRodney W. Grimes 1236dea673e9SRodney W. Grimes /* 1237dea673e9SRodney W. Grimes * Checks if specified job name is in the printer's queue. 1238dea673e9SRodney W. Grimes * Returns: negative (-1) if argument name is not in the queue. 1239dea673e9SRodney W. Grimes */ 1240dea673e9SRodney W. Grimes static int 1241ba7a1ad7SGarance A Drosehn doarg(char *job) 1242dea673e9SRodney W. Grimes { 124330b4b758SGarance A Drosehn register struct jobqueue **qq; 1244dea673e9SRodney W. Grimes register int jobnum, n; 1245dea673e9SRodney W. Grimes register char *cp, *machine; 1246dea673e9SRodney W. Grimes int cnt = 0; 1247dea673e9SRodney W. Grimes FILE *fp; 1248dea673e9SRodney W. Grimes 1249dea673e9SRodney W. Grimes /* 1250dea673e9SRodney W. Grimes * Look for a job item consisting of system name, colon, number 1251dea673e9SRodney W. Grimes * (example: ucbarpa:114) 1252dea673e9SRodney W. Grimes */ 1253f8eb25daSWarner Losh if ((cp = strchr(job, ':')) != NULL) { 1254dea673e9SRodney W. Grimes machine = job; 1255dea673e9SRodney W. Grimes *cp++ = '\0'; 1256dea673e9SRodney W. Grimes job = cp; 1257dea673e9SRodney W. Grimes } else 1258dea673e9SRodney W. Grimes machine = NULL; 1259dea673e9SRodney W. Grimes 1260dea673e9SRodney W. Grimes /* 1261dea673e9SRodney W. Grimes * Check for job specified by number (example: 112 or 235ucbarpa). 1262dea673e9SRodney W. Grimes */ 1263dea673e9SRodney W. Grimes if (isdigit(*job)) { 1264dea673e9SRodney W. Grimes jobnum = 0; 1265dea673e9SRodney W. Grimes do 1266dea673e9SRodney W. Grimes jobnum = jobnum * 10 + (*job++ - '0'); 1267dea673e9SRodney W. Grimes while (isdigit(*job)); 1268dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1269dea673e9SRodney W. Grimes n = 0; 127030b4b758SGarance A Drosehn for (cp = (*qq)->job_cfname+3; isdigit(*cp); ) 1271dea673e9SRodney W. Grimes n = n * 10 + (*cp++ - '0'); 1272dea673e9SRodney W. Grimes if (jobnum != n) 1273dea673e9SRodney W. Grimes continue; 1274dea673e9SRodney W. Grimes if (*job && strcmp(job, cp) != 0) 1275dea673e9SRodney W. Grimes continue; 1276dea673e9SRodney W. Grimes if (machine != NULL && strcmp(machine, cp) != 0) 1277dea673e9SRodney W. Grimes continue; 1278dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 127930b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1280dea673e9SRodney W. Grimes cnt++; 1281dea673e9SRodney W. Grimes } 1282dea673e9SRodney W. Grimes } 1283dea673e9SRodney W. Grimes return(cnt); 1284dea673e9SRodney W. Grimes } 1285dea673e9SRodney W. Grimes /* 1286dea673e9SRodney W. Grimes * Process item consisting of owner's name (example: henry). 1287dea673e9SRodney W. Grimes */ 1288dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1289360d4ad5SWarner Losh seteuid(euid); 129030b4b758SGarance A Drosehn fp = fopen((*qq)->job_cfname, "r"); 1291360d4ad5SWarner Losh seteuid(uid); 1292360d4ad5SWarner Losh if (fp == NULL) 1293dea673e9SRodney W. Grimes continue; 1294dea673e9SRodney W. Grimes while (getline(fp) > 0) 1295dea673e9SRodney W. Grimes if (line[0] == 'P') 1296dea673e9SRodney W. Grimes break; 1297dea673e9SRodney W. Grimes (void) fclose(fp); 1298dea673e9SRodney W. Grimes if (line[0] != 'P' || strcmp(job, line+1) != 0) 1299dea673e9SRodney W. Grimes continue; 1300dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 130130b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1302dea673e9SRodney W. Grimes cnt++; 1303dea673e9SRodney W. Grimes } 1304dea673e9SRodney W. Grimes } 1305dea673e9SRodney W. Grimes return(cnt); 1306dea673e9SRodney W. Grimes } 1307dea673e9SRodney W. Grimes 1308dea673e9SRodney W. Grimes /* 1309e8e715faSGarance A Drosehn * Enable both queuing & printing, and start printer (undo `down'). 1310e8e715faSGarance A Drosehn */ 1311e8e715faSGarance A Drosehn void 1312e8e715faSGarance A Drosehn up_q(struct printer *pp) 1313e8e715faSGarance A Drosehn { 1314e8e715faSGarance A Drosehn int setres, startok; 1315e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1316e8e715faSGarance A Drosehn 1317e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1318e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1319e8e715faSGarance A Drosehn 1320e8e715faSGarance A Drosehn setres = set_qstate(SQS_ENABLEQ+SQS_STARTP, lf); 1321e8e715faSGarance A Drosehn 1322e8e715faSGarance A Drosehn seteuid(euid); 1323e8e715faSGarance A Drosehn startok = startdaemon(pp); 1324e8e715faSGarance A Drosehn seteuid(uid); 1325e8e715faSGarance A Drosehn if (!startok) 1326e8e715faSGarance A Drosehn printf("\tcouldn't start daemon\n"); 1327e8e715faSGarance A Drosehn else 1328e8e715faSGarance A Drosehn printf("\tdaemon started\n"); 1329e8e715faSGarance A Drosehn } 1330