1*8a16b7a1SPedro F. Giffuni /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 40b561052SJoerg Wunsch * Copyright (c) 1983, 1993 50b561052SJoerg Wunsch * The Regents of the University of California. All rights reserved. 60b561052SJoerg Wunsch * 70b561052SJoerg Wunsch * Redistribution and use in source and binary forms, with or without 80b561052SJoerg Wunsch * modification, are permitted provided that the following conditions 90b561052SJoerg Wunsch * are met: 100b561052SJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 110b561052SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 120b561052SJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 130b561052SJoerg Wunsch * notice, this list of conditions and the following disclaimer in the 140b561052SJoerg Wunsch * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 160b561052SJoerg Wunsch * may be used to endorse or promote products derived from this software 170b561052SJoerg Wunsch * without specific prior written permission. 180b561052SJoerg Wunsch * 190b561052SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 200b561052SJoerg Wunsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 210b561052SJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 220b561052SJoerg Wunsch * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 230b561052SJoerg Wunsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 240b561052SJoerg Wunsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 250b561052SJoerg Wunsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 260b561052SJoerg Wunsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 270b561052SJoerg Wunsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 280b561052SJoerg Wunsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290b561052SJoerg Wunsch * SUCH DAMAGE. 300b561052SJoerg Wunsch */ 310b561052SJoerg Wunsch 321f589b47SGarance A Drosehn #if 0 33b7fd8699SGarance A Drosehn #ifndef lint 345458e2f4SJoerg Wunsch static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; 35b7fd8699SGarance A Drosehn #endif /* not lint */ 361f589b47SGarance A Drosehn #endif 37b7fd8699SGarance A Drosehn 381f589b47SGarance A Drosehn #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 391f589b47SGarance A Drosehn __FBSDID("$FreeBSD$"); 400b561052SJoerg Wunsch 410b561052SJoerg Wunsch #include <sys/param.h> 420b561052SJoerg Wunsch #include <sys/stat.h> 430b561052SJoerg Wunsch 444a1a0dbeSGarrett Wollman #include <ctype.h> 450b561052SJoerg Wunsch #include <dirent.h> 461d1d4a47SEitan Adler #include <err.h> 474a1a0dbeSGarrett Wollman #include <errno.h> 484a1a0dbeSGarrett Wollman #include <fcntl.h> 494a1a0dbeSGarrett Wollman #include <signal.h> 500b561052SJoerg Wunsch #include <stdio.h> 510b561052SJoerg Wunsch #include <stdlib.h> 520b561052SJoerg Wunsch #include <string.h> 534a1a0dbeSGarrett Wollman #define psignal foil_gcc_psignal 544a1a0dbeSGarrett Wollman #define sys_siglist foil_gcc_siglist 554a1a0dbeSGarrett Wollman #include <unistd.h> 564a1a0dbeSGarrett Wollman #undef psignal 574a1a0dbeSGarrett Wollman #undef sys_siglist 584a1a0dbeSGarrett Wollman 590b561052SJoerg Wunsch #include "lp.h" 600b561052SJoerg Wunsch #include "lp.local.h" 610b561052SJoerg Wunsch #include "pathnames.h" 620b561052SJoerg Wunsch 630b561052SJoerg Wunsch /* 640b561052SJoerg Wunsch * Routines to display the state of the queue. 650b561052SJoerg Wunsch */ 660b561052SJoerg Wunsch #define JOBCOL 40 /* column for job # in -l format */ 670b561052SJoerg Wunsch #define OWNCOL 7 /* start of Owner column in normal */ 680b561052SJoerg Wunsch #define SIZCOL 62 /* start of Size column in normal */ 690b561052SJoerg Wunsch 700b561052SJoerg Wunsch /* 7146bfa198SGarance A Drosehn * isprint() takes a parameter of 'int', but expect values in the range 7246bfa198SGarance A Drosehn * of unsigned char. Define a wrapper which takes a value of type 'char', 7346bfa198SGarance A Drosehn * whether signed or unsigned, and ensure it ends up in the right range. 7446bfa198SGarance A Drosehn */ 7546bfa198SGarance A Drosehn #define isprintch(Anychar) isprint((u_char)(Anychar)) 7646bfa198SGarance A Drosehn 7746bfa198SGarance A Drosehn /* 780b561052SJoerg Wunsch * Stuff for handling job specifications 790b561052SJoerg Wunsch */ 800b561052SJoerg Wunsch static int col; /* column on screen */ 817b7fb4bbSKris Kennaway static char current[MAXNAMLEN+1]; /* current file being printed */ 827b7fb4bbSKris Kennaway static char file[MAXNAMLEN+1]; /* print file name */ 830b561052SJoerg Wunsch static int first; /* first file in ``files'' column? */ 840b561052SJoerg Wunsch static int garbage; /* # of garbage cf files */ 850b561052SJoerg Wunsch static int lflag; /* long output option */ 860b561052SJoerg Wunsch static int rank; /* order to be printed (-1=none, 0=active) */ 870b561052SJoerg Wunsch static long totsize; /* total print job size in bytes */ 880b561052SJoerg Wunsch 89ba7a1ad7SGarance A Drosehn static const char *head0 = "Rank Owner Job Files"; 90ba7a1ad7SGarance A Drosehn static const char *head1 = "Total Size\n"; 910b561052SJoerg Wunsch 92ba7a1ad7SGarance A Drosehn static void alarmhandler(int _signo); 9346bfa198SGarance A Drosehn static void filtered_write(char *_obuffer, int _wlen, FILE *_wstream); 941d1d4a47SEitan Adler static void daemonwarn(const struct printer *_pp); 95334a9508SJoerg Wunsch 960b561052SJoerg Wunsch /* 970b561052SJoerg Wunsch * Display the current state of the queue. Format = 1 if long format. 980b561052SJoerg Wunsch */ 990b561052SJoerg Wunsch void 100ba7a1ad7SGarance A Drosehn displayq(struct printer *pp, int format) 1010b561052SJoerg Wunsch { 10230b4b758SGarance A Drosehn register struct jobqueue *q; 103360d4ad5SWarner Losh register int i, nitems, fd, ret; 1047b7fb4bbSKris Kennaway char *cp, *endp; 10530b4b758SGarance A Drosehn struct jobqueue **queue; 1060b561052SJoerg Wunsch struct stat statb; 1070b561052SJoerg Wunsch FILE *fp; 108334a9508SJoerg Wunsch void (*savealrm)(int); 1090b561052SJoerg Wunsch 1100b561052SJoerg Wunsch lflag = format; 1110b561052SJoerg Wunsch totsize = 0; 1120b561052SJoerg Wunsch rank = -1; 1134a1a0dbeSGarrett Wollman 1144a1a0dbeSGarrett Wollman if ((cp = checkremote(pp))) { 1150b561052SJoerg Wunsch printf("Warning: %s\n", cp); 1164a1a0dbeSGarrett Wollman free(cp); 1174a1a0dbeSGarrett Wollman } 1180b561052SJoerg Wunsch 1190b561052SJoerg Wunsch /* 1200b561052SJoerg Wunsch * Print out local queue 1210b561052SJoerg Wunsch * Find all the control files in the spooling directory 1220b561052SJoerg Wunsch */ 1231d1d4a47SEitan Adler PRIV_START 1244a1a0dbeSGarrett Wollman if (chdir(pp->spool_dir) < 0) 1254a1a0dbeSGarrett Wollman fatal(pp, "cannot chdir to spooling directory: %s", 1264a1a0dbeSGarrett Wollman strerror(errno)); 1271d1d4a47SEitan Adler PRIV_END 1284a1a0dbeSGarrett Wollman if ((nitems = getq(pp, &queue)) < 0) 1294a1a0dbeSGarrett Wollman fatal(pp, "cannot examine spooling area\n"); 1301d1d4a47SEitan Adler PRIV_START 1314a1a0dbeSGarrett Wollman ret = stat(pp->lock_file, &statb); 1321d1d4a47SEitan Adler PRIV_END 133360d4ad5SWarner Losh if (ret >= 0) { 1344a1a0dbeSGarrett Wollman if (statb.st_mode & LFM_PRINT_DIS) { 1354a1a0dbeSGarrett Wollman if (pp->remote) 136cc3fd56fSGarance A Drosehn printf("%s: ", local_host); 1374a1a0dbeSGarrett Wollman printf("Warning: %s is down: ", pp->printer); 1381d1d4a47SEitan Adler PRIV_START 1394a1a0dbeSGarrett Wollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 1401d1d4a47SEitan Adler PRIV_END 1410b561052SJoerg Wunsch if (fd >= 0) { 1420b561052SJoerg Wunsch while ((i = read(fd, line, sizeof(line))) > 0) 1430b561052SJoerg Wunsch (void) fwrite(line, 1, i, stdout); 1440b561052SJoerg Wunsch (void) close(fd); /* unlocks as well */ 1450b561052SJoerg Wunsch } else 1460b561052SJoerg Wunsch putchar('\n'); 1470b561052SJoerg Wunsch } 1484a1a0dbeSGarrett Wollman if (statb.st_mode & LFM_QUEUE_DIS) { 1494a1a0dbeSGarrett Wollman if (pp->remote) 150cc3fd56fSGarance A Drosehn printf("%s: ", local_host); 1514a1a0dbeSGarrett Wollman printf("Warning: %s queue is turned off\n", 1524a1a0dbeSGarrett Wollman pp->printer); 1530b561052SJoerg Wunsch } 1540b561052SJoerg Wunsch } 1550b561052SJoerg Wunsch 1560b561052SJoerg Wunsch if (nitems) { 1571d1d4a47SEitan Adler PRIV_START 1584a1a0dbeSGarrett Wollman fp = fopen(pp->lock_file, "r"); 1591d1d4a47SEitan Adler PRIV_END 1600b561052SJoerg Wunsch if (fp == NULL) 1611d1d4a47SEitan Adler daemonwarn(pp); 1620b561052SJoerg Wunsch else { 1630b561052SJoerg Wunsch /* get daemon pid */ 1640b561052SJoerg Wunsch cp = current; 1657b7fb4bbSKris Kennaway endp = cp + sizeof(current) - 1; 1667b7fb4bbSKris Kennaway while ((i = getc(fp)) != EOF && i != '\n') { 1677b7fb4bbSKris Kennaway if (cp < endp) 1685458e2f4SJoerg Wunsch *cp++ = i; 1697b7fb4bbSKris Kennaway } 1700b561052SJoerg Wunsch *cp = '\0'; 1710b561052SJoerg Wunsch i = atoi(current); 172360d4ad5SWarner Losh if (i <= 0) { 173360d4ad5SWarner Losh ret = -1; 174360d4ad5SWarner Losh } else { 1751d1d4a47SEitan Adler PRIV_START 176360d4ad5SWarner Losh ret = kill(i, 0); 1771d1d4a47SEitan Adler PRIV_END 178360d4ad5SWarner Losh } 179360d4ad5SWarner Losh if (ret < 0) { 1801d1d4a47SEitan Adler daemonwarn(pp); 181360d4ad5SWarner Losh } else { 1820b561052SJoerg Wunsch /* read current file name */ 1830b561052SJoerg Wunsch cp = current; 1847b7fb4bbSKris Kennaway endp = cp + sizeof(current) - 1; 1857b7fb4bbSKris Kennaway while ((i = getc(fp)) != EOF && i != '\n') { 1867b7fb4bbSKris Kennaway if (cp < endp) 1875458e2f4SJoerg Wunsch *cp++ = i; 1887b7fb4bbSKris Kennaway } 1890b561052SJoerg Wunsch *cp = '\0'; 1900b561052SJoerg Wunsch /* 1910b561052SJoerg Wunsch * Print the status file. 1920b561052SJoerg Wunsch */ 1934a1a0dbeSGarrett Wollman if (pp->remote) 194cc3fd56fSGarance A Drosehn printf("%s: ", local_host); 1951d1d4a47SEitan Adler PRIV_START 1964a1a0dbeSGarrett Wollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 1971d1d4a47SEitan Adler PRIV_END 1980b561052SJoerg Wunsch if (fd >= 0) { 1994a1a0dbeSGarrett Wollman while ((i = read(fd, line, 2004a1a0dbeSGarrett Wollman sizeof(line))) > 0) 2014a1a0dbeSGarrett Wollman fwrite(line, 1, i, stdout); 2024a1a0dbeSGarrett Wollman close(fd); /* unlocks as well */ 2030b561052SJoerg Wunsch } else 2040b561052SJoerg Wunsch putchar('\n'); 2050b561052SJoerg Wunsch } 2060b561052SJoerg Wunsch (void) fclose(fp); 2070b561052SJoerg Wunsch } 2080b561052SJoerg Wunsch /* 2090b561052SJoerg Wunsch * Now, examine the control files and print out the jobs to 2100b561052SJoerg Wunsch * be done for each user. 2110b561052SJoerg Wunsch */ 2120b561052SJoerg Wunsch if (!lflag) 2130b561052SJoerg Wunsch header(); 2140b561052SJoerg Wunsch for (i = 0; i < nitems; i++) { 2150b561052SJoerg Wunsch q = queue[i]; 21630b4b758SGarance A Drosehn inform(pp, q->job_cfname); 2170b561052SJoerg Wunsch free(q); 2180b561052SJoerg Wunsch } 2190b561052SJoerg Wunsch free(queue); 2200b561052SJoerg Wunsch } 2214a1a0dbeSGarrett Wollman if (!pp->remote) { 2220b561052SJoerg Wunsch if (nitems == 0) 2230b561052SJoerg Wunsch puts("no entries"); 2240b561052SJoerg Wunsch return; 2250b561052SJoerg Wunsch } 2260b561052SJoerg Wunsch 2270b561052SJoerg Wunsch /* 2280b561052SJoerg Wunsch * Print foreign queue 2290b561052SJoerg Wunsch * Note that a file in transit may show up in either queue. 2300b561052SJoerg Wunsch */ 2310b561052SJoerg Wunsch if (nitems) 2320b561052SJoerg Wunsch putchar('\n'); 2334a1a0dbeSGarrett Wollman (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3', 2344a1a0dbeSGarrett Wollman pp->remote_queue); 2350b561052SJoerg Wunsch cp = line; 2366ee8b269SWarner Losh for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 2370b561052SJoerg Wunsch cp += strlen(cp); 2380b561052SJoerg Wunsch (void) sprintf(cp, " %d", requ[i]); 2390b561052SJoerg Wunsch } 240d583a7c3SWarner Losh for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 2416ee8b269SWarner Losh sizeof(line) - 1; i++) { 2420b561052SJoerg Wunsch cp += strlen(cp); 2430b561052SJoerg Wunsch *cp++ = ' '; 2440b561052SJoerg Wunsch (void) strcpy(cp, user[i]); 2450b561052SJoerg Wunsch } 2460b561052SJoerg Wunsch strcat(line, "\n"); 247334a9508SJoerg Wunsch savealrm = signal(SIGALRM, alarmhandler); 2484a1a0dbeSGarrett Wollman alarm(pp->conn_timeout); 2494a1a0dbeSGarrett Wollman fd = getport(pp, pp->remote_host, 0); 2506d0727f4SJoerg Wunsch alarm(0); 251334a9508SJoerg Wunsch (void)signal(SIGALRM, savealrm); 2520b561052SJoerg Wunsch if (fd < 0) { 253cc3fd56fSGarance A Drosehn if (from_host != local_host) 254cc3fd56fSGarance A Drosehn printf("%s: ", local_host); 2554a1a0dbeSGarrett Wollman printf("connection to %s is down\n", pp->remote_host); 2560b561052SJoerg Wunsch } 2570b561052SJoerg Wunsch else { 2580b561052SJoerg Wunsch i = strlen(line); 2590b561052SJoerg Wunsch if (write(fd, line, i) != i) 2604a1a0dbeSGarrett Wollman fatal(pp, "Lost connection"); 2610b561052SJoerg Wunsch while ((i = read(fd, line, sizeof(line))) > 0) 26246bfa198SGarance A Drosehn filtered_write(line, i, stdout); 26346bfa198SGarance A Drosehn filtered_write(NULL, -1, stdout); 2640b561052SJoerg Wunsch (void) close(fd); 2650b561052SJoerg Wunsch } 2660b561052SJoerg Wunsch } 2670b561052SJoerg Wunsch 2680b561052SJoerg Wunsch /* 26946bfa198SGarance A Drosehn * The lpq-info read from remote hosts may contain unprintable characters, 27046bfa198SGarance A Drosehn * or carriage-returns instead of line-feeds. Clean those up before echoing 27146bfa198SGarance A Drosehn * the lpq-info line(s) to stdout. The info may also be missing any kind of 27246bfa198SGarance A Drosehn * end-of-line character. This also turns CRLF and LFCR into a plain LF. 27346bfa198SGarance A Drosehn * 27446bfa198SGarance A Drosehn * This routine may be called multiple times to process a single set of 27546bfa198SGarance A Drosehn * information, and after a set is finished this routine must be called 27646bfa198SGarance A Drosehn * one extra time with NULL specified as the buffer address. 27746bfa198SGarance A Drosehn */ 27846bfa198SGarance A Drosehn static void 27946bfa198SGarance A Drosehn filtered_write(char *wbuffer, int wlen, FILE *wstream) 28046bfa198SGarance A Drosehn { 28146bfa198SGarance A Drosehn static char lastchar, savedchar; 28246bfa198SGarance A Drosehn char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end; 28346bfa198SGarance A Drosehn int destlen; 28446bfa198SGarance A Drosehn char destbuf[BUFSIZ]; 28546bfa198SGarance A Drosehn 28646bfa198SGarance A Drosehn if (wbuffer == NULL) { 28746bfa198SGarance A Drosehn if (savedchar != '\0') { 28846bfa198SGarance A Drosehn if (savedchar == '\r') 28946bfa198SGarance A Drosehn savedchar = '\n'; 29046bfa198SGarance A Drosehn fputc(savedchar, wstream); 29146bfa198SGarance A Drosehn lastchar = savedchar; 29246bfa198SGarance A Drosehn savedchar = '\0'; 29346bfa198SGarance A Drosehn } 29446bfa198SGarance A Drosehn if (lastchar != '\0' && lastchar != '\n') 29546bfa198SGarance A Drosehn fputc('\n', wstream); 29646bfa198SGarance A Drosehn lastchar = '\0'; 29746bfa198SGarance A Drosehn return; 29846bfa198SGarance A Drosehn } 29946bfa198SGarance A Drosehn 30046bfa198SGarance A Drosehn dest_ch = &destbuf[0]; 30146bfa198SGarance A Drosehn dest_end = dest_ch + sizeof(destbuf); 30246bfa198SGarance A Drosehn chkptr = wbuffer; 30346bfa198SGarance A Drosehn w_end = wbuffer + wlen; 30446bfa198SGarance A Drosehn lastchar = '\0'; 30546bfa198SGarance A Drosehn if (savedchar != '\0') { 30646bfa198SGarance A Drosehn chkptr = &savedchar; 30746bfa198SGarance A Drosehn nxtptr = wbuffer; 30846bfa198SGarance A Drosehn } else 30946bfa198SGarance A Drosehn nxtptr = chkptr + 1; 31046bfa198SGarance A Drosehn 31146bfa198SGarance A Drosehn while (chkptr < w_end) { 31246bfa198SGarance A Drosehn if (nxtptr < w_end) { 31346bfa198SGarance A Drosehn if ((*chkptr == '\r' && *nxtptr == '\n') || 31446bfa198SGarance A Drosehn (*chkptr == '\n' && *nxtptr == '\r')) { 31546bfa198SGarance A Drosehn *dest_ch++ = '\n'; 31646bfa198SGarance A Drosehn /* want to skip past that second character */ 31746bfa198SGarance A Drosehn nxtptr++; 31846bfa198SGarance A Drosehn goto check_next; 31946bfa198SGarance A Drosehn } 32046bfa198SGarance A Drosehn } else { 32146bfa198SGarance A Drosehn /* This is the last byte in the buffer given on this 32246bfa198SGarance A Drosehn * call, so check if it could be the first-byte of a 32346bfa198SGarance A Drosehn * significant two-byte sequence. If it is, then 32446bfa198SGarance A Drosehn * don't write it out now, but save for checking in 32546bfa198SGarance A Drosehn * the next call. 32646bfa198SGarance A Drosehn */ 32746bfa198SGarance A Drosehn savedchar = '\0'; 32846bfa198SGarance A Drosehn if (*chkptr == '\r' || *chkptr == '\n') { 32946bfa198SGarance A Drosehn savedchar = *chkptr; 33046bfa198SGarance A Drosehn break; 33146bfa198SGarance A Drosehn } 33246bfa198SGarance A Drosehn } 33346bfa198SGarance A Drosehn if (*chkptr == '\r') 33446bfa198SGarance A Drosehn *dest_ch++ = '\n'; 33546bfa198SGarance A Drosehn #if 0 /* XXX - don't translate unprintable characters (yet) */ 33646bfa198SGarance A Drosehn else if (*chkptr != '\t' && *chkptr != '\n' && 33746bfa198SGarance A Drosehn !isprintch(*chkptr)) 33846bfa198SGarance A Drosehn *dest_ch++ = '?'; 33946bfa198SGarance A Drosehn #endif 34046bfa198SGarance A Drosehn else 34146bfa198SGarance A Drosehn *dest_ch++ = *chkptr; 34246bfa198SGarance A Drosehn 34346bfa198SGarance A Drosehn check_next: 34446bfa198SGarance A Drosehn chkptr = nxtptr; 34546bfa198SGarance A Drosehn nxtptr = chkptr + 1; 34646bfa198SGarance A Drosehn if (dest_ch >= dest_end) { 34746bfa198SGarance A Drosehn destlen = dest_ch - &destbuf[0]; 34846bfa198SGarance A Drosehn fwrite(destbuf, 1, destlen, wstream); 34946bfa198SGarance A Drosehn lastchar = destbuf[destlen - 1]; 35046bfa198SGarance A Drosehn dest_ch = &destbuf[0]; 35146bfa198SGarance A Drosehn } 35246bfa198SGarance A Drosehn } 35346bfa198SGarance A Drosehn destlen = dest_ch - &destbuf[0]; 35446bfa198SGarance A Drosehn if (destlen > 0) { 35546bfa198SGarance A Drosehn fwrite(destbuf, 1, destlen, wstream); 35646bfa198SGarance A Drosehn lastchar = destbuf[destlen - 1]; 35746bfa198SGarance A Drosehn } 35846bfa198SGarance A Drosehn } 35946bfa198SGarance A Drosehn 36046bfa198SGarance A Drosehn /* 3610b561052SJoerg Wunsch * Print a warning message if there is no daemon present. 3620b561052SJoerg Wunsch */ 36336d0e2a3SJoerg Wunsch static void 3641d1d4a47SEitan Adler daemonwarn(const struct printer *pp) 3650b561052SJoerg Wunsch { 3664a1a0dbeSGarrett Wollman if (pp->remote) 367cc3fd56fSGarance A Drosehn printf("%s: ", local_host); 3680b561052SJoerg Wunsch puts("Warning: no daemon present"); 3690b561052SJoerg Wunsch current[0] = '\0'; 3700b561052SJoerg Wunsch } 3710b561052SJoerg Wunsch 3720b561052SJoerg Wunsch /* 3730b561052SJoerg Wunsch * Print the header for the short listing format 3740b561052SJoerg Wunsch */ 3750b561052SJoerg Wunsch void 376ba7a1ad7SGarance A Drosehn header(void) 3770b561052SJoerg Wunsch { 3786d39e1b7SGarance A Drosehn printf("%s", head0); 3790b561052SJoerg Wunsch col = strlen(head0)+1; 3800b561052SJoerg Wunsch blankfill(SIZCOL); 3816d39e1b7SGarance A Drosehn printf("%s", head1); 3820b561052SJoerg Wunsch } 3830b561052SJoerg Wunsch 3840b561052SJoerg Wunsch void 385ba7a1ad7SGarance A Drosehn inform(const struct printer *pp, char *cf) 3860b561052SJoerg Wunsch { 387c547dbe8SGarance A Drosehn int copycnt, jnum; 388ec6b8da5SGarance A Drosehn char savedname[MAXPATHLEN+1]; 3890b561052SJoerg Wunsch FILE *cfp; 3900b561052SJoerg Wunsch 3910b561052SJoerg Wunsch /* 3920b561052SJoerg Wunsch * There's a chance the control file has gone away 3930b561052SJoerg Wunsch * in the meantime; if this is the case just keep going 3940b561052SJoerg Wunsch */ 3951d1d4a47SEitan Adler PRIV_START 3960b561052SJoerg Wunsch if ((cfp = fopen(cf, "r")) == NULL) 3970b561052SJoerg Wunsch return; 3981d1d4a47SEitan Adler PRIV_END 3990b561052SJoerg Wunsch 4000b561052SJoerg Wunsch if (rank < 0) 4010b561052SJoerg Wunsch rank = 0; 4024a1a0dbeSGarrett Wollman if (pp->remote || garbage || strcmp(cf, current)) 4030b561052SJoerg Wunsch rank++; 404ec6b8da5SGarance A Drosehn 405ec6b8da5SGarance A Drosehn /* 406ec6b8da5SGarance A Drosehn * The cf-file may include commands to print more than one datafile 407ec6b8da5SGarance A Drosehn * from the user. For each datafile, the cf-file contains at least 408ec6b8da5SGarance A Drosehn * one line which starts with some format-specifier ('a'-'z'), and 409ec6b8da5SGarance A Drosehn * a second line ('N'ame) which indicates the original name the user 410ec6b8da5SGarance A Drosehn * specified for that file. There can be multiple format-spec lines 411ec6b8da5SGarance A Drosehn * for a single Name-line, if the user requested multiple copies of 412ec6b8da5SGarance A Drosehn * that file. Standard lpr puts the format-spec line(s) before the 413ec6b8da5SGarance A Drosehn * Name-line, while lprNG puts the Name-line before the format-spec 414ec6b8da5SGarance A Drosehn * line(s). This section needs to handle the lines in either order. 415ec6b8da5SGarance A Drosehn */ 416ec6b8da5SGarance A Drosehn copycnt = 0; 417ec6b8da5SGarance A Drosehn file[0] = '\0'; 418ec6b8da5SGarance A Drosehn savedname[0] = '\0'; 419c547dbe8SGarance A Drosehn jnum = calc_jobnum(cf, NULL); 420a9c48188SBaptiste Daroussin while (get_line(cfp)) { 4210b561052SJoerg Wunsch switch (line[0]) { 4220b561052SJoerg Wunsch case 'P': /* Was this file specified in the user's list? */ 4230b561052SJoerg Wunsch if (!inlist(line+1, cf)) { 4240b561052SJoerg Wunsch fclose(cfp); 4250b561052SJoerg Wunsch return; 4260b561052SJoerg Wunsch } 4270b561052SJoerg Wunsch if (lflag) { 4280b561052SJoerg Wunsch printf("\n%s: ", line+1); 4290b561052SJoerg Wunsch col = strlen(line+1) + 2; 4300b561052SJoerg Wunsch prank(rank); 4310b561052SJoerg Wunsch blankfill(JOBCOL); 4320b561052SJoerg Wunsch printf(" [job %s]\n", cf+3); 4330b561052SJoerg Wunsch } else { 4340b561052SJoerg Wunsch col = 0; 4350b561052SJoerg Wunsch prank(rank); 4360b561052SJoerg Wunsch blankfill(OWNCOL); 437c547dbe8SGarance A Drosehn printf("%-10s %-3d ", line+1, jnum); 4380b561052SJoerg Wunsch col += 16; 4390b561052SJoerg Wunsch first = 1; 4400b561052SJoerg Wunsch } 4410b561052SJoerg Wunsch continue; 4420b561052SJoerg Wunsch default: /* some format specifer and file name? */ 4430b561052SJoerg Wunsch if (line[0] < 'a' || line[0] > 'z') 444ec6b8da5SGarance A Drosehn break; 445ec6b8da5SGarance A Drosehn if (copycnt == 0 || strcmp(file, line+1) != 0) { 4465d7321f6SGarance A Drosehn strlcpy(file, line + 1, sizeof(file)); 447d583a7c3SWarner Losh } 448ec6b8da5SGarance A Drosehn copycnt++; 449ec6b8da5SGarance A Drosehn /* 450a9c48188SBaptiste Daroussin * deliberately 'continue' to another get_line(), so 451ec6b8da5SGarance A Drosehn * all format-spec lines for this datafile are read 452ec6b8da5SGarance A Drosehn * in and counted before calling show() 453ec6b8da5SGarance A Drosehn */ 4540b561052SJoerg Wunsch continue; 4550b561052SJoerg Wunsch case 'N': 4565d7321f6SGarance A Drosehn strlcpy(savedname, line + 1, sizeof(savedname)); 457ec6b8da5SGarance A Drosehn break; 458ec6b8da5SGarance A Drosehn } 459ec6b8da5SGarance A Drosehn if ((file[0] != '\0') && (savedname[0] != '\0')) { 460ec6b8da5SGarance A Drosehn show(savedname, file, copycnt); 461ec6b8da5SGarance A Drosehn copycnt = 0; 4620b561052SJoerg Wunsch file[0] = '\0'; 463ec6b8da5SGarance A Drosehn savedname[0] = '\0'; 4640b561052SJoerg Wunsch } 4650b561052SJoerg Wunsch } 4660b561052SJoerg Wunsch fclose(cfp); 467ec6b8da5SGarance A Drosehn /* check for a file which hasn't been shown yet */ 468ec6b8da5SGarance A Drosehn if (file[0] != '\0') { 469ec6b8da5SGarance A Drosehn if (savedname[0] == '\0') { 470ec6b8da5SGarance A Drosehn /* a safeguard in case the N-ame line is missing */ 4715d7321f6SGarance A Drosehn strlcpy(savedname, file, sizeof(savedname)); 472ec6b8da5SGarance A Drosehn } 473ec6b8da5SGarance A Drosehn show(savedname, file, copycnt); 474ec6b8da5SGarance A Drosehn } 4750b561052SJoerg Wunsch if (!lflag) { 4760b561052SJoerg Wunsch blankfill(SIZCOL); 4770b561052SJoerg Wunsch printf("%ld bytes\n", totsize); 4780b561052SJoerg Wunsch totsize = 0; 4790b561052SJoerg Wunsch } 4800b561052SJoerg Wunsch } 4810b561052SJoerg Wunsch 4820b561052SJoerg Wunsch int 483ba7a1ad7SGarance A Drosehn inlist(char *uname, char *cfile) 4840b561052SJoerg Wunsch { 485c547dbe8SGarance A Drosehn int *r, jnum; 486c547dbe8SGarance A Drosehn char **u; 487c547dbe8SGarance A Drosehn const char *cfhost; 4880b561052SJoerg Wunsch 4890b561052SJoerg Wunsch if (users == 0 && requests == 0) 4900b561052SJoerg Wunsch return(1); 4910b561052SJoerg Wunsch /* 4920b561052SJoerg Wunsch * Check to see if it's in the user list 4930b561052SJoerg Wunsch */ 4940b561052SJoerg Wunsch for (u = user; u < &user[users]; u++) 495ba7a1ad7SGarance A Drosehn if (!strcmp(*u, uname)) 4960b561052SJoerg Wunsch return(1); 4970b561052SJoerg Wunsch /* 4980b561052SJoerg Wunsch * Check the request list 4990b561052SJoerg Wunsch */ 500c547dbe8SGarance A Drosehn jnum = calc_jobnum(cfile, &cfhost); 5010b561052SJoerg Wunsch for (r = requ; r < &requ[requests]; r++) 502c547dbe8SGarance A Drosehn if (*r == jnum && !strcmp(cfhost, from_host)) 5030b561052SJoerg Wunsch return(1); 5040b561052SJoerg Wunsch return(0); 5050b561052SJoerg Wunsch } 5060b561052SJoerg Wunsch 5070b561052SJoerg Wunsch void 508ba7a1ad7SGarance A Drosehn show(const char *nfile, const char *datafile, int copies) 5090b561052SJoerg Wunsch { 5100b561052SJoerg Wunsch if (strcmp(nfile, " ") == 0) 5110b561052SJoerg Wunsch nfile = "(standard input)"; 5120b561052SJoerg Wunsch if (lflag) 513ba7a1ad7SGarance A Drosehn ldump(nfile, datafile, copies); 5140b561052SJoerg Wunsch else 515ba7a1ad7SGarance A Drosehn dump(nfile, datafile, copies); 5160b561052SJoerg Wunsch } 5170b561052SJoerg Wunsch 5180b561052SJoerg Wunsch /* 5190b561052SJoerg Wunsch * Fill the line with blanks to the specified column 5200b561052SJoerg Wunsch */ 5210b561052SJoerg Wunsch void 522ba7a1ad7SGarance A Drosehn blankfill(int tocol) 5230b561052SJoerg Wunsch { 524ba7a1ad7SGarance A Drosehn while (col++ < tocol) 5250b561052SJoerg Wunsch putchar(' '); 5260b561052SJoerg Wunsch } 5270b561052SJoerg Wunsch 5280b561052SJoerg Wunsch /* 5290b561052SJoerg Wunsch * Give the abbreviated dump of the file names 5300b561052SJoerg Wunsch */ 5310b561052SJoerg Wunsch void 532ba7a1ad7SGarance A Drosehn dump(const char *nfile, const char *datafile, int copies) 5330b561052SJoerg Wunsch { 5340b561052SJoerg Wunsch struct stat lbuf; 535be794da7SGarance A Drosehn const char etctmpl[] = ", ..."; 536be794da7SGarance A Drosehn char etc[sizeof(etctmpl)]; 537be794da7SGarance A Drosehn char *lastsep; 538be794da7SGarance A Drosehn short fill, nlen; 539be794da7SGarance A Drosehn short rem, remetc; 5400b561052SJoerg Wunsch 5410b561052SJoerg Wunsch /* 542be794da7SGarance A Drosehn * Print as many filenames as will fit 543be794da7SGarance A Drosehn * (leaving room for the 'total size' field) 5440b561052SJoerg Wunsch */ 5450b561052SJoerg Wunsch fill = first ? 0 : 2; /* fill space for ``, '' */ 546be794da7SGarance A Drosehn nlen = strlen(nfile); 547be794da7SGarance A Drosehn rem = SIZCOL - 1 - col; 548be794da7SGarance A Drosehn if (nlen + fill > rem) { 549be794da7SGarance A Drosehn if (first) { 550be794da7SGarance A Drosehn /* print the right-most part of the name */ 551be794da7SGarance A Drosehn printf("...%s ", &nfile[3+nlen-rem]); 552be794da7SGarance A Drosehn col = SIZCOL; 553be794da7SGarance A Drosehn } else if (rem > 0) { 554be794da7SGarance A Drosehn /* fit as much of the etc-string as we can */ 555be794da7SGarance A Drosehn remetc = rem; 556be794da7SGarance A Drosehn if (rem > strlen(etctmpl)) 557be794da7SGarance A Drosehn remetc = strlen(etctmpl); 558be794da7SGarance A Drosehn etc[0] = '\0'; 559be794da7SGarance A Drosehn strncat(etc, etctmpl, remetc); 5606d39e1b7SGarance A Drosehn printf("%s", etc); 561be794da7SGarance A Drosehn col += remetc; 562be794da7SGarance A Drosehn rem -= remetc; 563be794da7SGarance A Drosehn /* room for the last segment of this filename? */ 564be794da7SGarance A Drosehn lastsep = strrchr(nfile, '/'); 565be794da7SGarance A Drosehn if ((lastsep != NULL) && (rem > strlen(lastsep))) { 566be794da7SGarance A Drosehn /* print the right-most part of this name */ 567be794da7SGarance A Drosehn printf("%s", lastsep); 568be794da7SGarance A Drosehn col += strlen(lastsep); 569be794da7SGarance A Drosehn } else { 570be794da7SGarance A Drosehn /* do not pack any more names in here */ 5710b561052SJoerg Wunsch blankfill(SIZCOL); 5720b561052SJoerg Wunsch } 573be794da7SGarance A Drosehn } 5740b561052SJoerg Wunsch } else { 575be794da7SGarance A Drosehn if (!first) 5760b561052SJoerg Wunsch printf(", "); 5770b561052SJoerg Wunsch printf("%s", nfile); 578be794da7SGarance A Drosehn col += nlen + fill; 5790b561052SJoerg Wunsch } 580be794da7SGarance A Drosehn first = 0; 581be794da7SGarance A Drosehn 5821d1d4a47SEitan Adler PRIV_START 583ba7a1ad7SGarance A Drosehn if (*datafile && !stat(datafile, &lbuf)) 5840b561052SJoerg Wunsch totsize += copies * lbuf.st_size; 5851d1d4a47SEitan Adler PRIV_END 5860b561052SJoerg Wunsch } 5870b561052SJoerg Wunsch 5880b561052SJoerg Wunsch /* 5890b561052SJoerg Wunsch * Print the long info about the file 5900b561052SJoerg Wunsch */ 5910b561052SJoerg Wunsch void 592ba7a1ad7SGarance A Drosehn ldump(const char *nfile, const char *datafile, int copies) 5930b561052SJoerg Wunsch { 5940b561052SJoerg Wunsch struct stat lbuf; 5950b561052SJoerg Wunsch 5960b561052SJoerg Wunsch putchar('\t'); 5970b561052SJoerg Wunsch if (copies > 1) 5980b561052SJoerg Wunsch printf("%-2d copies of %-19s", copies, nfile); 5990b561052SJoerg Wunsch else 6000b561052SJoerg Wunsch printf("%-32s", nfile); 601ba7a1ad7SGarance A Drosehn if (*datafile && !stat(datafile, &lbuf)) 602ef1c4c53SJohn Birrell printf(" %qd bytes", (long long) lbuf.st_size); 6030b561052SJoerg Wunsch else 6040b561052SJoerg Wunsch printf(" ??? bytes"); 6050b561052SJoerg Wunsch putchar('\n'); 6060b561052SJoerg Wunsch } 6070b561052SJoerg Wunsch 6080b561052SJoerg Wunsch /* 6090b561052SJoerg Wunsch * Print the job's rank in the queue, 6100b561052SJoerg Wunsch * update col for screen management 6110b561052SJoerg Wunsch */ 6120b561052SJoerg Wunsch void 613ba7a1ad7SGarance A Drosehn prank(int n) 6140b561052SJoerg Wunsch { 6150b561052SJoerg Wunsch char rline[100]; 616ba7a1ad7SGarance A Drosehn static const char *r[] = { 6170b561052SJoerg Wunsch "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 6180b561052SJoerg Wunsch }; 6190b561052SJoerg Wunsch 6200b561052SJoerg Wunsch if (n == 0) { 6210b561052SJoerg Wunsch printf("active"); 6220b561052SJoerg Wunsch col += 6; 6230b561052SJoerg Wunsch return; 6240b561052SJoerg Wunsch } 6250b561052SJoerg Wunsch if ((n/10)%10 == 1) 6260b561052SJoerg Wunsch (void)snprintf(rline, sizeof(rline), "%dth", n); 6270b561052SJoerg Wunsch else 6280b561052SJoerg Wunsch (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 6290b561052SJoerg Wunsch col += strlen(rline); 6300b561052SJoerg Wunsch printf("%s", rline); 6310b561052SJoerg Wunsch } 632334a9508SJoerg Wunsch 633334a9508SJoerg Wunsch void 634ba7a1ad7SGarance A Drosehn alarmhandler(int signo __unused) 635334a9508SJoerg Wunsch { 636ba7a1ad7SGarance A Drosehn /* the signal is ignored */ 637ba7a1ad7SGarance A Drosehn /* (the '__unused' is just to avoid a compile-time warning) */ 638334a9508SJoerg Wunsch } 639