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 73e8e715faSGarance A Drosehn /* 74e8e715faSGarance A Drosehn * Return values from kill_qtask(). 75e8e715faSGarance A Drosehn */ 76e8e715faSGarance A Drosehn #define KQT_LFERROR -2 77e8e715faSGarance A Drosehn #define KQT_KILLFAIL -1 78e8e715faSGarance A Drosehn #define KQT_NODAEMON 0 79e8e715faSGarance A Drosehn #define KQT_KILLOK 1 80e8e715faSGarance A Drosehn 81ba7a1ad7SGarance A Drosehn static void abortpr(struct printer *_pp, int _dis); 8254032d11SGarance A Drosehn static char *args2line(int argc, char **argv); 83ba7a1ad7SGarance A Drosehn static int doarg(char *_job); 84ba7a1ad7SGarance A Drosehn static int doselect(struct dirent *_d); 85e8e715faSGarance A Drosehn static int kill_qtask(const char *lf); 86ba7a1ad7SGarance A Drosehn static void putmsg(struct printer *_pp, int _argc, char **_argv); 87ba7a1ad7SGarance A Drosehn static int sortq(const void *_a, const void *_b); 88ba7a1ad7SGarance A Drosehn static void startpr(struct printer *_pp, int _chgenable); 89ba7a1ad7SGarance A Drosehn static int touch(struct jobqueue *_jq); 90ba7a1ad7SGarance A Drosehn static void unlinkf(char *_name); 9154032d11SGarance A Drosehn static void upstat(struct printer *_pp, const char *_msg, int _notify); 92004c9c5dSGarance A Drosehn static void wrapup_clean(int _laststatus); 934a1a0dbeSGarrett Wollman 944a1a0dbeSGarrett Wollman /* 954a1a0dbeSGarrett Wollman * generic framework for commands which operate on all or a specified 964a1a0dbeSGarrett Wollman * set of printers 974a1a0dbeSGarrett Wollman */ 98004c9c5dSGarance A Drosehn enum qsel_val { /* how a given ptr was selected */ 99004c9c5dSGarance A Drosehn QSEL_UNKNOWN = -1, /* ... not selected yet */ 100004c9c5dSGarance A Drosehn QSEL_BYNAME = 0, /* ... user specifed it by name */ 101004c9c5dSGarance A Drosehn QSEL_ALL = 1 /* ... user wants "all" printers */ 102004c9c5dSGarance A Drosehn /* (with more to come) */ 103004c9c5dSGarance A Drosehn }; 104004c9c5dSGarance A Drosehn 105004c9c5dSGarance A Drosehn static enum qsel_val generic_qselect; /* indicates how ptr was selected */ 106004c9c5dSGarance A Drosehn static int generic_initerr; /* result of initrtn processing */ 107e7f478b2SGarance A Drosehn static char *generic_cmdname; 10854032d11SGarance A Drosehn static char *generic_msg; /* if a -msg was specified */ 109004c9c5dSGarance A Drosehn static char *generic_nullarg; 110004c9c5dSGarance A Drosehn static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */ 111004c9c5dSGarance A Drosehn 1124a1a0dbeSGarrett Wollman void 11354032d11SGarance A Drosehn generic(void (*specificrtn)(struct printer *_pp), int cmdopts, 114004c9c5dSGarance A Drosehn void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[]) 1154a1a0dbeSGarrett Wollman { 116004c9c5dSGarance A Drosehn int cmdstatus, more, targc; 117004c9c5dSGarance A Drosehn struct printer myprinter, *pp; 118e7f478b2SGarance A Drosehn char **margv, **targv; 1194a1a0dbeSGarrett Wollman 1204a1a0dbeSGarrett Wollman if (argc == 1) { 1215b1c34fbSGarance A Drosehn /* 1225b1c34fbSGarance A Drosehn * Usage needs a special case for 'down': The user must 1235b1c34fbSGarance A Drosehn * either include `-msg', or only the first parameter 1245b1c34fbSGarance A Drosehn * that they give will be processed as a printer name. 1255b1c34fbSGarance A Drosehn */ 12654032d11SGarance A Drosehn printf("usage: %s {all | printer ...}", argv[0]); 1275b1c34fbSGarance A Drosehn if (strcmp(argv[0], "down") == 0) { 1285b1c34fbSGarance A Drosehn printf(" -msg [<text> ...]\n"); 1295b1c34fbSGarance A Drosehn printf(" or: down {all | printer} [<text> ...]"); 1305b1c34fbSGarance A Drosehn } else if (cmdopts & LPC_MSGOPT) 13154032d11SGarance A Drosehn printf(" [-msg <text> ...]"); 13254032d11SGarance A Drosehn printf("\n"); 1334a1a0dbeSGarrett Wollman return; 1344a1a0dbeSGarrett Wollman } 135004c9c5dSGarance A Drosehn 136e7f478b2SGarance A Drosehn /* The first argument is the command name. */ 137e7f478b2SGarance A Drosehn generic_cmdname = *argv++; 138e7f478b2SGarance A Drosehn argc--; 139e7f478b2SGarance A Drosehn 140004c9c5dSGarance A Drosehn /* 141004c9c5dSGarance A Drosehn * The initialization routine for a command might set a generic 142004c9c5dSGarance A Drosehn * "wrapup" routine, which should be called after processing all 143004c9c5dSGarance A Drosehn * the printers in the command. This might print summary info. 144004c9c5dSGarance A Drosehn * 145004c9c5dSGarance A Drosehn * Note that the initialization routine may also parse (and 146004c9c5dSGarance A Drosehn * nullify) some of the parameters given on the command, leaving 147004c9c5dSGarance A Drosehn * only the parameters which have to do with printer names. 148004c9c5dSGarance A Drosehn */ 149004c9c5dSGarance A Drosehn pp = &myprinter; 150004c9c5dSGarance A Drosehn generic_wrapup = NULL; 151004c9c5dSGarance A Drosehn generic_qselect = QSEL_UNKNOWN; 152004c9c5dSGarance A Drosehn cmdstatus = 0; 153004c9c5dSGarance A Drosehn /* this just needs to be a distinct value of type 'char *' */ 154004c9c5dSGarance A Drosehn if (generic_nullarg == NULL) 155004c9c5dSGarance A Drosehn generic_nullarg = strdup(""); 156004c9c5dSGarance A Drosehn 15754032d11SGarance A Drosehn /* 15854032d11SGarance A Drosehn * Some commands accept a -msg argument, which indicates that 15954032d11SGarance A Drosehn * all remaining arguments should be combined into a string. 16054032d11SGarance A Drosehn */ 16154032d11SGarance A Drosehn generic_msg = NULL; 16254032d11SGarance A Drosehn if (cmdopts & LPC_MSGOPT) { 16354032d11SGarance A Drosehn targc = argc; 16454032d11SGarance A Drosehn targv = argv; 165e7f478b2SGarance A Drosehn for (; targc > 0; targc--, targv++) { 16654032d11SGarance A Drosehn if (strcmp(*targv, "-msg") == 0) { 16754032d11SGarance A Drosehn argc -= targc; 16854032d11SGarance A Drosehn generic_msg = args2line(targc - 1, targv + 1); 16954032d11SGarance A Drosehn break; 17054032d11SGarance A Drosehn } 17154032d11SGarance A Drosehn } 17254032d11SGarance A Drosehn } 17354032d11SGarance A Drosehn 174004c9c5dSGarance A Drosehn /* call initialization routine, if there is one for this cmd */ 175004c9c5dSGarance A Drosehn if (initrtn != NULL) { 176004c9c5dSGarance A Drosehn generic_initerr = 0; 177004c9c5dSGarance A Drosehn (*initrtn)(argc, argv); 178004c9c5dSGarance A Drosehn if (generic_initerr) 179004c9c5dSGarance A Drosehn return; 180e7f478b2SGarance A Drosehn /* 181e7f478b2SGarance A Drosehn * The initrtn may have null'ed out some of the parameters. 182e7f478b2SGarance A Drosehn * Compact the parameter list to remove those nulls, and 183e7f478b2SGarance A Drosehn * correct the arg-count. 184e7f478b2SGarance A Drosehn */ 185004c9c5dSGarance A Drosehn targc = argc; 186004c9c5dSGarance A Drosehn targv = argv; 187e7f478b2SGarance A Drosehn margv = argv; 188e7f478b2SGarance A Drosehn argc = 0; 189e7f478b2SGarance A Drosehn for (; targc > 0; targc--, targv++) { 190e7f478b2SGarance A Drosehn if (*targv != generic_nullarg) { 191e7f478b2SGarance A Drosehn if (targv != margv) 192e7f478b2SGarance A Drosehn *margv = *targv; 193e7f478b2SGarance A Drosehn margv++; 194e7f478b2SGarance A Drosehn argc++; 195004c9c5dSGarance A Drosehn } 196004c9c5dSGarance A Drosehn } 197004c9c5dSGarance A Drosehn } 198004c9c5dSGarance A Drosehn 199e7f478b2SGarance A Drosehn if (argc == 1 && strcmp(*argv, "all") == 0) { 200004c9c5dSGarance A Drosehn generic_qselect = QSEL_ALL; 201ba7a1ad7SGarance A Drosehn more = firstprinter(pp, &cmdstatus); 202ba7a1ad7SGarance A Drosehn if (cmdstatus) 2034a1a0dbeSGarrett Wollman goto looperr; 2044a1a0dbeSGarrett Wollman while (more) { 205ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 2064a1a0dbeSGarrett Wollman do { 207ba7a1ad7SGarance A Drosehn more = nextprinter(pp, &cmdstatus); 2084a1a0dbeSGarrett Wollman looperr: 209ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 2104a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 2114a1a0dbeSGarrett Wollman printf("warning: %s: unresolved " 2124a1a0dbeSGarrett Wollman "tc= reference(s) ", 2134a1a0dbeSGarrett Wollman pp->printer); 2144a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 2154a1a0dbeSGarrett Wollman break; 2164a1a0dbeSGarrett Wollman default: 2176d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 2184a1a0dbeSGarrett Wollman } 219ba7a1ad7SGarance A Drosehn } while (more && cmdstatus); 2204a1a0dbeSGarrett Wollman } 221004c9c5dSGarance A Drosehn goto wrapup; 2224a1a0dbeSGarrett Wollman } 223004c9c5dSGarance A Drosehn 224004c9c5dSGarance A Drosehn generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */ 225e7f478b2SGarance A Drosehn for (; argc > 0; argc--, argv++) { 2264a1a0dbeSGarrett Wollman init_printer(pp); 227ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 228ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 2294a1a0dbeSGarrett Wollman default: 2306d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 2314a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 2324a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 2334a1a0dbeSGarrett Wollman continue; 2344a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 2354a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)\n", 2364a1a0dbeSGarrett Wollman *argv); 2374a1a0dbeSGarrett Wollman break; 2384a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 2394a1a0dbeSGarrett Wollman break; 2404a1a0dbeSGarrett Wollman } 241ba7a1ad7SGarance A Drosehn (*specificrtn)(pp); 2424a1a0dbeSGarrett Wollman } 243004c9c5dSGarance A Drosehn 244004c9c5dSGarance A Drosehn wrapup: 245004c9c5dSGarance A Drosehn if (generic_wrapup) { 246004c9c5dSGarance A Drosehn (*generic_wrapup)(cmdstatus); 247004c9c5dSGarance A Drosehn } 24854032d11SGarance A Drosehn if (generic_msg) 24954032d11SGarance A Drosehn free(generic_msg); 25054032d11SGarance A Drosehn } 251004c9c5dSGarance A Drosehn 25254032d11SGarance A Drosehn /* 25354032d11SGarance A Drosehn * Convert an argv-array of character strings into a single string. 25454032d11SGarance A Drosehn */ 25554032d11SGarance A Drosehn static char * 25654032d11SGarance A Drosehn args2line(int argc, char **argv) 25754032d11SGarance A Drosehn { 25854032d11SGarance A Drosehn char *cp1, *cend; 25954032d11SGarance A Drosehn const char *cp2; 26054032d11SGarance A Drosehn char buf[1024]; 26154032d11SGarance A Drosehn 26254032d11SGarance A Drosehn if (argc <= 0) 26354032d11SGarance A Drosehn return strdup("\n"); 26454032d11SGarance A Drosehn 26554032d11SGarance A Drosehn cp1 = buf; 26654032d11SGarance A Drosehn cend = buf + sizeof(buf) - 1; /* save room for '\0' */ 26754032d11SGarance A Drosehn while (--argc >= 0) { 26854032d11SGarance A Drosehn cp2 = *argv++; 26954032d11SGarance A Drosehn while ((cp1 < cend) && (*cp1++ = *cp2++)) 27054032d11SGarance A Drosehn ; 27154032d11SGarance A Drosehn cp1[-1] = ' '; 27254032d11SGarance A Drosehn } 27354032d11SGarance A Drosehn cp1[-1] = '\n'; 27454032d11SGarance A Drosehn *cp1 = '\0'; 27554032d11SGarance A Drosehn return strdup(buf); 2764a1a0dbeSGarrett Wollman } 277dea673e9SRodney W. Grimes 278dea673e9SRodney W. Grimes /* 279dea673e9SRodney W. Grimes * kill an existing daemon and disable printing. 280dea673e9SRodney W. Grimes */ 281dea673e9SRodney W. Grimes void 282ba7a1ad7SGarance A Drosehn doabort(struct printer *pp) 283dea673e9SRodney W. Grimes { 2844a1a0dbeSGarrett Wollman abortpr(pp, 1); 285dea673e9SRodney W. Grimes } 286dea673e9SRodney W. Grimes 287dea673e9SRodney W. Grimes static void 288ba7a1ad7SGarance A Drosehn abortpr(struct printer *pp, int dis) 289dea673e9SRodney W. Grimes { 290dea673e9SRodney W. Grimes register FILE *fp; 291dea673e9SRodney W. Grimes struct stat stbuf; 292dea673e9SRodney W. Grimes int pid, fd; 2934a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 294dea673e9SRodney W. Grimes 2954a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 2964a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 297dea673e9SRodney W. Grimes 298dea673e9SRodney W. Grimes /* 299dea673e9SRodney W. Grimes * Turn on the owner execute bit of the lock file to disable printing. 300dea673e9SRodney W. Grimes */ 301dea673e9SRodney W. Grimes if (dis) { 302360d4ad5SWarner Losh seteuid(euid); 3034a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 3044a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 3054a1a0dbeSGarrett Wollman printf("\tcannot disable printing: %s\n", 3064a1a0dbeSGarrett Wollman strerror(errno)); 307dea673e9SRodney W. Grimes else { 30854032d11SGarance A Drosehn /* ..call newer upstat() in obsolete code.. */ 30954032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 31054032d11SGarance A Drosehn /* ..the new upstat() did a setuid(uid).. */ 31154032d11SGarance A Drosehn seteuid(euid); 312dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 313dea673e9SRodney W. Grimes } 314dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 3154a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 3164a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 3174a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 3184a1a0dbeSGarrett Wollman strerror(errno)); 319dea673e9SRodney W. Grimes else { 320dea673e9SRodney W. Grimes (void) close(fd); 32154032d11SGarance A Drosehn /* ..call newer upstat() in obsolete code.. */ 32254032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 32354032d11SGarance A Drosehn /* ..the new upstat() did a setuid(uid).. */ 32454032d11SGarance A Drosehn seteuid(euid); 325dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 326dea673e9SRodney W. Grimes printf("\tno daemon to abort\n"); 327dea673e9SRodney W. Grimes } 328360d4ad5SWarner Losh goto out; 329dea673e9SRodney W. Grimes } else { 330dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 331360d4ad5SWarner Losh goto out; 332dea673e9SRodney W. Grimes } 333dea673e9SRodney W. Grimes } 334dea673e9SRodney W. Grimes /* 335dea673e9SRodney W. Grimes * Kill the current daemon to stop printing now. 336dea673e9SRodney W. Grimes */ 3374a1a0dbeSGarrett Wollman if ((fp = fopen(lf, "r")) == NULL) { 338dea673e9SRodney W. Grimes printf("\tcannot open lock file\n"); 339360d4ad5SWarner Losh goto out; 340dea673e9SRodney W. Grimes } 341dea673e9SRodney W. Grimes if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 342dea673e9SRodney W. Grimes (void) fclose(fp); /* unlocks as well */ 343dea673e9SRodney W. Grimes printf("\tno daemon to abort\n"); 344360d4ad5SWarner Losh goto out; 345dea673e9SRodney W. Grimes } 346dea673e9SRodney W. Grimes (void) fclose(fp); 347360d4ad5SWarner Losh if (kill(pid = atoi(line), SIGTERM) < 0) { 348360d4ad5SWarner Losh if (errno == ESRCH) 349360d4ad5SWarner Losh printf("\tno daemon to abort\n"); 350dea673e9SRodney W. Grimes else 351360d4ad5SWarner Losh printf("\tWarning: daemon (pid %d) not killed\n", pid); 352360d4ad5SWarner Losh } else 353dea673e9SRodney W. Grimes printf("\tdaemon (pid %d) killed\n", pid); 354360d4ad5SWarner Losh out: 355360d4ad5SWarner Losh seteuid(uid); 356dea673e9SRodney W. Grimes } 357dea673e9SRodney W. Grimes 358dea673e9SRodney W. Grimes /* 359e8e715faSGarance A Drosehn * Kill the current daemon, to stop printing of the active job. 360e8e715faSGarance A Drosehn */ 361e8e715faSGarance A Drosehn static int 362e8e715faSGarance A Drosehn kill_qtask(const char *lf) 363e8e715faSGarance A Drosehn { 364e8e715faSGarance A Drosehn FILE *fp; 365e8e715faSGarance A Drosehn pid_t pid; 366e8e715faSGarance A Drosehn int errsav, killres, lockres, res; 367e8e715faSGarance A Drosehn 368e8e715faSGarance A Drosehn seteuid(euid); 369e8e715faSGarance A Drosehn fp = fopen(lf, "r"); 370e8e715faSGarance A Drosehn errsav = errno; 371e8e715faSGarance A Drosehn seteuid(uid); 372e8e715faSGarance A Drosehn res = KQT_NODAEMON; 373e8e715faSGarance A Drosehn if (fp == NULL) { 374e8e715faSGarance A Drosehn /* 375e8e715faSGarance A Drosehn * If there is no lock file, then there is no daemon to 376e8e715faSGarance A Drosehn * kill. Any other error return means there is some 377e8e715faSGarance A Drosehn * kind of problem with the lock file. 378e8e715faSGarance A Drosehn */ 379e8e715faSGarance A Drosehn if (errsav != ENOENT) 380e8e715faSGarance A Drosehn res = KQT_LFERROR; 381e8e715faSGarance A Drosehn goto killdone; 382e8e715faSGarance A Drosehn } 383e8e715faSGarance A Drosehn 384e8e715faSGarance A Drosehn /* If the lock file is empty, then there is no daemon to kill */ 385e8e715faSGarance A Drosehn if (getline(fp) == 0) 386e8e715faSGarance A Drosehn goto killdone; 387e8e715faSGarance A Drosehn 388e8e715faSGarance A Drosehn /* 389e8e715faSGarance A Drosehn * If the file can be locked without blocking, then there 390e8e715faSGarance A Drosehn * no daemon to kill, or we should not try to kill it. 391e8e715faSGarance A Drosehn * 392e8e715faSGarance A Drosehn * XXX - not sure I understand the reasoning behind this... 393e8e715faSGarance A Drosehn */ 394e8e715faSGarance A Drosehn lockres = flock(fileno(fp), LOCK_SH|LOCK_NB); 395e8e715faSGarance A Drosehn (void) fclose(fp); 396e8e715faSGarance A Drosehn if (lockres == 0) 397e8e715faSGarance A Drosehn goto killdone; 398e8e715faSGarance A Drosehn 399e8e715faSGarance A Drosehn pid = atoi(line); 400e8e715faSGarance A Drosehn if (pid < 0) { 401e8e715faSGarance A Drosehn /* 402e8e715faSGarance A Drosehn * If we got a negative pid, then the contents of the 403e8e715faSGarance A Drosehn * lock file is not valid. 404e8e715faSGarance A Drosehn */ 405e8e715faSGarance A Drosehn res = KQT_LFERROR; 406e8e715faSGarance A Drosehn goto killdone; 407e8e715faSGarance A Drosehn } 408e8e715faSGarance A Drosehn 409e8e715faSGarance A Drosehn seteuid(uid); 410e8e715faSGarance A Drosehn killres = kill(pid, SIGTERM); 411e8e715faSGarance A Drosehn errsav = errno; 412e8e715faSGarance A Drosehn seteuid(uid); 413e8e715faSGarance A Drosehn if (killres == 0) { 414e8e715faSGarance A Drosehn res = KQT_KILLOK; 415e8e715faSGarance A Drosehn printf("\tdaemon (pid %d) killed\n", pid); 416e8e715faSGarance A Drosehn } else if (errno == ESRCH) { 417e8e715faSGarance A Drosehn res = KQT_NODAEMON; 418e8e715faSGarance A Drosehn } else { 419e8e715faSGarance A Drosehn res = KQT_KILLFAIL; 420e8e715faSGarance A Drosehn printf("\tWarning: daemon (pid %d) not killed:\n", pid); 421e8e715faSGarance A Drosehn printf("\t %s\n", strerror(errsav)); 422e8e715faSGarance A Drosehn } 423e8e715faSGarance A Drosehn 424e8e715faSGarance A Drosehn killdone: 425e8e715faSGarance A Drosehn switch (res) { 426e8e715faSGarance A Drosehn case KQT_LFERROR: 427e8e715faSGarance A Drosehn printf("\tcannot open lock file: %s\n", 428e8e715faSGarance A Drosehn strerror(errsav)); 429e8e715faSGarance A Drosehn break; 430e8e715faSGarance A Drosehn case KQT_NODAEMON: 431e8e715faSGarance A Drosehn printf("\tno daemon to abort\n"); 432e8e715faSGarance A Drosehn break; 433e8e715faSGarance A Drosehn case KQT_KILLFAIL: 434e8e715faSGarance A Drosehn case KQT_KILLOK: 435e8e715faSGarance A Drosehn /* These two already printed messages to the user. */ 436e8e715faSGarance A Drosehn break; 437e8e715faSGarance A Drosehn default: 438e8e715faSGarance A Drosehn printf("\t<internal error in kill_qtask>\n"); 439e8e715faSGarance A Drosehn break; 440e8e715faSGarance A Drosehn } 441e8e715faSGarance A Drosehn 442e8e715faSGarance A Drosehn return (res); 443e8e715faSGarance A Drosehn } 444e8e715faSGarance A Drosehn 445e8e715faSGarance A Drosehn /* 446dea673e9SRodney W. Grimes * Write a message into the status file. 447dea673e9SRodney W. Grimes */ 448dea673e9SRodney W. Grimes static void 44954032d11SGarance A Drosehn upstat(struct printer *pp, const char *msg, int notifyuser) 450dea673e9SRodney W. Grimes { 45154032d11SGarance A Drosehn int fd; 4525f87a7b6SWarner Losh char statfile[MAXPATHLEN]; 453dea673e9SRodney W. Grimes 4544a1a0dbeSGarrett Wollman status_file_name(pp, statfile, sizeof statfile); 455dea673e9SRodney W. Grimes umask(0); 45654032d11SGarance A Drosehn seteuid(euid); 4574a1a0dbeSGarrett Wollman fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 45854032d11SGarance A Drosehn seteuid(uid); 4594a1a0dbeSGarrett Wollman if (fd < 0) { 4604a1a0dbeSGarrett Wollman printf("\tcannot create status file: %s\n", strerror(errno)); 461dea673e9SRodney W. Grimes return; 462dea673e9SRodney W. Grimes } 463dea673e9SRodney W. Grimes (void) ftruncate(fd, 0); 464dea673e9SRodney W. Grimes if (msg == (char *)NULL) 465dea673e9SRodney W. Grimes (void) write(fd, "\n", 1); 466dea673e9SRodney W. Grimes else 467dea673e9SRodney W. Grimes (void) write(fd, msg, strlen(msg)); 468dea673e9SRodney W. Grimes (void) close(fd); 46954032d11SGarance A Drosehn if (notifyuser) { 47054032d11SGarance A Drosehn if ((msg == (char *)NULL) || (strcmp(msg, "\n") == 0)) 47154032d11SGarance A Drosehn printf("\tstatus message is now set to nothing.\n"); 47254032d11SGarance A Drosehn else 47354032d11SGarance A Drosehn printf("\tstatus message is now: %s", msg); 47454032d11SGarance A Drosehn } 475dea673e9SRodney W. Grimes } 476dea673e9SRodney W. Grimes 477004c9c5dSGarance A Drosehn /* 478e8e715faSGarance A Drosehn * kill an existing daemon and disable printing. 479e8e715faSGarance A Drosehn */ 480e8e715faSGarance A Drosehn void 481e8e715faSGarance A Drosehn abort_q(struct printer *pp) 482e8e715faSGarance A Drosehn { 483e8e715faSGarance A Drosehn int killres, setres; 484e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 485e8e715faSGarance A Drosehn 486e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 487e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 488e8e715faSGarance A Drosehn 489e8e715faSGarance A Drosehn /* 490e8e715faSGarance A Drosehn * Turn on the owner execute bit of the lock file to disable printing. 491e8e715faSGarance A Drosehn */ 492e8e715faSGarance A Drosehn setres = set_qstate(SQS_STOPP, lf); 493e8e715faSGarance A Drosehn 494e8e715faSGarance A Drosehn /* 495e8e715faSGarance A Drosehn * If set_qstate found that there already was a lock file, then 496e8e715faSGarance A Drosehn * call a routine which will read that lock file and kill the 497e8e715faSGarance A Drosehn * lpd-process which is listed in that lock file. If the lock 498e8e715faSGarance A Drosehn * file did not exist, then either there is no daemon running 499e8e715faSGarance A Drosehn * for this queue, or there is one running but *it* could not 500e8e715faSGarance A Drosehn * write a lock file (which means we can not determine the 501e8e715faSGarance A Drosehn * process id of that lpd-process). 502e8e715faSGarance A Drosehn */ 503e8e715faSGarance A Drosehn switch (setres) { 504e8e715faSGarance A Drosehn case SQS_CHGOK: 505e8e715faSGarance A Drosehn case SQS_CHGFAIL: 506e8e715faSGarance A Drosehn /* Kill the process */ 507e8e715faSGarance A Drosehn killres = kill_qtask(lf); 508e8e715faSGarance A Drosehn break; 509e8e715faSGarance A Drosehn case SQS_CREOK: 510e8e715faSGarance A Drosehn case SQS_CREFAIL: 511e8e715faSGarance A Drosehn printf("\tno daemon to abort\n"); 512e8e715faSGarance A Drosehn break; 513e8e715faSGarance A Drosehn case SQS_STATFAIL: 514e8e715faSGarance A Drosehn printf("\tassuming no daemon to abort\n"); 515e8e715faSGarance A Drosehn break; 516e8e715faSGarance A Drosehn default: 517e8e715faSGarance A Drosehn printf("\t<unexpected result (%d) from set_qstate>\n", 518e8e715faSGarance A Drosehn setres); 519e8e715faSGarance A Drosehn break; 520e8e715faSGarance A Drosehn } 521e8e715faSGarance A Drosehn 52254032d11SGarance A Drosehn if (setres >= 0) 52354032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 524e8e715faSGarance A Drosehn } 525e8e715faSGarance A Drosehn 526e8e715faSGarance A Drosehn /* 527004c9c5dSGarance A Drosehn * "global" variables for all the routines related to 'clean' and 'tclean' 528004c9c5dSGarance A Drosehn */ 529004c9c5dSGarance A Drosehn static time_t cln_now; /* current time */ 530004c9c5dSGarance A Drosehn static double cln_minage; /* minimum age before file is removed */ 531004c9c5dSGarance A Drosehn static long cln_sizecnt; /* amount of space freed up */ 532004c9c5dSGarance A Drosehn static int cln_debug; /* print extra debugging msgs */ 533004c9c5dSGarance A Drosehn static int cln_filecnt; /* number of files destroyed */ 534004c9c5dSGarance A Drosehn static int cln_foundcore; /* found a core file! */ 535004c9c5dSGarance A Drosehn static int cln_queuecnt; /* number of queues checked */ 536004c9c5dSGarance A Drosehn static int cln_testonly; /* remove-files vs just-print-info */ 537004c9c5dSGarance A Drosehn 538dea673e9SRodney W. Grimes static int 539ba7a1ad7SGarance A Drosehn doselect(struct dirent *d) 540dea673e9SRodney W. Grimes { 541dea673e9SRodney W. Grimes int c = d->d_name[0]; 542dea673e9SRodney W. Grimes 5431fd731faSGarance A Drosehn if ((c == 'c' || c == 'd' || c == 'r' || c == 't') && 5441fd731faSGarance A Drosehn d->d_name[1] == 'f') 545004c9c5dSGarance A Drosehn return 1; 546004c9c5dSGarance A Drosehn if (c == 'c') { 547004c9c5dSGarance A Drosehn if (!strcmp(d->d_name, "core")) 548004c9c5dSGarance A Drosehn cln_foundcore = 1; 549004c9c5dSGarance A Drosehn } 550004c9c5dSGarance A Drosehn if (c == 'e') { 551004c9c5dSGarance A Drosehn if (!strncmp(d->d_name, "errs.", 5)) 552004c9c5dSGarance A Drosehn return 1; 553004c9c5dSGarance A Drosehn } 554004c9c5dSGarance A Drosehn return 0; 555dea673e9SRodney W. Grimes } 556dea673e9SRodney W. Grimes 557dea673e9SRodney W. Grimes /* 558ceeaedd3SGarance A Drosehn * Comparison routine that clean_q() uses for scandir. 559ceeaedd3SGarance A Drosehn * 560ceeaedd3SGarance A Drosehn * The purpose of this sort is to have all `df' files end up immediately 5611fd731faSGarance A Drosehn * after the matching `cf' file. For files matching `cf', `df', `rf', or 5621fd731faSGarance A Drosehn * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or 5631fd731faSGarance A Drosehn * `tf', and then by the sequence letter (which is A-Z, or a-z). This 5641fd731faSGarance A Drosehn * routine may also see filenames which do not start with `cf', `df', `rf', 5651fd731faSGarance A Drosehn * or `tf' (such as `errs.*'), and those are simply sorted by the full 5661fd731faSGarance A Drosehn * filename. 5671fd731faSGarance A Drosehn * 5681fd731faSGarance A Drosehn * XXX 5691fd731faSGarance A Drosehn * This assumes that all control files start with `cfA*', and it turns 5701fd731faSGarance A Drosehn * out there are a few implementations of lpr which will create `cfB*' 5711fd731faSGarance A Drosehn * filenames (they will have datafile names which start with `dfB*'). 572dea673e9SRodney W. Grimes */ 573dea673e9SRodney W. Grimes static int 574ba7a1ad7SGarance A Drosehn sortq(const void *a, const void *b) 575dea673e9SRodney W. Grimes { 576ceeaedd3SGarance A Drosehn const int a_lt_b = -1, a_gt_b = 1, cat_other = 10; 577ceeaedd3SGarance A Drosehn const char *fname_a, *fname_b, *jnum_a, *jnum_b; 578ceeaedd3SGarance A Drosehn int cat_a, cat_b, ch, res, seq_a, seq_b; 579dea673e9SRodney W. Grimes 580f0baf665SGarance A Drosehn fname_a = (*(const struct dirent * const *)a)->d_name; 581f0baf665SGarance A Drosehn fname_b = (*(const struct dirent * const *)b)->d_name; 582ceeaedd3SGarance A Drosehn 583ceeaedd3SGarance A Drosehn /* 584ceeaedd3SGarance A Drosehn * First separate filenames into cagatories. Catagories are 5851fd731faSGarance A Drosehn * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in 5861fd731faSGarance A Drosehn * that order. It is critical that the mapping be exactly the 5871fd731faSGarance A Drosehn * same for 'a' vs 'b', so define a macro for the job. 588ceeaedd3SGarance A Drosehn * 589ceeaedd3SGarance A Drosehn * [aside: the standard `cf' file has the jobnumber start in 590ceeaedd3SGarance A Drosehn * position 4, but some implementations have that as an extra 591ceeaedd3SGarance A Drosehn * file-sequence letter, and start the job number in position 5.] 592ceeaedd3SGarance A Drosehn */ 593ceeaedd3SGarance A Drosehn #define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \ 594ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 595ceeaedd3SGarance A Drosehn ch = *(fname_X + 2); \ 596ceeaedd3SGarance A Drosehn jnum_X = fname_X + 3; \ 5974f7f8234SGarance A Drosehn seq_X = 0; \ 598ceeaedd3SGarance A Drosehn if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \ 599ceeaedd3SGarance A Drosehn seq_X = ch; \ 600ceeaedd3SGarance A Drosehn if (*fname_X == 'c') \ 601ceeaedd3SGarance A Drosehn cat_X = 1; \ 602ceeaedd3SGarance A Drosehn else if (*fname_X == 'd') \ 603ceeaedd3SGarance A Drosehn cat_X = 2; \ 6041fd731faSGarance A Drosehn else if (*fname_X == 'r') \ 605ceeaedd3SGarance A Drosehn cat_X = 3; \ 6061fd731faSGarance A Drosehn else if (*fname_X == 't') \ 6071fd731faSGarance A Drosehn cat_X = 4; \ 608ceeaedd3SGarance A Drosehn if (cat_X != cat_other) { \ 609ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 610ceeaedd3SGarance A Drosehn if (!isdigit(ch)) { \ 611ceeaedd3SGarance A Drosehn if (isalpha(ch)) { \ 612ceeaedd3SGarance A Drosehn jnum_X++; \ 613ceeaedd3SGarance A Drosehn ch = *jnum_X; \ 614ceeaedd3SGarance A Drosehn seq_X = (seq_X << 8) + ch; \ 615ceeaedd3SGarance A Drosehn } \ 616ceeaedd3SGarance A Drosehn if (!isdigit(ch)) \ 617ceeaedd3SGarance A Drosehn cat_X = cat_other; \ 618ceeaedd3SGarance A Drosehn } \ 619ceeaedd3SGarance A Drosehn } \ 620ceeaedd3SGarance A Drosehn } \ 621ceeaedd3SGarance A Drosehn } while (0) 622ceeaedd3SGarance A Drosehn 623ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a); 624ceeaedd3SGarance A Drosehn MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b); 625ceeaedd3SGarance A Drosehn 626ceeaedd3SGarance A Drosehn #undef MAP_TO_CAT 627ceeaedd3SGarance A Drosehn 628ceeaedd3SGarance A Drosehn /* First handle all cases which have "other" files */ 629ceeaedd3SGarance A Drosehn if ((cat_a >= cat_other) || (cat_b >= cat_other)) { 630ceeaedd3SGarance A Drosehn /* for two "other" files, just compare the full name */ 631ceeaedd3SGarance A Drosehn if (cat_a == cat_b) 632ceeaedd3SGarance A Drosehn res = strcmp(fname_a, fname_b); 633ceeaedd3SGarance A Drosehn else if (cat_a < cat_b) 634ceeaedd3SGarance A Drosehn res = a_lt_b; 635ceeaedd3SGarance A Drosehn else 636ceeaedd3SGarance A Drosehn res = a_gt_b; 637ceeaedd3SGarance A Drosehn goto have_res; 638ceeaedd3SGarance A Drosehn } 639ceeaedd3SGarance A Drosehn 640ceeaedd3SGarance A Drosehn /* 6411fd731faSGarance A Drosehn * At this point, we know both files are legitimate `cf', `df', `rf', 642ceeaedd3SGarance A Drosehn * or `tf' files. Compare them by job-number and machine name. 643ceeaedd3SGarance A Drosehn */ 644ceeaedd3SGarance A Drosehn res = strcmp(jnum_a, jnum_b); 645ceeaedd3SGarance A Drosehn if (res != 0) 646ceeaedd3SGarance A Drosehn goto have_res; 647ceeaedd3SGarance A Drosehn 648ceeaedd3SGarance A Drosehn /* 649ceeaedd3SGarance A Drosehn * We have two files which belong to the same job. Sort based 650ceeaedd3SGarance A Drosehn * on the catagory of file (`c' before `d', etc). 651ceeaedd3SGarance A Drosehn */ 652ceeaedd3SGarance A Drosehn if (cat_a < cat_b) { 653ceeaedd3SGarance A Drosehn res = a_lt_b; 654ceeaedd3SGarance A Drosehn goto have_res; 655ceeaedd3SGarance A Drosehn } else if (cat_a > cat_b) { 656ceeaedd3SGarance A Drosehn res = a_gt_b; 657ceeaedd3SGarance A Drosehn goto have_res; 658ceeaedd3SGarance A Drosehn } 659ceeaedd3SGarance A Drosehn 660ceeaedd3SGarance A Drosehn /* 661ceeaedd3SGarance A Drosehn * Two files in the same catagory for a single job. Sort based 662ceeaedd3SGarance A Drosehn * on the sequence letter(s). (usually `A' thru `Z', etc). 663ceeaedd3SGarance A Drosehn */ 664ceeaedd3SGarance A Drosehn if (seq_a < seq_b) { 665ceeaedd3SGarance A Drosehn res = a_lt_b; 666ceeaedd3SGarance A Drosehn goto have_res; 667ceeaedd3SGarance A Drosehn } else if (seq_a > seq_b) { 668ceeaedd3SGarance A Drosehn res = a_gt_b; 669ceeaedd3SGarance A Drosehn goto have_res; 670ceeaedd3SGarance A Drosehn } 671ceeaedd3SGarance A Drosehn 672ceeaedd3SGarance A Drosehn /* 673ceeaedd3SGarance A Drosehn * Given that the filenames in a directory are unique, this SHOULD 674ceeaedd3SGarance A Drosehn * never happen (unless there are logic errors in this routine). 675ceeaedd3SGarance A Drosehn * But if it does happen, we must return "is equal" or the caller 676ceeaedd3SGarance A Drosehn * might see inconsistent results in the sorting order, and that 677ceeaedd3SGarance A Drosehn * can trigger other problems. 678ceeaedd3SGarance A Drosehn */ 679ceeaedd3SGarance A Drosehn printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b); 680ceeaedd3SGarance A Drosehn printf("\t*** cat %d == %d ; seq = %d %d\n", cat_a, cat_b, 681ceeaedd3SGarance A Drosehn seq_a, seq_b); 682ceeaedd3SGarance A Drosehn res = 0; 683ceeaedd3SGarance A Drosehn 684ceeaedd3SGarance A Drosehn have_res: 685ceeaedd3SGarance A Drosehn return res; 686dea673e9SRodney W. Grimes } 687dea673e9SRodney W. Grimes 688dea673e9SRodney W. Grimes /* 6894a1a0dbeSGarrett Wollman * Remove all spool files and temporaries from the spooling area. 6904a1a0dbeSGarrett Wollman * Or, perhaps: 691dea673e9SRodney W. Grimes * Remove incomplete jobs from spooling area. 692dea673e9SRodney W. Grimes */ 693dea673e9SRodney W. Grimes 694004c9c5dSGarance A Drosehn void 695c9cb13a0SGarance A Drosehn clean_gi(int argc, char *argv[]) 696004c9c5dSGarance A Drosehn { 697004c9c5dSGarance A Drosehn 698004c9c5dSGarance A Drosehn /* init some fields before 'clean' is called for each queue */ 699004c9c5dSGarance A Drosehn cln_queuecnt = 0; 700004c9c5dSGarance A Drosehn cln_now = time(NULL); 701004c9c5dSGarance A Drosehn cln_minage = 3600.0; /* only delete files >1h old */ 702004c9c5dSGarance A Drosehn cln_filecnt = 0; 703004c9c5dSGarance A Drosehn cln_sizecnt = 0; 704004c9c5dSGarance A Drosehn cln_debug = 0; 705004c9c5dSGarance A Drosehn cln_testonly = 0; 706004c9c5dSGarance A Drosehn generic_wrapup = &wrapup_clean; 707004c9c5dSGarance A Drosehn 708004c9c5dSGarance A Drosehn /* see if there are any options specified before the ptr list */ 709e7f478b2SGarance A Drosehn for (; argc > 0; argc--, argv++) { 710004c9c5dSGarance A Drosehn if (**argv != '-') 711004c9c5dSGarance A Drosehn break; 712004c9c5dSGarance A Drosehn if (strcmp(*argv, "-d") == 0) { 713004c9c5dSGarance A Drosehn /* just an example of an option... */ 714ceeaedd3SGarance A Drosehn cln_debug++; 715004c9c5dSGarance A Drosehn *argv = generic_nullarg; /* "erase" it */ 716004c9c5dSGarance A Drosehn } else { 717004c9c5dSGarance A Drosehn printf("Invalid option '%s'\n", *argv); 718004c9c5dSGarance A Drosehn generic_initerr = 1; 719004c9c5dSGarance A Drosehn } 720004c9c5dSGarance A Drosehn } 721004c9c5dSGarance A Drosehn 722004c9c5dSGarance A Drosehn return; 723004c9c5dSGarance A Drosehn } 724004c9c5dSGarance A Drosehn 725004c9c5dSGarance A Drosehn void 726c9cb13a0SGarance A Drosehn tclean_gi(int argc, char *argv[]) 727004c9c5dSGarance A Drosehn { 728004c9c5dSGarance A Drosehn 729004c9c5dSGarance A Drosehn /* only difference between 'clean' and 'tclean' is one value */ 730004c9c5dSGarance A Drosehn /* (...and the fact that 'clean' is priv and 'tclean' is not) */ 731c9cb13a0SGarance A Drosehn clean_gi(argc, argv); 732004c9c5dSGarance A Drosehn cln_testonly = 1; 733004c9c5dSGarance A Drosehn 734004c9c5dSGarance A Drosehn return; 735004c9c5dSGarance A Drosehn } 736004c9c5dSGarance A Drosehn 737004c9c5dSGarance A Drosehn void 738004c9c5dSGarance A Drosehn clean_q(struct printer *pp) 739004c9c5dSGarance A Drosehn { 740004c9c5dSGarance A Drosehn char *cp, *cp1, *lp; 741004c9c5dSGarance A Drosehn struct dirent **queue; 742004c9c5dSGarance A Drosehn size_t linerem; 743004c9c5dSGarance A Drosehn int didhead, i, n, nitems, rmcp; 744004c9c5dSGarance A Drosehn 745004c9c5dSGarance A Drosehn cln_queuecnt++; 746004c9c5dSGarance A Drosehn 747004c9c5dSGarance A Drosehn didhead = 0; 748004c9c5dSGarance A Drosehn if (generic_qselect == QSEL_BYNAME) { 7494a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 750004c9c5dSGarance A Drosehn didhead = 1; 751004c9c5dSGarance A Drosehn } 752dea673e9SRodney W. Grimes 7534a1a0dbeSGarrett Wollman lp = line; 7544a1a0dbeSGarrett Wollman cp = pp->spool_dir; 7554a1a0dbeSGarrett Wollman while (lp < &line[sizeof(line) - 1]) { 7564a1a0dbeSGarrett Wollman if ((*lp++ = *cp++) == 0) 7574a1a0dbeSGarrett Wollman break; 7584a1a0dbeSGarrett Wollman } 759dea673e9SRodney W. Grimes lp[-1] = '/'; 760004c9c5dSGarance A Drosehn linerem = sizeof(line) - (lp - line); 761dea673e9SRodney W. Grimes 762004c9c5dSGarance A Drosehn cln_foundcore = 0; 763360d4ad5SWarner Losh seteuid(euid); 7644a1a0dbeSGarrett Wollman nitems = scandir(pp->spool_dir, &queue, doselect, sortq); 765360d4ad5SWarner Losh seteuid(uid); 766dea673e9SRodney W. Grimes if (nitems < 0) { 767004c9c5dSGarance A Drosehn if (!didhead) { 768004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 769004c9c5dSGarance A Drosehn didhead = 1; 770004c9c5dSGarance A Drosehn } 771dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 772dea673e9SRodney W. Grimes return; 773dea673e9SRodney W. Grimes } 774004c9c5dSGarance A Drosehn if (cln_foundcore) { 775004c9c5dSGarance A Drosehn if (!didhead) { 776004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 777004c9c5dSGarance A Drosehn didhead = 1; 778004c9c5dSGarance A Drosehn } 779004c9c5dSGarance A Drosehn printf("\t** found a core file in %s !\n", pp->spool_dir); 780004c9c5dSGarance A Drosehn } 781dea673e9SRodney W. Grimes if (nitems == 0) 782dea673e9SRodney W. Grimes return; 783004c9c5dSGarance A Drosehn if (!didhead) 784004c9c5dSGarance A Drosehn printf("%s:\n", pp->printer); 785ceeaedd3SGarance A Drosehn if (cln_debug) { 786ceeaedd3SGarance A Drosehn printf("\t** ----- Sorted list of files being checked:\n"); 787ceeaedd3SGarance A Drosehn i = 0; 788ceeaedd3SGarance A Drosehn do { 789ceeaedd3SGarance A Drosehn cp = queue[i]->d_name; 790ceeaedd3SGarance A Drosehn printf("\t** [%3d] = %s\n", i, cp); 791ceeaedd3SGarance A Drosehn } while (++i < nitems); 792ceeaedd3SGarance A Drosehn printf("\t** ----- end of sorted list\n"); 793ceeaedd3SGarance A Drosehn } 794dea673e9SRodney W. Grimes i = 0; 795dea673e9SRodney W. Grimes do { 796dea673e9SRodney W. Grimes cp = queue[i]->d_name; 797004c9c5dSGarance A Drosehn rmcp = 0; 798dea673e9SRodney W. Grimes if (*cp == 'c') { 799004c9c5dSGarance A Drosehn /* 800004c9c5dSGarance A Drosehn * A control file. Look for matching data-files. 801004c9c5dSGarance A Drosehn */ 802004c9c5dSGarance A Drosehn /* XXX 803004c9c5dSGarance A Drosehn * Note the logic here assumes that the hostname 804004c9c5dSGarance A Drosehn * part of cf-filenames match the hostname part 805004c9c5dSGarance A Drosehn * in df-filenames, and that is not necessarily 806004c9c5dSGarance A Drosehn * true (eg: for multi-homed hosts). This needs 807004c9c5dSGarance A Drosehn * some further thought... 808004c9c5dSGarance A Drosehn */ 809dea673e9SRodney W. Grimes n = 0; 810dea673e9SRodney W. Grimes while (i + 1 < nitems) { 811dea673e9SRodney W. Grimes cp1 = queue[i + 1]->d_name; 812dea673e9SRodney W. Grimes if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 813dea673e9SRodney W. Grimes break; 814dea673e9SRodney W. Grimes i++; 815dea673e9SRodney W. Grimes n++; 816dea673e9SRodney W. Grimes } 817dea673e9SRodney W. Grimes if (n == 0) { 818004c9c5dSGarance A Drosehn rmcp = 1; 819dea673e9SRodney W. Grimes } 820004c9c5dSGarance A Drosehn } else if (*cp == 'e') { 821004c9c5dSGarance A Drosehn /* 822004c9c5dSGarance A Drosehn * Must be an errrs or email temp file. 823004c9c5dSGarance A Drosehn */ 824004c9c5dSGarance A Drosehn rmcp = 1; 825dea673e9SRodney W. Grimes } else { 826dea673e9SRodney W. Grimes /* 827dea673e9SRodney W. Grimes * Must be a df with no cf (otherwise, it would have 8281fd731faSGarance A Drosehn * been skipped above) or an rf or tf file (which can 8291fd731faSGarance A Drosehn * always be removed if it is old enough). 830dea673e9SRodney W. Grimes */ 831004c9c5dSGarance A Drosehn rmcp = 1; 832004c9c5dSGarance A Drosehn } 833004c9c5dSGarance A Drosehn if (rmcp) { 834004c9c5dSGarance A Drosehn if (strlen(cp) >= linerem) { 835004c9c5dSGarance A Drosehn printf("\t** internal error: 'line' overflow!\n"); 836004c9c5dSGarance A Drosehn printf("\t** spooldir = %s\n", pp->spool_dir); 837004c9c5dSGarance A Drosehn printf("\t** cp = %s\n", cp); 838004c9c5dSGarance A Drosehn return; 839004c9c5dSGarance A Drosehn } 840004c9c5dSGarance A Drosehn strlcpy(lp, cp, linerem); 841dea673e9SRodney W. Grimes unlinkf(line); 842dea673e9SRodney W. Grimes } 843dea673e9SRodney W. Grimes } while (++i < nitems); 844dea673e9SRodney W. Grimes } 845dea673e9SRodney W. Grimes 846dea673e9SRodney W. Grimes static void 847004c9c5dSGarance A Drosehn wrapup_clean(int laststatus __unused) 848004c9c5dSGarance A Drosehn { 849004c9c5dSGarance A Drosehn 850004c9c5dSGarance A Drosehn printf("Checked %d queues, and ", cln_queuecnt); 851004c9c5dSGarance A Drosehn if (cln_filecnt < 1) { 852004c9c5dSGarance A Drosehn printf("no cruft was found\n"); 853004c9c5dSGarance A Drosehn return; 854004c9c5dSGarance A Drosehn } 855004c9c5dSGarance A Drosehn if (cln_testonly) { 856004c9c5dSGarance A Drosehn printf("would have "); 857004c9c5dSGarance A Drosehn } 858004c9c5dSGarance A Drosehn printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt); 859004c9c5dSGarance A Drosehn } 860004c9c5dSGarance A Drosehn 861004c9c5dSGarance A Drosehn static void 862ba7a1ad7SGarance A Drosehn unlinkf(char *name) 863dea673e9SRodney W. Grimes { 864004c9c5dSGarance A Drosehn struct stat stbuf; 865004c9c5dSGarance A Drosehn double agemod, agestat; 866004c9c5dSGarance A Drosehn int res; 867004c9c5dSGarance A Drosehn char linkbuf[BUFSIZ]; 868004c9c5dSGarance A Drosehn 869004c9c5dSGarance A Drosehn /* 870004c9c5dSGarance A Drosehn * We have to use lstat() instead of stat(), in case this is a df* 871004c9c5dSGarance A Drosehn * "file" which is really a symlink due to 'lpr -s' processing. In 872004c9c5dSGarance A Drosehn * that case, we need to check the last-mod time of the symlink, and 873004c9c5dSGarance A Drosehn * not the file that the symlink is pointed at. 874004c9c5dSGarance A Drosehn */ 875360d4ad5SWarner Losh seteuid(euid); 876004c9c5dSGarance A Drosehn res = lstat(name, &stbuf); 877004c9c5dSGarance A Drosehn seteuid(uid); 878004c9c5dSGarance A Drosehn if (res < 0) { 879004c9c5dSGarance A Drosehn printf("\terror return from stat(%s):\n", name); 880004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 881004c9c5dSGarance A Drosehn return; 882004c9c5dSGarance A Drosehn } 883004c9c5dSGarance A Drosehn 884004c9c5dSGarance A Drosehn agemod = difftime(cln_now, stbuf.st_mtime); 885004c9c5dSGarance A Drosehn agestat = difftime(cln_now, stbuf.st_ctime); 886ceeaedd3SGarance A Drosehn if (cln_debug > 1) { 887004c9c5dSGarance A Drosehn /* this debugging-aid probably is not needed any more... */ 888004c9c5dSGarance A Drosehn printf("\t\t modify age=%g secs, stat age=%g secs\n", 889004c9c5dSGarance A Drosehn agemod, agestat); 890004c9c5dSGarance A Drosehn } 891004c9c5dSGarance A Drosehn if ((agemod <= cln_minage) && (agestat <= cln_minage)) 892004c9c5dSGarance A Drosehn return; 893004c9c5dSGarance A Drosehn 894004c9c5dSGarance A Drosehn /* 895004c9c5dSGarance A Drosehn * if this file is a symlink, then find out the target of the 896004c9c5dSGarance A Drosehn * symlink before unlink-ing the file itself 897004c9c5dSGarance A Drosehn */ 898004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 899004c9c5dSGarance A Drosehn seteuid(euid); 900004c9c5dSGarance A Drosehn res = readlink(name, linkbuf, sizeof(linkbuf)); 901004c9c5dSGarance A Drosehn seteuid(uid); 902004c9c5dSGarance A Drosehn if (res < 0) { 903004c9c5dSGarance A Drosehn printf("\terror return from readlink(%s):\n", name); 904004c9c5dSGarance A Drosehn printf("\t %s\n", strerror(errno)); 905004c9c5dSGarance A Drosehn return; 906004c9c5dSGarance A Drosehn } 907004c9c5dSGarance A Drosehn if (res == sizeof(linkbuf)) 908004c9c5dSGarance A Drosehn res--; 909004c9c5dSGarance A Drosehn linkbuf[res] = '\0'; 910004c9c5dSGarance A Drosehn } 911004c9c5dSGarance A Drosehn 912004c9c5dSGarance A Drosehn cln_filecnt++; 913004c9c5dSGarance A Drosehn cln_sizecnt += stbuf.st_size; 914004c9c5dSGarance A Drosehn 915004c9c5dSGarance A Drosehn if (cln_testonly) { 916004c9c5dSGarance A Drosehn printf("\twould remove %s\n", name); 917004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 918004c9c5dSGarance A Drosehn printf("\t (which is a symlink to %s)\n", linkbuf); 919004c9c5dSGarance A Drosehn } 920004c9c5dSGarance A Drosehn } else { 921004c9c5dSGarance A Drosehn seteuid(euid); 922004c9c5dSGarance A Drosehn res = unlink(name); 923004c9c5dSGarance A Drosehn seteuid(uid); 924004c9c5dSGarance A Drosehn if (res < 0) 925004c9c5dSGarance A Drosehn printf("\tcannot remove %s (!)\n", name); 926dea673e9SRodney W. Grimes else 927dea673e9SRodney W. Grimes printf("\tremoved %s\n", name); 928004c9c5dSGarance A Drosehn /* XXX 929004c9c5dSGarance A Drosehn * Note that for a df* file, this code should also check to see 930004c9c5dSGarance A Drosehn * if it is a symlink to some other file, and if the original 931004c9c5dSGarance A Drosehn * lpr command included '-r' ("remove file"). Of course, this 932004c9c5dSGarance A Drosehn * code would not be removing the df* file unless there was no 933004c9c5dSGarance A Drosehn * matching cf* file, and without the cf* file it is currently 934004c9c5dSGarance A Drosehn * impossible to determine if '-r' had been specified... 935004c9c5dSGarance A Drosehn * 936004c9c5dSGarance A Drosehn * As a result of this quandry, we may be leaving behind a 937004c9c5dSGarance A Drosehn * user's file that was supposed to have been removed after 938004c9c5dSGarance A Drosehn * being printed. This may effect services such as CAP or 939004c9c5dSGarance A Drosehn * samba, if they were configured to use 'lpr -r', and if 940004c9c5dSGarance A Drosehn * datafiles are not being properly removed. 941004c9c5dSGarance A Drosehn */ 942004c9c5dSGarance A Drosehn if (S_ISLNK(stbuf.st_mode)) { 943004c9c5dSGarance A Drosehn printf("\t (which was a symlink to %s)\n", linkbuf); 944004c9c5dSGarance A Drosehn } 945004c9c5dSGarance A Drosehn } 946dea673e9SRodney W. Grimes } 947dea673e9SRodney W. Grimes 948dea673e9SRodney W. Grimes /* 949dea673e9SRodney W. Grimes * Enable queuing to the printer (allow lpr's). 950dea673e9SRodney W. Grimes */ 951dea673e9SRodney W. Grimes void 952ba7a1ad7SGarance A Drosehn enable(struct printer *pp) 953dea673e9SRodney W. Grimes { 954dea673e9SRodney W. Grimes struct stat stbuf; 9554a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 956dea673e9SRodney W. Grimes 9574a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 9584a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 959dea673e9SRodney W. Grimes 960dea673e9SRodney W. Grimes /* 961dea673e9SRodney W. Grimes * Turn off the group execute bit of the lock file to enable queuing. 962dea673e9SRodney W. Grimes */ 963360d4ad5SWarner Losh seteuid(euid); 9644a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 9654a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode & ~LFM_QUEUE_DIS) < 0) 966dea673e9SRodney W. Grimes printf("\tcannot enable queuing\n"); 967dea673e9SRodney W. Grimes else 968dea673e9SRodney W. Grimes printf("\tqueuing enabled\n"); 969dea673e9SRodney W. Grimes } 970360d4ad5SWarner Losh seteuid(uid); 971dea673e9SRodney W. Grimes } 972dea673e9SRodney W. Grimes 973dea673e9SRodney W. Grimes /* 974e8e715faSGarance A Drosehn * Enable queuing to the printer (allow lpr to add new jobs to the queue). 975e8e715faSGarance A Drosehn */ 976e8e715faSGarance A Drosehn void 977e8e715faSGarance A Drosehn enable_q(struct printer *pp) 978e8e715faSGarance A Drosehn { 979e8e715faSGarance A Drosehn int setres; 980e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 981e8e715faSGarance A Drosehn 982e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 983e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 984e8e715faSGarance A Drosehn 985e8e715faSGarance A Drosehn setres = set_qstate(SQS_ENABLEQ, lf); 986e8e715faSGarance A Drosehn } 987e8e715faSGarance A Drosehn 988e8e715faSGarance A Drosehn /* 989dea673e9SRodney W. Grimes * Disable queuing. 990dea673e9SRodney W. Grimes */ 991dea673e9SRodney W. Grimes void 992ba7a1ad7SGarance A Drosehn disable(struct printer *pp) 993dea673e9SRodney W. Grimes { 994dea673e9SRodney W. Grimes register int fd; 995dea673e9SRodney W. Grimes struct stat stbuf; 9964a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 997dea673e9SRodney W. Grimes 9984a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 9994a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1000dea673e9SRodney W. Grimes /* 1001dea673e9SRodney W. Grimes * Turn on the group execute bit of the lock file to disable queuing. 1002dea673e9SRodney W. Grimes */ 1003360d4ad5SWarner Losh seteuid(euid); 10044a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 10054a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_QUEUE_DIS) < 0) 10064a1a0dbeSGarrett Wollman printf("\tcannot disable queuing: %s\n", 10074a1a0dbeSGarrett Wollman strerror(errno)); 1008dea673e9SRodney W. Grimes else 1009dea673e9SRodney W. Grimes printf("\tqueuing disabled\n"); 1010dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 10114a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 10124a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_QUEUE_DIS)) < 0) 10134a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 10144a1a0dbeSGarrett Wollman strerror(errno)); 1015dea673e9SRodney W. Grimes else { 1016dea673e9SRodney W. Grimes (void) close(fd); 1017dea673e9SRodney W. Grimes printf("\tqueuing disabled\n"); 1018dea673e9SRodney W. Grimes } 1019dea673e9SRodney W. Grimes } else 1020dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 1021360d4ad5SWarner Losh seteuid(uid); 1022dea673e9SRodney W. Grimes } 1023dea673e9SRodney W. Grimes 1024dea673e9SRodney W. Grimes /* 1025e8e715faSGarance A Drosehn * Disable queuing. 1026e8e715faSGarance A Drosehn */ 1027e8e715faSGarance A Drosehn void 1028e8e715faSGarance A Drosehn disable_q(struct printer *pp) 1029e8e715faSGarance A Drosehn { 1030e8e715faSGarance A Drosehn int setres; 1031e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1032e8e715faSGarance A Drosehn 1033e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1034e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1035e8e715faSGarance A Drosehn 1036e8e715faSGarance A Drosehn setres = set_qstate(SQS_DISABLEQ, lf); 1037e8e715faSGarance A Drosehn } 1038e8e715faSGarance A Drosehn 1039e8e715faSGarance A Drosehn /* 1040dea673e9SRodney W. Grimes * Disable queuing and printing and put a message into the status file 1041dea673e9SRodney W. Grimes * (reason for being down). 1042dea673e9SRodney W. Grimes */ 1043dea673e9SRodney W. Grimes void 1044ba7a1ad7SGarance A Drosehn down(int argc, char *argv[]) 1045dea673e9SRodney W. Grimes { 1046ba7a1ad7SGarance A Drosehn int cmdstatus, more; 10474a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 1048dea673e9SRodney W. Grimes 1049dea673e9SRodney W. Grimes if (argc == 1) { 1050d3974088SDag-Erling Smørgrav printf("usage: down {all | printer} [message ...]\n"); 1051dea673e9SRodney W. Grimes return; 1052dea673e9SRodney W. Grimes } 1053dea673e9SRodney W. Grimes if (!strcmp(argv[1], "all")) { 1054ba7a1ad7SGarance A Drosehn more = firstprinter(pp, &cmdstatus); 1055ba7a1ad7SGarance A Drosehn if (cmdstatus) 10564a1a0dbeSGarrett Wollman goto looperr; 10574a1a0dbeSGarrett Wollman while (more) { 10584a1a0dbeSGarrett Wollman putmsg(pp, argc - 2, argv + 2); 10594a1a0dbeSGarrett Wollman do { 1060ba7a1ad7SGarance A Drosehn more = nextprinter(pp, &cmdstatus); 10614a1a0dbeSGarrett Wollman looperr: 1062ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 10634a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 10644a1a0dbeSGarrett Wollman printf("warning: %s: unresolved " 10654a1a0dbeSGarrett Wollman "tc= reference(s) ", 10664a1a0dbeSGarrett Wollman pp->printer); 10674a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 10684a1a0dbeSGarrett Wollman break; 10694a1a0dbeSGarrett Wollman default: 10706d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 10714a1a0dbeSGarrett Wollman } 1072ba7a1ad7SGarance A Drosehn } while (more && cmdstatus); 1073dea673e9SRodney W. Grimes } 1074dea673e9SRodney W. Grimes return; 1075dea673e9SRodney W. Grimes } 10764a1a0dbeSGarrett Wollman init_printer(pp); 1077ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(argv[1], pp); 1078ba7a1ad7SGarance A Drosehn switch (cmdstatus) { 10794a1a0dbeSGarrett Wollman default: 10806d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 10814a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 10824a1a0dbeSGarrett Wollman printf("unknown printer %s\n", argv[1]); 1083dea673e9SRodney W. Grimes return; 10844a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 10854a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)", argv[1]); 10864a1a0dbeSGarrett Wollman break; 10874a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 10884a1a0dbeSGarrett Wollman break; 10894a1a0dbeSGarrett Wollman } 10904a1a0dbeSGarrett Wollman putmsg(pp, argc - 2, argv + 2); 1091dea673e9SRodney W. Grimes } 1092dea673e9SRodney W. Grimes 1093dea673e9SRodney W. Grimes static void 1094ba7a1ad7SGarance A Drosehn putmsg(struct printer *pp, int argc, char **argv) 1095dea673e9SRodney W. Grimes { 1096dea673e9SRodney W. Grimes register int fd; 1097dea673e9SRodney W. Grimes register char *cp1, *cp2; 1098dea673e9SRodney W. Grimes char buf[1024]; 10994a1a0dbeSGarrett Wollman char file[MAXPATHLEN]; 1100dea673e9SRodney W. Grimes struct stat stbuf; 1101dea673e9SRodney W. Grimes 11024a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1103dea673e9SRodney W. Grimes /* 11044a1a0dbeSGarrett Wollman * Turn on the group execute bit of the lock file to disable queuing; 1105dea673e9SRodney W. Grimes * turn on the owner execute bit of the lock file to disable printing. 1106dea673e9SRodney W. Grimes */ 11074a1a0dbeSGarrett Wollman lock_file_name(pp, file, sizeof file); 1108360d4ad5SWarner Losh seteuid(euid); 11094a1a0dbeSGarrett Wollman if (stat(file, &stbuf) >= 0) { 11104a1a0dbeSGarrett Wollman if (chmod(file, stbuf.st_mode|LFM_PRINT_DIS|LFM_QUEUE_DIS) < 0) 11114a1a0dbeSGarrett Wollman printf("\tcannot disable queuing: %s\n", 11124a1a0dbeSGarrett Wollman strerror(errno)); 1113dea673e9SRodney W. Grimes else 1114dea673e9SRodney W. Grimes printf("\tprinter and queuing disabled\n"); 1115dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 11164a1a0dbeSGarrett Wollman if ((fd = open(file, O_WRONLY|O_CREAT, 11174a1a0dbeSGarrett Wollman LOCK_FILE_MODE|LFM_PRINT_DIS|LFM_QUEUE_DIS)) < 0) 11184a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 11194a1a0dbeSGarrett Wollman strerror(errno)); 1120dea673e9SRodney W. Grimes else { 1121dea673e9SRodney W. Grimes (void) close(fd); 1122dea673e9SRodney W. Grimes printf("\tprinter and queuing disabled\n"); 1123dea673e9SRodney W. Grimes } 1124360d4ad5SWarner Losh seteuid(uid); 1125dea673e9SRodney W. Grimes return; 1126dea673e9SRodney W. Grimes } else 1127dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 1128dea673e9SRodney W. Grimes /* 1129dea673e9SRodney W. Grimes * Write the message into the status file. 1130dea673e9SRodney W. Grimes */ 11314a1a0dbeSGarrett Wollman status_file_name(pp, file, sizeof file); 11324a1a0dbeSGarrett Wollman fd = open(file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE); 11334a1a0dbeSGarrett Wollman if (fd < 0) { 11344a1a0dbeSGarrett Wollman printf("\tcannot create status file: %s\n", strerror(errno)); 1135360d4ad5SWarner Losh seteuid(uid); 1136dea673e9SRodney W. Grimes return; 1137dea673e9SRodney W. Grimes } 1138360d4ad5SWarner Losh seteuid(uid); 1139dea673e9SRodney W. Grimes (void) ftruncate(fd, 0); 1140dea673e9SRodney W. Grimes if (argc <= 0) { 1141dea673e9SRodney W. Grimes (void) write(fd, "\n", 1); 1142dea673e9SRodney W. Grimes (void) close(fd); 1143dea673e9SRodney W. Grimes return; 1144dea673e9SRodney W. Grimes } 1145dea673e9SRodney W. Grimes cp1 = buf; 1146dea673e9SRodney W. Grimes while (--argc >= 0) { 1147dea673e9SRodney W. Grimes cp2 = *argv++; 114879c96a6cSGarance A Drosehn while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 1149dea673e9SRodney W. Grimes ; 1150dea673e9SRodney W. Grimes cp1[-1] = ' '; 1151dea673e9SRodney W. Grimes } 1152dea673e9SRodney W. Grimes cp1[-1] = '\n'; 1153dea673e9SRodney W. Grimes *cp1 = '\0'; 1154dea673e9SRodney W. Grimes (void) write(fd, buf, strlen(buf)); 1155dea673e9SRodney W. Grimes (void) close(fd); 1156dea673e9SRodney W. Grimes } 1157dea673e9SRodney W. Grimes 1158dea673e9SRodney W. Grimes /* 11595b1c34fbSGarance A Drosehn * Disable queuing and printing and put a message into the status file 11605b1c34fbSGarance A Drosehn * (reason for being down). If the user specified `-msg', then use 11615b1c34fbSGarance A Drosehn * everything after that as the message for the status file. If the 11625b1c34fbSGarance A Drosehn * user did NOT specify `-msg', then the command should take the first 11635b1c34fbSGarance A Drosehn * parameter as the printer name, and all remaining parameters as the 11645b1c34fbSGarance A Drosehn * message for the status file. (This is to be compatible with the 11655b1c34fbSGarance A Drosehn * original definition of 'down', which was implemented long before 11665b1c34fbSGarance A Drosehn * `-msg' was around). 11675b1c34fbSGarance A Drosehn */ 11685b1c34fbSGarance A Drosehn void 11695b1c34fbSGarance A Drosehn down_gi(int argc, char *argv[]) 11705b1c34fbSGarance A Drosehn { 11715b1c34fbSGarance A Drosehn 11725b1c34fbSGarance A Drosehn /* If `-msg' was specified, then this routine has nothing to do. */ 11735b1c34fbSGarance A Drosehn if (generic_msg != NULL) 11745b1c34fbSGarance A Drosehn return; 11755b1c34fbSGarance A Drosehn 11765b1c34fbSGarance A Drosehn /* 11775b1c34fbSGarance A Drosehn * If the user only gave one parameter, then use a default msg. 11785b1c34fbSGarance A Drosehn * (if argc == 1 at this point, then *argv == name of printer). 11795b1c34fbSGarance A Drosehn */ 11805b1c34fbSGarance A Drosehn if (argc == 1) { 11815b1c34fbSGarance A Drosehn generic_msg = strdup("printing disabled\n"); 11825b1c34fbSGarance A Drosehn return; 11835b1c34fbSGarance A Drosehn } 11845b1c34fbSGarance A Drosehn 11855b1c34fbSGarance A Drosehn /* 11865b1c34fbSGarance A Drosehn * The user specified multiple parameters, and did not specify 11875b1c34fbSGarance A Drosehn * `-msg'. Build a message from all the parameters after the 11885b1c34fbSGarance A Drosehn * first one (and nullify those parameters so generic-processing 11895b1c34fbSGarance A Drosehn * will not process them as printer-queue names). 11905b1c34fbSGarance A Drosehn */ 11915b1c34fbSGarance A Drosehn argc--; 11925b1c34fbSGarance A Drosehn argv++; 11935b1c34fbSGarance A Drosehn generic_msg = args2line(argc, argv); 11945b1c34fbSGarance A Drosehn for (; argc > 0; argc--, argv++) 11955b1c34fbSGarance A Drosehn *argv = generic_nullarg; /* "erase" it */ 11965b1c34fbSGarance A Drosehn } 11975b1c34fbSGarance A Drosehn 11985b1c34fbSGarance A Drosehn void 11995b1c34fbSGarance A Drosehn down_q(struct printer *pp) 12005b1c34fbSGarance A Drosehn { 12015b1c34fbSGarance A Drosehn int setres; 12025b1c34fbSGarance A Drosehn char lf[MAXPATHLEN]; 12035b1c34fbSGarance A Drosehn 12045b1c34fbSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 12055b1c34fbSGarance A Drosehn printf("%s:\n", pp->printer); 12065b1c34fbSGarance A Drosehn 12075b1c34fbSGarance A Drosehn setres = set_qstate(SQS_DISABLEQ+SQS_STOPP, lf); 12085b1c34fbSGarance A Drosehn if (setres >= 0) 12095b1c34fbSGarance A Drosehn upstat(pp, generic_msg, 1); 12105b1c34fbSGarance A Drosehn } 12115b1c34fbSGarance A Drosehn 12125b1c34fbSGarance A Drosehn /* 1213dea673e9SRodney W. Grimes * Exit lpc 1214dea673e9SRodney W. Grimes */ 1215dea673e9SRodney W. Grimes void 1216ba7a1ad7SGarance A Drosehn quit(int argc __unused, char *argv[] __unused) 1217dea673e9SRodney W. Grimes { 1218dea673e9SRodney W. Grimes exit(0); 1219dea673e9SRodney W. Grimes } 1220dea673e9SRodney W. Grimes 1221dea673e9SRodney W. Grimes /* 1222dea673e9SRodney W. Grimes * Kill and restart the daemon. 1223dea673e9SRodney W. Grimes */ 1224dea673e9SRodney W. Grimes void 1225ba7a1ad7SGarance A Drosehn restart(struct printer *pp) 1226dea673e9SRodney W. Grimes { 12274a1a0dbeSGarrett Wollman abortpr(pp, 0); 12284a1a0dbeSGarrett Wollman startpr(pp, 0); 1229dea673e9SRodney W. Grimes } 1230dea673e9SRodney W. Grimes 1231dea673e9SRodney W. Grimes /* 1232e8e715faSGarance A Drosehn * Kill and restart the daemon. 1233e8e715faSGarance A Drosehn */ 1234e8e715faSGarance A Drosehn void 1235e8e715faSGarance A Drosehn restart_q(struct printer *pp) 1236e8e715faSGarance A Drosehn { 1237e8e715faSGarance A Drosehn int killres, setres, startok; 1238e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1239e8e715faSGarance A Drosehn 1240e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1241e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1242e8e715faSGarance A Drosehn 1243e8e715faSGarance A Drosehn killres = kill_qtask(lf); 1244e8e715faSGarance A Drosehn 1245e8e715faSGarance A Drosehn /* 1246e8e715faSGarance A Drosehn * XXX - if the kill worked, we should probably sleep for 1247e8e715faSGarance A Drosehn * a second or so before trying to restart the queue. 1248e8e715faSGarance A Drosehn */ 1249e8e715faSGarance A Drosehn 1250e8e715faSGarance A Drosehn /* make sure the queue is set to print jobs */ 1251e8e715faSGarance A Drosehn setres = set_qstate(SQS_STARTP, lf); 1252e8e715faSGarance A Drosehn 1253e8e715faSGarance A Drosehn seteuid(euid); 1254e8e715faSGarance A Drosehn startok = startdaemon(pp); 1255e8e715faSGarance A Drosehn seteuid(uid); 1256e8e715faSGarance A Drosehn if (!startok) 1257e8e715faSGarance A Drosehn printf("\tcouldn't restart daemon\n"); 1258e8e715faSGarance A Drosehn else 1259e8e715faSGarance A Drosehn printf("\tdaemon restarted\n"); 1260e8e715faSGarance A Drosehn } 1261e8e715faSGarance A Drosehn 1262e8e715faSGarance A Drosehn /* 126354032d11SGarance A Drosehn * Set the status message of each queue listed. Requires a "-msg" 126454032d11SGarance A Drosehn * parameter to indicate the end of the queue list and start of msg text. 126554032d11SGarance A Drosehn */ 126654032d11SGarance A Drosehn void 126754032d11SGarance A Drosehn setstatus_gi(int argc __unused, char *argv[] __unused) 126854032d11SGarance A Drosehn { 126954032d11SGarance A Drosehn 127054032d11SGarance A Drosehn if (generic_msg == NULL) { 127154032d11SGarance A Drosehn printf("You must specify '-msg' before the text of the new status message.\n"); 127254032d11SGarance A Drosehn generic_initerr = 1; 127354032d11SGarance A Drosehn } 127454032d11SGarance A Drosehn } 127554032d11SGarance A Drosehn 127654032d11SGarance A Drosehn void 127754032d11SGarance A Drosehn setstatus_q(struct printer *pp) 127854032d11SGarance A Drosehn { 127954032d11SGarance A Drosehn char lf[MAXPATHLEN]; 128054032d11SGarance A Drosehn 128154032d11SGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 128254032d11SGarance A Drosehn printf("%s:\n", pp->printer); 128354032d11SGarance A Drosehn 128454032d11SGarance A Drosehn upstat(pp, generic_msg, 1); 128554032d11SGarance A Drosehn } 128654032d11SGarance A Drosehn 128754032d11SGarance A Drosehn /* 1288dea673e9SRodney W. Grimes * Enable printing on the specified printer and startup the daemon. 1289dea673e9SRodney W. Grimes */ 1290dea673e9SRodney W. Grimes void 1291ba7a1ad7SGarance A Drosehn startcmd(struct printer *pp) 1292dea673e9SRodney W. Grimes { 12934a1a0dbeSGarrett Wollman startpr(pp, 1); 1294dea673e9SRodney W. Grimes } 1295dea673e9SRodney W. Grimes 1296dea673e9SRodney W. Grimes static void 1297ba7a1ad7SGarance A Drosehn startpr(struct printer *pp, int chgenable) 1298dea673e9SRodney W. Grimes { 1299dea673e9SRodney W. Grimes struct stat stbuf; 13004a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 1301dea673e9SRodney W. Grimes 13024a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 13034a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1304dea673e9SRodney W. Grimes 1305dea673e9SRodney W. Grimes /* 1306ba7a1ad7SGarance A Drosehn * For chgenable==1 ('start'), turn off the LFM_PRINT_DIS bit of the 1307ba7a1ad7SGarance A Drosehn * lock file to re-enable printing. For chgenable==2 ('up'), also 13081bd87e1bSMatthew Dillon * turn off the LFM_QUEUE_DIS bit to re-enable queueing. 1309dea673e9SRodney W. Grimes */ 1310360d4ad5SWarner Losh seteuid(euid); 1311ba7a1ad7SGarance A Drosehn if (chgenable && stat(lf, &stbuf) >= 0) { 1312ba7a1ad7SGarance A Drosehn mode_t bits = (chgenable == 2 ? 0 : LFM_QUEUE_DIS); 13134a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode & (LOCK_FILE_MODE | bits)) < 0) 1314dea673e9SRodney W. Grimes printf("\tcannot enable printing\n"); 1315dea673e9SRodney W. Grimes else 1316dea673e9SRodney W. Grimes printf("\tprinting enabled\n"); 1317dea673e9SRodney W. Grimes } 13184a1a0dbeSGarrett Wollman if (!startdaemon(pp)) 1319dea673e9SRodney W. Grimes printf("\tcouldn't start daemon\n"); 1320dea673e9SRodney W. Grimes else 1321dea673e9SRodney W. Grimes printf("\tdaemon started\n"); 1322360d4ad5SWarner Losh seteuid(uid); 1323dea673e9SRodney W. Grimes } 1324dea673e9SRodney W. Grimes 1325dea673e9SRodney W. Grimes /* 1326e8e715faSGarance A Drosehn * Enable printing on the specified printer and startup the daemon. 1327e8e715faSGarance A Drosehn */ 1328e8e715faSGarance A Drosehn void 1329e8e715faSGarance A Drosehn start_q(struct printer *pp) 1330e8e715faSGarance A Drosehn { 1331e8e715faSGarance A Drosehn int setres, startok; 1332e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1333e8e715faSGarance A Drosehn 1334e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1335e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1336e8e715faSGarance A Drosehn 1337e8e715faSGarance A Drosehn setres = set_qstate(SQS_STARTP, lf); 1338e8e715faSGarance A Drosehn 1339e8e715faSGarance A Drosehn seteuid(euid); 1340e8e715faSGarance A Drosehn startok = startdaemon(pp); 1341e8e715faSGarance A Drosehn seteuid(uid); 1342e8e715faSGarance A Drosehn if (!startok) 1343e8e715faSGarance A Drosehn printf("\tcouldn't start daemon\n"); 1344e8e715faSGarance A Drosehn else 1345e8e715faSGarance A Drosehn printf("\tdaemon started\n"); 1346e8e715faSGarance A Drosehn seteuid(uid); 1347e8e715faSGarance A Drosehn } 1348e8e715faSGarance A Drosehn 1349e8e715faSGarance A Drosehn /* 1350dea673e9SRodney W. Grimes * Print the status of the printer queue. 1351dea673e9SRodney W. Grimes */ 13524a1a0dbeSGarrett Wollman void 1353ba7a1ad7SGarance A Drosehn status(struct printer *pp) 1354dea673e9SRodney W. Grimes { 1355dea673e9SRodney W. Grimes struct stat stbuf; 1356dea673e9SRodney W. Grimes register int fd, i; 1357dea673e9SRodney W. Grimes register struct dirent *dp; 1358dea673e9SRodney W. Grimes DIR *dirp; 13594a1a0dbeSGarrett Wollman char file[MAXPATHLEN]; 1360dea673e9SRodney W. Grimes 13614a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 13624a1a0dbeSGarrett Wollman lock_file_name(pp, file, sizeof file); 13634a1a0dbeSGarrett Wollman if (stat(file, &stbuf) >= 0) { 1364dea673e9SRodney W. Grimes printf("\tqueuing is %s\n", 13654a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled" 13664a1a0dbeSGarrett Wollman : "enabled")); 1367dea673e9SRodney W. Grimes printf("\tprinting is %s\n", 13684a1a0dbeSGarrett Wollman ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled" 13694a1a0dbeSGarrett Wollman : "enabled")); 1370dea673e9SRodney W. Grimes } else { 1371dea673e9SRodney W. Grimes printf("\tqueuing is enabled\n"); 1372dea673e9SRodney W. Grimes printf("\tprinting is enabled\n"); 1373dea673e9SRodney W. Grimes } 13744a1a0dbeSGarrett Wollman if ((dirp = opendir(pp->spool_dir)) == NULL) { 1375dea673e9SRodney W. Grimes printf("\tcannot examine spool directory\n"); 1376dea673e9SRodney W. Grimes return; 1377dea673e9SRodney W. Grimes } 1378dea673e9SRodney W. Grimes i = 0; 1379dea673e9SRodney W. Grimes while ((dp = readdir(dirp)) != NULL) { 1380dea673e9SRodney W. Grimes if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 1381dea673e9SRodney W. Grimes i++; 1382dea673e9SRodney W. Grimes } 1383dea673e9SRodney W. Grimes closedir(dirp); 1384dea673e9SRodney W. Grimes if (i == 0) 13854a1a0dbeSGarrett Wollman printf("\tno entries in spool area\n"); 1386dea673e9SRodney W. Grimes else if (i == 1) 1387dea673e9SRodney W. Grimes printf("\t1 entry in spool area\n"); 1388dea673e9SRodney W. Grimes else 1389dea673e9SRodney W. Grimes printf("\t%d entries in spool area\n", i); 13904a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY); 1391dea673e9SRodney W. Grimes if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 1392dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1393bc407914SWarner Losh printf("\tprinter idle\n"); 1394dea673e9SRodney W. Grimes return; 1395dea673e9SRodney W. Grimes } 1396dea673e9SRodney W. Grimes (void) close(fd); 139736abea5dSBrian Somers /* print out the contents of the status file, if it exists */ 13984a1a0dbeSGarrett Wollman status_file_name(pp, file, sizeof file); 13994a1a0dbeSGarrett Wollman fd = open(file, O_RDONLY|O_SHLOCK); 1400dea673e9SRodney W. Grimes if (fd >= 0) { 140136abea5dSBrian Somers (void) fstat(fd, &stbuf); 140236abea5dSBrian Somers if (stbuf.st_size > 0) { 140336abea5dSBrian Somers putchar('\t'); 1404dea673e9SRodney W. Grimes while ((i = read(fd, line, sizeof(line))) > 0) 1405dea673e9SRodney W. Grimes (void) fwrite(line, 1, i, stdout); 140636abea5dSBrian Somers } 1407dea673e9SRodney W. Grimes (void) close(fd); /* unlocks as well */ 1408dea673e9SRodney W. Grimes } 1409dea673e9SRodney W. Grimes } 1410dea673e9SRodney W. Grimes 1411dea673e9SRodney W. Grimes /* 1412dea673e9SRodney W. Grimes * Stop the specified daemon after completing the current job and disable 1413dea673e9SRodney W. Grimes * printing. 1414dea673e9SRodney W. Grimes */ 1415dea673e9SRodney W. Grimes void 1416ba7a1ad7SGarance A Drosehn stop(struct printer *pp) 1417dea673e9SRodney W. Grimes { 1418dea673e9SRodney W. Grimes register int fd; 1419dea673e9SRodney W. Grimes struct stat stbuf; 14204a1a0dbeSGarrett Wollman char lf[MAXPATHLEN]; 1421dea673e9SRodney W. Grimes 14224a1a0dbeSGarrett Wollman lock_file_name(pp, lf, sizeof lf); 14234a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1424dea673e9SRodney W. Grimes 1425dea673e9SRodney W. Grimes /* 1426dea673e9SRodney W. Grimes * Turn on the owner execute bit of the lock file to disable printing. 1427dea673e9SRodney W. Grimes */ 1428360d4ad5SWarner Losh seteuid(euid); 14294a1a0dbeSGarrett Wollman if (stat(lf, &stbuf) >= 0) { 14304a1a0dbeSGarrett Wollman if (chmod(lf, stbuf.st_mode | LFM_PRINT_DIS) < 0) 14314a1a0dbeSGarrett Wollman printf("\tcannot disable printing: %s\n", 14324a1a0dbeSGarrett Wollman strerror(errno)); 1433dea673e9SRodney W. Grimes else { 143454032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 1435dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 1436dea673e9SRodney W. Grimes } 1437dea673e9SRodney W. Grimes } else if (errno == ENOENT) { 14384a1a0dbeSGarrett Wollman if ((fd = open(lf, O_WRONLY|O_CREAT, 14394a1a0dbeSGarrett Wollman LOCK_FILE_MODE | LFM_PRINT_DIS)) < 0) 14404a1a0dbeSGarrett Wollman printf("\tcannot create lock file: %s\n", 14414a1a0dbeSGarrett Wollman strerror(errno)); 1442dea673e9SRodney W. Grimes else { 1443dea673e9SRodney W. Grimes (void) close(fd); 144454032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 1445dea673e9SRodney W. Grimes printf("\tprinting disabled\n"); 1446dea673e9SRodney W. Grimes } 1447dea673e9SRodney W. Grimes } else 1448dea673e9SRodney W. Grimes printf("\tcannot stat lock file\n"); 1449360d4ad5SWarner Losh seteuid(uid); 1450dea673e9SRodney W. Grimes } 1451dea673e9SRodney W. Grimes 1452e8e715faSGarance A Drosehn /* 1453e8e715faSGarance A Drosehn * Stop the specified daemon after completing the current job and disable 1454e8e715faSGarance A Drosehn * printing. 1455e8e715faSGarance A Drosehn */ 1456e8e715faSGarance A Drosehn void 1457e8e715faSGarance A Drosehn stop_q(struct printer *pp) 1458e8e715faSGarance A Drosehn { 1459e8e715faSGarance A Drosehn int setres; 1460e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1461e8e715faSGarance A Drosehn 1462e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1463e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1464e8e715faSGarance A Drosehn 1465e8e715faSGarance A Drosehn setres = set_qstate(SQS_STOPP, lf); 1466e8e715faSGarance A Drosehn 146754032d11SGarance A Drosehn if (setres >= 0) 146854032d11SGarance A Drosehn upstat(pp, "printing disabled\n", 0); 1469e8e715faSGarance A Drosehn } 1470e8e715faSGarance A Drosehn 147130b4b758SGarance A Drosehn struct jobqueue **queue; 1472dea673e9SRodney W. Grimes int nitems; 1473dea673e9SRodney W. Grimes time_t mtime; 1474dea673e9SRodney W. Grimes 1475dea673e9SRodney W. Grimes /* 1476dea673e9SRodney W. Grimes * Put the specified jobs at the top of printer queue. 1477dea673e9SRodney W. Grimes */ 1478dea673e9SRodney W. Grimes void 1479ba7a1ad7SGarance A Drosehn topq(int argc, char *argv[]) 1480dea673e9SRodney W. Grimes { 1481dea673e9SRodney W. Grimes register int i; 1482dea673e9SRodney W. Grimes struct stat stbuf; 1483ba7a1ad7SGarance A Drosehn int cmdstatus, changed; 14844a1a0dbeSGarrett Wollman struct printer myprinter, *pp = &myprinter; 1485dea673e9SRodney W. Grimes 1486dea673e9SRodney W. Grimes if (argc < 3) { 1487d3974088SDag-Erling Smørgrav printf("usage: topq printer [jobnum ...] [user ...]\n"); 1488dea673e9SRodney W. Grimes return; 1489dea673e9SRodney W. Grimes } 1490dea673e9SRodney W. Grimes 1491dea673e9SRodney W. Grimes --argc; 14924a1a0dbeSGarrett Wollman ++argv; 14934a1a0dbeSGarrett Wollman init_printer(pp); 1494ba7a1ad7SGarance A Drosehn cmdstatus = getprintcap(*argv, pp); 1495ba7a1ad7SGarance A Drosehn switch(cmdstatus) { 14964a1a0dbeSGarrett Wollman default: 14976d39e1b7SGarance A Drosehn fatal(pp, "%s", pcaperr(cmdstatus)); 14984a1a0dbeSGarrett Wollman case PCAPERR_NOTFOUND: 14994a1a0dbeSGarrett Wollman printf("unknown printer %s\n", *argv); 1500dea673e9SRodney W. Grimes return; 15014a1a0dbeSGarrett Wollman case PCAPERR_TCOPEN: 15024a1a0dbeSGarrett Wollman printf("warning: %s: unresolved tc= reference(s)", *argv); 15034a1a0dbeSGarrett Wollman break; 15044a1a0dbeSGarrett Wollman case PCAPERR_SUCCESS: 15054a1a0dbeSGarrett Wollman break; 15064a1a0dbeSGarrett Wollman } 15074a1a0dbeSGarrett Wollman printf("%s:\n", pp->printer); 1508dea673e9SRodney W. Grimes 1509360d4ad5SWarner Losh seteuid(euid); 15104a1a0dbeSGarrett Wollman if (chdir(pp->spool_dir) < 0) { 15114a1a0dbeSGarrett Wollman printf("\tcannot chdir to %s\n", pp->spool_dir); 1512360d4ad5SWarner Losh goto out; 1513dea673e9SRodney W. Grimes } 1514360d4ad5SWarner Losh seteuid(uid); 15154a1a0dbeSGarrett Wollman nitems = getq(pp, &queue); 1516dea673e9SRodney W. Grimes if (nitems == 0) 1517dea673e9SRodney W. Grimes return; 1518dea673e9SRodney W. Grimes changed = 0; 151930b4b758SGarance A Drosehn mtime = queue[0]->job_time; 1520dea673e9SRodney W. Grimes for (i = argc; --i; ) { 1521dea673e9SRodney W. Grimes if (doarg(argv[i]) == 0) { 1522dea673e9SRodney W. Grimes printf("\tjob %s is not in the queue\n", argv[i]); 1523dea673e9SRodney W. Grimes continue; 1524dea673e9SRodney W. Grimes } else 1525dea673e9SRodney W. Grimes changed++; 1526dea673e9SRodney W. Grimes } 1527dea673e9SRodney W. Grimes for (i = 0; i < nitems; i++) 1528dea673e9SRodney W. Grimes free(queue[i]); 1529dea673e9SRodney W. Grimes free(queue); 1530dea673e9SRodney W. Grimes if (!changed) { 1531dea673e9SRodney W. Grimes printf("\tqueue order unchanged\n"); 1532dea673e9SRodney W. Grimes return; 1533dea673e9SRodney W. Grimes } 1534dea673e9SRodney W. Grimes /* 1535dea673e9SRodney W. Grimes * Turn on the public execute bit of the lock file to 1536dea673e9SRodney W. Grimes * get lpd to rebuild the queue after the current job. 1537dea673e9SRodney W. Grimes */ 1538360d4ad5SWarner Losh seteuid(euid); 15394a1a0dbeSGarrett Wollman if (changed && stat(pp->lock_file, &stbuf) >= 0) 15404a1a0dbeSGarrett Wollman (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE); 1541360d4ad5SWarner Losh 1542360d4ad5SWarner Losh out: 1543360d4ad5SWarner Losh seteuid(uid); 1544dea673e9SRodney W. Grimes } 1545dea673e9SRodney W. Grimes 1546dea673e9SRodney W. Grimes /* 1547dea673e9SRodney W. Grimes * Reposition the job by changing the modification time of 1548dea673e9SRodney W. Grimes * the control file. 1549dea673e9SRodney W. Grimes */ 1550dea673e9SRodney W. Grimes static int 1551ba7a1ad7SGarance A Drosehn touch(struct jobqueue *jq) 1552dea673e9SRodney W. Grimes { 1553dea673e9SRodney W. Grimes struct timeval tvp[2]; 1554360d4ad5SWarner Losh int ret; 1555dea673e9SRodney W. Grimes 1556dea673e9SRodney W. Grimes tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 1557dea673e9SRodney W. Grimes tvp[0].tv_usec = tvp[1].tv_usec = 0; 1558360d4ad5SWarner Losh seteuid(euid); 1559ba7a1ad7SGarance A Drosehn ret = utimes(jq->job_cfname, tvp); 1560360d4ad5SWarner Losh seteuid(uid); 1561360d4ad5SWarner Losh return (ret); 1562dea673e9SRodney W. Grimes } 1563dea673e9SRodney W. Grimes 1564dea673e9SRodney W. Grimes /* 1565dea673e9SRodney W. Grimes * Checks if specified job name is in the printer's queue. 1566dea673e9SRodney W. Grimes * Returns: negative (-1) if argument name is not in the queue. 1567dea673e9SRodney W. Grimes */ 1568dea673e9SRodney W. Grimes static int 1569ba7a1ad7SGarance A Drosehn doarg(char *job) 1570dea673e9SRodney W. Grimes { 157130b4b758SGarance A Drosehn register struct jobqueue **qq; 1572dea673e9SRodney W. Grimes register int jobnum, n; 1573dea673e9SRodney W. Grimes register char *cp, *machine; 1574dea673e9SRodney W. Grimes int cnt = 0; 1575dea673e9SRodney W. Grimes FILE *fp; 1576dea673e9SRodney W. Grimes 1577dea673e9SRodney W. Grimes /* 1578dea673e9SRodney W. Grimes * Look for a job item consisting of system name, colon, number 1579dea673e9SRodney W. Grimes * (example: ucbarpa:114) 1580dea673e9SRodney W. Grimes */ 1581f8eb25daSWarner Losh if ((cp = strchr(job, ':')) != NULL) { 1582dea673e9SRodney W. Grimes machine = job; 1583dea673e9SRodney W. Grimes *cp++ = '\0'; 1584dea673e9SRodney W. Grimes job = cp; 1585dea673e9SRodney W. Grimes } else 1586dea673e9SRodney W. Grimes machine = NULL; 1587dea673e9SRodney W. Grimes 1588dea673e9SRodney W. Grimes /* 1589dea673e9SRodney W. Grimes * Check for job specified by number (example: 112 or 235ucbarpa). 1590dea673e9SRodney W. Grimes */ 1591dea673e9SRodney W. Grimes if (isdigit(*job)) { 1592dea673e9SRodney W. Grimes jobnum = 0; 1593dea673e9SRodney W. Grimes do 1594dea673e9SRodney W. Grimes jobnum = jobnum * 10 + (*job++ - '0'); 1595dea673e9SRodney W. Grimes while (isdigit(*job)); 1596dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1597dea673e9SRodney W. Grimes n = 0; 159830b4b758SGarance A Drosehn for (cp = (*qq)->job_cfname+3; isdigit(*cp); ) 1599dea673e9SRodney W. Grimes n = n * 10 + (*cp++ - '0'); 1600dea673e9SRodney W. Grimes if (jobnum != n) 1601dea673e9SRodney W. Grimes continue; 1602dea673e9SRodney W. Grimes if (*job && strcmp(job, cp) != 0) 1603dea673e9SRodney W. Grimes continue; 1604dea673e9SRodney W. Grimes if (machine != NULL && strcmp(machine, cp) != 0) 1605dea673e9SRodney W. Grimes continue; 1606dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 160730b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1608dea673e9SRodney W. Grimes cnt++; 1609dea673e9SRodney W. Grimes } 1610dea673e9SRodney W. Grimes } 1611dea673e9SRodney W. Grimes return(cnt); 1612dea673e9SRodney W. Grimes } 1613dea673e9SRodney W. Grimes /* 1614dea673e9SRodney W. Grimes * Process item consisting of owner's name (example: henry). 1615dea673e9SRodney W. Grimes */ 1616dea673e9SRodney W. Grimes for (qq = queue + nitems; --qq >= queue; ) { 1617360d4ad5SWarner Losh seteuid(euid); 161830b4b758SGarance A Drosehn fp = fopen((*qq)->job_cfname, "r"); 1619360d4ad5SWarner Losh seteuid(uid); 1620360d4ad5SWarner Losh if (fp == NULL) 1621dea673e9SRodney W. Grimes continue; 1622dea673e9SRodney W. Grimes while (getline(fp) > 0) 1623dea673e9SRodney W. Grimes if (line[0] == 'P') 1624dea673e9SRodney W. Grimes break; 1625dea673e9SRodney W. Grimes (void) fclose(fp); 1626dea673e9SRodney W. Grimes if (line[0] != 'P' || strcmp(job, line+1) != 0) 1627dea673e9SRodney W. Grimes continue; 1628dea673e9SRodney W. Grimes if (touch(*qq) == 0) { 162930b4b758SGarance A Drosehn printf("\tmoved %s\n", (*qq)->job_cfname); 1630dea673e9SRodney W. Grimes cnt++; 1631dea673e9SRodney W. Grimes } 1632dea673e9SRodney W. Grimes } 1633dea673e9SRodney W. Grimes return(cnt); 1634dea673e9SRodney W. Grimes } 1635dea673e9SRodney W. Grimes 1636dea673e9SRodney W. Grimes /* 1637dea673e9SRodney W. Grimes * Enable everything and start printer (undo `down'). 1638dea673e9SRodney W. Grimes */ 1639dea673e9SRodney W. Grimes void 1640ba7a1ad7SGarance A Drosehn up(struct printer *pp) 1641dea673e9SRodney W. Grimes { 16424a1a0dbeSGarrett Wollman startpr(pp, 2); 1643dea673e9SRodney W. Grimes } 1644e8e715faSGarance A Drosehn 1645e8e715faSGarance A Drosehn /* 1646e8e715faSGarance A Drosehn * Enable both queuing & printing, and start printer (undo `down'). 1647e8e715faSGarance A Drosehn */ 1648e8e715faSGarance A Drosehn void 1649e8e715faSGarance A Drosehn up_q(struct printer *pp) 1650e8e715faSGarance A Drosehn { 1651e8e715faSGarance A Drosehn int setres, startok; 1652e8e715faSGarance A Drosehn char lf[MAXPATHLEN]; 1653e8e715faSGarance A Drosehn 1654e8e715faSGarance A Drosehn lock_file_name(pp, lf, sizeof lf); 1655e8e715faSGarance A Drosehn printf("%s:\n", pp->printer); 1656e8e715faSGarance A Drosehn 1657e8e715faSGarance A Drosehn setres = set_qstate(SQS_ENABLEQ+SQS_STARTP, lf); 1658e8e715faSGarance A Drosehn 1659e8e715faSGarance A Drosehn seteuid(euid); 1660e8e715faSGarance A Drosehn startok = startdaemon(pp); 1661e8e715faSGarance A Drosehn seteuid(uid); 1662e8e715faSGarance A Drosehn if (!startok) 1663e8e715faSGarance A Drosehn printf("\tcouldn't start daemon\n"); 1664e8e715faSGarance A Drosehn else 1665e8e715faSGarance A Drosehn printf("\tdaemon started\n"); 1666e8e715faSGarance A Drosehn } 1667