11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 30117541Sgad#if 0 31117592Sgad#ifndef lint 3215648Sjoergstatic char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; 33117592Sgad#endif /* not lint */ 34117541Sgad#endif 35117592Sgad 36117541Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 37117541Sgad__FBSDID("$FreeBSD$"); 381553Srgrimes 391553Srgrimes#include <sys/param.h> 401553Srgrimes#include <sys/stat.h> 411553Srgrimes 4231492Swollman#include <ctype.h> 4331492Swollman#include <dirent.h> 44241852Seadler#include <err.h> 4531492Swollman#include <errno.h> 4631492Swollman#include <fcntl.h> 471553Srgrimes#include <signal.h> 481553Srgrimes#include <stdio.h> 491553Srgrimes#include <stdlib.h> 501553Srgrimes#include <string.h> 5131492Swollman#define psignal foil_gcc_psignal 5231492Swollman#define sys_siglist foil_gcc_siglist 5331492Swollman#include <unistd.h> 5431492Swollman#undef psignal 5531492Swollman#undef sys_siglist 5631492Swollman 571553Srgrimes#include "lp.h" 581553Srgrimes#include "lp.local.h" 591553Srgrimes#include "pathnames.h" 601553Srgrimes 611553Srgrimes/* 621553Srgrimes * Routines to display the state of the queue. 631553Srgrimes */ 641553Srgrimes#define JOBCOL 40 /* column for job # in -l format */ 651553Srgrimes#define OWNCOL 7 /* start of Owner column in normal */ 661553Srgrimes#define SIZCOL 62 /* start of Size column in normal */ 671553Srgrimes 681553Srgrimes/* 69194859Sgad * isprint() takes a parameter of 'int', but expect values in the range 70194859Sgad * of unsigned char. Define a wrapper which takes a value of type 'char', 71194859Sgad * whether signed or unsigned, and ensure it ends up in the right range. 72194859Sgad */ 73194859Sgad#define isprintch(Anychar) isprint((u_char)(Anychar)) 74194859Sgad 75194859Sgad/* 761553Srgrimes * Stuff for handling job specifications 771553Srgrimes */ 781553Srgrimesstatic int col; /* column on screen */ 7982557Skrisstatic char current[MAXNAMLEN+1]; /* current file being printed */ 8082557Skrisstatic char file[MAXNAMLEN+1]; /* print file name */ 811553Srgrimesstatic int first; /* first file in ``files'' column? */ 821553Srgrimesstatic int garbage; /* # of garbage cf files */ 831553Srgrimesstatic int lflag; /* long output option */ 841553Srgrimesstatic int rank; /* order to be printed (-1=none, 0=active) */ 851553Srgrimesstatic long totsize; /* total print job size in bytes */ 861553Srgrimes 8778146Sgadstatic const char *head0 = "Rank Owner Job Files"; 8878146Sgadstatic const char *head1 = "Total Size\n"; 891553Srgrimes 9078146Sgadstatic void alarmhandler(int _signo); 91194859Sgadstatic void filtered_write(char *_obuffer, int _wlen, FILE *_wstream); 92241852Seadlerstatic void daemonwarn(const struct printer *_pp); 9326844Sjoerg 941553Srgrimes/* 951553Srgrimes * Display the current state of the queue. Format = 1 if long format. 961553Srgrimes */ 971553Srgrimesvoid 9878146Sgaddisplayq(struct printer *pp, int format) 991553Srgrimes{ 10068401Sgad register struct jobqueue *q; 10127618Simp register int i, nitems, fd, ret; 10282557Skris char *cp, *endp; 10368401Sgad struct jobqueue **queue; 1041553Srgrimes struct stat statb; 1051553Srgrimes FILE *fp; 10626844Sjoerg void (*savealrm)(int); 1071553Srgrimes 1081553Srgrimes lflag = format; 1091553Srgrimes totsize = 0; 1101553Srgrimes rank = -1; 11131492Swollman 11231492Swollman if ((cp = checkremote(pp))) { 1131553Srgrimes printf("Warning: %s\n", cp); 11431492Swollman free(cp); 11531492Swollman } 1161553Srgrimes 1171553Srgrimes /* 1181553Srgrimes * Print out local queue 1191553Srgrimes * Find all the control files in the spooling directory 1201553Srgrimes */ 121241852Seadler PRIV_START 12231492Swollman if (chdir(pp->spool_dir) < 0) 12331492Swollman fatal(pp, "cannot chdir to spooling directory: %s", 12431492Swollman strerror(errno)); 125241852Seadler PRIV_END 12631492Swollman if ((nitems = getq(pp, &queue)) < 0) 12731492Swollman fatal(pp, "cannot examine spooling area\n"); 128241852Seadler PRIV_START 12931492Swollman ret = stat(pp->lock_file, &statb); 130241852Seadler PRIV_END 13127618Simp if (ret >= 0) { 13231492Swollman if (statb.st_mode & LFM_PRINT_DIS) { 13331492Swollman if (pp->remote) 13478300Sgad printf("%s: ", local_host); 13531492Swollman printf("Warning: %s is down: ", pp->printer); 136241852Seadler PRIV_START 13731492Swollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 138241852Seadler PRIV_END 1391553Srgrimes if (fd >= 0) { 1401553Srgrimes while ((i = read(fd, line, sizeof(line))) > 0) 1411553Srgrimes (void) fwrite(line, 1, i, stdout); 1421553Srgrimes (void) close(fd); /* unlocks as well */ 1431553Srgrimes } else 1441553Srgrimes putchar('\n'); 1451553Srgrimes } 14631492Swollman if (statb.st_mode & LFM_QUEUE_DIS) { 14731492Swollman if (pp->remote) 14878300Sgad printf("%s: ", local_host); 14931492Swollman printf("Warning: %s queue is turned off\n", 15031492Swollman pp->printer); 1511553Srgrimes } 1521553Srgrimes } 1531553Srgrimes 1541553Srgrimes if (nitems) { 155241852Seadler PRIV_START 15631492Swollman fp = fopen(pp->lock_file, "r"); 157241852Seadler PRIV_END 1581553Srgrimes if (fp == NULL) 159241852Seadler daemonwarn(pp); 1601553Srgrimes else { 1611553Srgrimes /* get daemon pid */ 1621553Srgrimes cp = current; 16382557Skris endp = cp + sizeof(current) - 1; 16482557Skris while ((i = getc(fp)) != EOF && i != '\n') { 16582557Skris if (cp < endp) 16682557Skris *cp++ = i; 16782557Skris } 1681553Srgrimes *cp = '\0'; 1691553Srgrimes i = atoi(current); 17027618Simp if (i <= 0) { 17127618Simp ret = -1; 17227618Simp } else { 173241852Seadler PRIV_START 17427618Simp ret = kill(i, 0); 175241852Seadler PRIV_END 17627618Simp } 17727618Simp if (ret < 0) { 178241852Seadler daemonwarn(pp); 17927618Simp } else { 1801553Srgrimes /* read current file name */ 1811553Srgrimes cp = current; 18282557Skris endp = cp + sizeof(current) - 1; 18382557Skris while ((i = getc(fp)) != EOF && i != '\n') { 18482557Skris if (cp < endp) 18582557Skris *cp++ = i; 18682557Skris } 1871553Srgrimes *cp = '\0'; 1881553Srgrimes /* 1891553Srgrimes * Print the status file. 1901553Srgrimes */ 19131492Swollman if (pp->remote) 19278300Sgad printf("%s: ", local_host); 193241852Seadler PRIV_START 19431492Swollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 195241852Seadler PRIV_END 1961553Srgrimes if (fd >= 0) { 19731492Swollman while ((i = read(fd, line, 19831492Swollman sizeof(line))) > 0) 19931492Swollman fwrite(line, 1, i, stdout); 20031492Swollman close(fd); /* unlocks as well */ 2011553Srgrimes } else 2021553Srgrimes putchar('\n'); 2031553Srgrimes } 2041553Srgrimes (void) fclose(fp); 2051553Srgrimes } 2061553Srgrimes /* 2071553Srgrimes * Now, examine the control files and print out the jobs to 2081553Srgrimes * be done for each user. 2091553Srgrimes */ 2101553Srgrimes if (!lflag) 2111553Srgrimes header(); 2121553Srgrimes for (i = 0; i < nitems; i++) { 2131553Srgrimes q = queue[i]; 21468401Sgad inform(pp, q->job_cfname); 2151553Srgrimes free(q); 2161553Srgrimes } 2171553Srgrimes free(queue); 2181553Srgrimes } 21931492Swollman if (!pp->remote) { 2201553Srgrimes if (nitems == 0) 2211553Srgrimes puts("no entries"); 2221553Srgrimes return; 2231553Srgrimes } 2241553Srgrimes 2251553Srgrimes /* 2261553Srgrimes * Print foreign queue 2271553Srgrimes * Note that a file in transit may show up in either queue. 2281553Srgrimes */ 2291553Srgrimes if (nitems) 2301553Srgrimes putchar('\n'); 23131492Swollman (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3', 23231492Swollman pp->remote_queue); 2331553Srgrimes cp = line; 23427757Simp for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 2351553Srgrimes cp += strlen(cp); 2361553Srgrimes (void) sprintf(cp, " %d", requ[i]); 2371553Srgrimes } 23822466Simp for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 23927757Simp sizeof(line) - 1; i++) { 2401553Srgrimes cp += strlen(cp); 2411553Srgrimes *cp++ = ' '; 2421553Srgrimes (void) strcpy(cp, user[i]); 2431553Srgrimes } 2441553Srgrimes strcat(line, "\n"); 24526844Sjoerg savealrm = signal(SIGALRM, alarmhandler); 24631492Swollman alarm(pp->conn_timeout); 24731492Swollman fd = getport(pp, pp->remote_host, 0); 24831020Sjoerg alarm(0); 24926844Sjoerg (void)signal(SIGALRM, savealrm); 2501553Srgrimes if (fd < 0) { 25178300Sgad if (from_host != local_host) 25278300Sgad printf("%s: ", local_host); 25331492Swollman printf("connection to %s is down\n", pp->remote_host); 2541553Srgrimes } 2551553Srgrimes else { 2561553Srgrimes i = strlen(line); 2571553Srgrimes if (write(fd, line, i) != i) 25831492Swollman fatal(pp, "Lost connection"); 2591553Srgrimes while ((i = read(fd, line, sizeof(line))) > 0) 260194859Sgad filtered_write(line, i, stdout); 261194859Sgad filtered_write(NULL, -1, stdout); 2621553Srgrimes (void) close(fd); 2631553Srgrimes } 2641553Srgrimes} 2651553Srgrimes 2661553Srgrimes/* 267194859Sgad * The lpq-info read from remote hosts may contain unprintable characters, 268194859Sgad * or carriage-returns instead of line-feeds. Clean those up before echoing 269194859Sgad * the lpq-info line(s) to stdout. The info may also be missing any kind of 270194859Sgad * end-of-line character. This also turns CRLF and LFCR into a plain LF. 271194859Sgad * 272194859Sgad * This routine may be called multiple times to process a single set of 273194859Sgad * information, and after a set is finished this routine must be called 274194859Sgad * one extra time with NULL specified as the buffer address. 275194859Sgad */ 276194859Sgadstatic void 277194859Sgadfiltered_write(char *wbuffer, int wlen, FILE *wstream) 278194859Sgad{ 279194859Sgad static char lastchar, savedchar; 280194859Sgad char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end; 281194859Sgad int destlen; 282194859Sgad char destbuf[BUFSIZ]; 283194859Sgad 284194859Sgad if (wbuffer == NULL) { 285194859Sgad if (savedchar != '\0') { 286194859Sgad if (savedchar == '\r') 287194859Sgad savedchar = '\n'; 288194859Sgad fputc(savedchar, wstream); 289194859Sgad lastchar = savedchar; 290194859Sgad savedchar = '\0'; 291194859Sgad } 292194859Sgad if (lastchar != '\0' && lastchar != '\n') 293194859Sgad fputc('\n', wstream); 294194859Sgad lastchar = '\0'; 295194859Sgad return; 296194859Sgad } 297194859Sgad 298194859Sgad dest_ch = &destbuf[0]; 299194859Sgad dest_end = dest_ch + sizeof(destbuf); 300194859Sgad chkptr = wbuffer; 301194859Sgad w_end = wbuffer + wlen; 302194859Sgad lastchar = '\0'; 303194859Sgad if (savedchar != '\0') { 304194859Sgad chkptr = &savedchar; 305194859Sgad nxtptr = wbuffer; 306194859Sgad } else 307194859Sgad nxtptr = chkptr + 1; 308194859Sgad 309194859Sgad while (chkptr < w_end) { 310194859Sgad if (nxtptr < w_end) { 311194859Sgad if ((*chkptr == '\r' && *nxtptr == '\n') || 312194859Sgad (*chkptr == '\n' && *nxtptr == '\r')) { 313194859Sgad *dest_ch++ = '\n'; 314194859Sgad /* want to skip past that second character */ 315194859Sgad nxtptr++; 316194859Sgad goto check_next; 317194859Sgad } 318194859Sgad } else { 319194859Sgad /* This is the last byte in the buffer given on this 320194859Sgad * call, so check if it could be the first-byte of a 321194859Sgad * significant two-byte sequence. If it is, then 322194859Sgad * don't write it out now, but save for checking in 323194859Sgad * the next call. 324194859Sgad */ 325194859Sgad savedchar = '\0'; 326194859Sgad if (*chkptr == '\r' || *chkptr == '\n') { 327194859Sgad savedchar = *chkptr; 328194859Sgad break; 329194859Sgad } 330194859Sgad } 331194859Sgad if (*chkptr == '\r') 332194859Sgad *dest_ch++ = '\n'; 333194859Sgad#if 0 /* XXX - don't translate unprintable characters (yet) */ 334194859Sgad else if (*chkptr != '\t' && *chkptr != '\n' && 335194859Sgad !isprintch(*chkptr)) 336194859Sgad *dest_ch++ = '?'; 337194859Sgad#endif 338194859Sgad else 339194859Sgad *dest_ch++ = *chkptr; 340194859Sgad 341194859Sgadcheck_next: 342194859Sgad chkptr = nxtptr; 343194859Sgad nxtptr = chkptr + 1; 344194859Sgad if (dest_ch >= dest_end) { 345194859Sgad destlen = dest_ch - &destbuf[0]; 346194859Sgad fwrite(destbuf, 1, destlen, wstream); 347194859Sgad lastchar = destbuf[destlen - 1]; 348194859Sgad dest_ch = &destbuf[0]; 349194859Sgad } 350194859Sgad } 351194859Sgad destlen = dest_ch - &destbuf[0]; 352194859Sgad if (destlen > 0) { 353194859Sgad fwrite(destbuf, 1, destlen, wstream); 354194859Sgad lastchar = destbuf[destlen - 1]; 355194859Sgad } 356194859Sgad} 357194859Sgad 358194859Sgad/* 3591553Srgrimes * Print a warning message if there is no daemon present. 3601553Srgrimes */ 36128621Sjoergstatic void 362241852Seadlerdaemonwarn(const struct printer *pp) 3631553Srgrimes{ 36431492Swollman if (pp->remote) 36578300Sgad printf("%s: ", local_host); 3661553Srgrimes puts("Warning: no daemon present"); 3671553Srgrimes current[0] = '\0'; 3681553Srgrimes} 3691553Srgrimes 3701553Srgrimes/* 3711553Srgrimes * Print the header for the short listing format 3721553Srgrimes */ 3731553Srgrimesvoid 37478146Sgadheader(void) 3751553Srgrimes{ 37679739Sgad printf("%s", head0); 3771553Srgrimes col = strlen(head0)+1; 3781553Srgrimes blankfill(SIZCOL); 37979739Sgad printf("%s", head1); 3801553Srgrimes} 3811553Srgrimes 3821553Srgrimesvoid 38378146Sgadinform(const struct printer *pp, char *cf) 3841553Srgrimes{ 385139464Sgad int copycnt, jnum; 38668100Sgad char savedname[MAXPATHLEN+1]; 38768100Sgad FILE *cfp; 3881553Srgrimes 3891553Srgrimes /* 3901553Srgrimes * There's a chance the control file has gone away 3911553Srgrimes * in the meantime; if this is the case just keep going 3921553Srgrimes */ 393241852Seadler PRIV_START 3941553Srgrimes if ((cfp = fopen(cf, "r")) == NULL) 3951553Srgrimes return; 396241852Seadler PRIV_END 3971553Srgrimes 3981553Srgrimes if (rank < 0) 3991553Srgrimes rank = 0; 40031492Swollman if (pp->remote || garbage || strcmp(cf, current)) 4011553Srgrimes rank++; 40268100Sgad 40368100Sgad /* 40468100Sgad * The cf-file may include commands to print more than one datafile 40568100Sgad * from the user. For each datafile, the cf-file contains at least 40668100Sgad * one line which starts with some format-specifier ('a'-'z'), and 40768100Sgad * a second line ('N'ame) which indicates the original name the user 40868100Sgad * specified for that file. There can be multiple format-spec lines 40968100Sgad * for a single Name-line, if the user requested multiple copies of 41068100Sgad * that file. Standard lpr puts the format-spec line(s) before the 41168100Sgad * Name-line, while lprNG puts the Name-line before the format-spec 41268100Sgad * line(s). This section needs to handle the lines in either order. 41368100Sgad */ 41468100Sgad copycnt = 0; 41568100Sgad file[0] = '\0'; 41668100Sgad savedname[0] = '\0'; 417139464Sgad jnum = calc_jobnum(cf, NULL); 4181553Srgrimes while (getline(cfp)) { 4191553Srgrimes switch (line[0]) { 4201553Srgrimes case 'P': /* Was this file specified in the user's list? */ 4211553Srgrimes if (!inlist(line+1, cf)) { 4221553Srgrimes fclose(cfp); 4231553Srgrimes return; 4241553Srgrimes } 4251553Srgrimes if (lflag) { 4261553Srgrimes printf("\n%s: ", line+1); 4271553Srgrimes col = strlen(line+1) + 2; 4281553Srgrimes prank(rank); 4291553Srgrimes blankfill(JOBCOL); 4301553Srgrimes printf(" [job %s]\n", cf+3); 4311553Srgrimes } else { 4321553Srgrimes col = 0; 4331553Srgrimes prank(rank); 4341553Srgrimes blankfill(OWNCOL); 435139464Sgad printf("%-10s %-3d ", line+1, jnum); 4361553Srgrimes col += 16; 4371553Srgrimes first = 1; 4381553Srgrimes } 4391553Srgrimes continue; 4401553Srgrimes default: /* some format specifer and file name? */ 4411553Srgrimes if (line[0] < 'a' || line[0] > 'z') 44268100Sgad break; 44368100Sgad if (copycnt == 0 || strcmp(file, line+1) != 0) { 44480133Sgad strlcpy(file, line + 1, sizeof(file)); 44522466Simp } 44668100Sgad copycnt++; 44768100Sgad /* 44868100Sgad * deliberately 'continue' to another getline(), so 44968100Sgad * all format-spec lines for this datafile are read 45068100Sgad * in and counted before calling show() 45168100Sgad */ 4521553Srgrimes continue; 4531553Srgrimes case 'N': 45480133Sgad strlcpy(savedname, line + 1, sizeof(savedname)); 45568100Sgad break; 45668100Sgad } 45768100Sgad if ((file[0] != '\0') && (savedname[0] != '\0')) { 45868100Sgad show(savedname, file, copycnt); 45968100Sgad copycnt = 0; 4601553Srgrimes file[0] = '\0'; 46168100Sgad savedname[0] = '\0'; 4621553Srgrimes } 4631553Srgrimes } 4641553Srgrimes fclose(cfp); 46568100Sgad /* check for a file which hasn't been shown yet */ 46668100Sgad if (file[0] != '\0') { 46768100Sgad if (savedname[0] == '\0') { 46868100Sgad /* a safeguard in case the N-ame line is missing */ 46980133Sgad strlcpy(savedname, file, sizeof(savedname)); 47068100Sgad } 47168100Sgad show(savedname, file, copycnt); 47268100Sgad } 4731553Srgrimes if (!lflag) { 4741553Srgrimes blankfill(SIZCOL); 4751553Srgrimes printf("%ld bytes\n", totsize); 4761553Srgrimes totsize = 0; 4771553Srgrimes } 4781553Srgrimes} 4791553Srgrimes 4801553Srgrimesint 48178146Sgadinlist(char *uname, char *cfile) 4821553Srgrimes{ 483139464Sgad int *r, jnum; 484139464Sgad char **u; 485139464Sgad const char *cfhost; 4861553Srgrimes 4871553Srgrimes if (users == 0 && requests == 0) 4881553Srgrimes return(1); 4891553Srgrimes /* 4901553Srgrimes * Check to see if it's in the user list 4911553Srgrimes */ 4921553Srgrimes for (u = user; u < &user[users]; u++) 49378146Sgad if (!strcmp(*u, uname)) 4941553Srgrimes return(1); 4951553Srgrimes /* 4961553Srgrimes * Check the request list 4971553Srgrimes */ 498139464Sgad jnum = calc_jobnum(cfile, &cfhost); 4991553Srgrimes for (r = requ; r < &requ[requests]; r++) 500139464Sgad if (*r == jnum && !strcmp(cfhost, from_host)) 5011553Srgrimes return(1); 5021553Srgrimes return(0); 5031553Srgrimes} 5041553Srgrimes 5051553Srgrimesvoid 50678146Sgadshow(const char *nfile, const char *datafile, int copies) 5071553Srgrimes{ 5081553Srgrimes if (strcmp(nfile, " ") == 0) 5091553Srgrimes nfile = "(standard input)"; 5101553Srgrimes if (lflag) 51178146Sgad ldump(nfile, datafile, copies); 5121553Srgrimes else 51378146Sgad dump(nfile, datafile, copies); 5141553Srgrimes} 5151553Srgrimes 5161553Srgrimes/* 5171553Srgrimes * Fill the line with blanks to the specified column 5181553Srgrimes */ 5191553Srgrimesvoid 52078146Sgadblankfill(int tocol) 5211553Srgrimes{ 52278146Sgad while (col++ < tocol) 5231553Srgrimes putchar(' '); 5241553Srgrimes} 5251553Srgrimes 5261553Srgrimes/* 5271553Srgrimes * Give the abbreviated dump of the file names 5281553Srgrimes */ 5291553Srgrimesvoid 53078146Sgaddump(const char *nfile, const char *datafile, int copies) 5311553Srgrimes{ 5321553Srgrimes struct stat lbuf; 53368101Sgad const char etctmpl[] = ", ..."; 53468101Sgad char etc[sizeof(etctmpl)]; 53568101Sgad char *lastsep; 53668101Sgad short fill, nlen; 53768101Sgad short rem, remetc; 5381553Srgrimes 5391553Srgrimes /* 54068101Sgad * Print as many filenames as will fit 54168101Sgad * (leaving room for the 'total size' field) 5421553Srgrimes */ 54368101Sgad fill = first ? 0 : 2; /* fill space for ``, '' */ 54468101Sgad nlen = strlen(nfile); 54568101Sgad rem = SIZCOL - 1 - col; 54668101Sgad if (nlen + fill > rem) { 54768101Sgad if (first) { 54868101Sgad /* print the right-most part of the name */ 54968101Sgad printf("...%s ", &nfile[3+nlen-rem]); 55068101Sgad col = SIZCOL; 55168101Sgad } else if (rem > 0) { 55268101Sgad /* fit as much of the etc-string as we can */ 55368101Sgad remetc = rem; 55468101Sgad if (rem > strlen(etctmpl)) 55568101Sgad remetc = strlen(etctmpl); 55668101Sgad etc[0] = '\0'; 55768101Sgad strncat(etc, etctmpl, remetc); 55879739Sgad printf("%s", etc); 55968101Sgad col += remetc; 56068101Sgad rem -= remetc; 56168101Sgad /* room for the last segment of this filename? */ 56268101Sgad lastsep = strrchr(nfile, '/'); 56368101Sgad if ((lastsep != NULL) && (rem > strlen(lastsep))) { 56468101Sgad /* print the right-most part of this name */ 56568101Sgad printf("%s", lastsep); 56668101Sgad col += strlen(lastsep); 56768101Sgad } else { 56868101Sgad /* do not pack any more names in here */ 56968101Sgad blankfill(SIZCOL); 57068101Sgad } 5711553Srgrimes } 5721553Srgrimes } else { 57368101Sgad if (!first) 5741553Srgrimes printf(", "); 5751553Srgrimes printf("%s", nfile); 57668101Sgad col += nlen + fill; 5771553Srgrimes } 57868101Sgad first = 0; 57968101Sgad 580241852Seadler PRIV_START 58178146Sgad if (*datafile && !stat(datafile, &lbuf)) 5821553Srgrimes totsize += copies * lbuf.st_size; 583241852Seadler PRIV_END 5841553Srgrimes} 5851553Srgrimes 5861553Srgrimes/* 5871553Srgrimes * Print the long info about the file 5881553Srgrimes */ 5891553Srgrimesvoid 59078146Sgadldump(const char *nfile, const char *datafile, int copies) 5911553Srgrimes{ 5921553Srgrimes struct stat lbuf; 5931553Srgrimes 5941553Srgrimes putchar('\t'); 5951553Srgrimes if (copies > 1) 5961553Srgrimes printf("%-2d copies of %-19s", copies, nfile); 5971553Srgrimes else 5981553Srgrimes printf("%-32s", nfile); 59978146Sgad if (*datafile && !stat(datafile, &lbuf)) 60035998Sjb printf(" %qd bytes", (long long) lbuf.st_size); 6011553Srgrimes else 6021553Srgrimes printf(" ??? bytes"); 6031553Srgrimes putchar('\n'); 6041553Srgrimes} 6051553Srgrimes 6061553Srgrimes/* 6071553Srgrimes * Print the job's rank in the queue, 6081553Srgrimes * update col for screen management 6091553Srgrimes */ 6101553Srgrimesvoid 61178146Sgadprank(int n) 6121553Srgrimes{ 6131553Srgrimes char rline[100]; 61478146Sgad static const char *r[] = { 6151553Srgrimes "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 6161553Srgrimes }; 6171553Srgrimes 6181553Srgrimes if (n == 0) { 6191553Srgrimes printf("active"); 6201553Srgrimes col += 6; 6211553Srgrimes return; 6221553Srgrimes } 6231553Srgrimes if ((n/10)%10 == 1) 6241553Srgrimes (void)snprintf(rline, sizeof(rline), "%dth", n); 6251553Srgrimes else 6261553Srgrimes (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 6271553Srgrimes col += strlen(rline); 6281553Srgrimes printf("%s", rline); 6291553Srgrimes} 63026844Sjoerg 63126844Sjoergvoid 63278146Sgadalarmhandler(int signo __unused) 63326844Sjoerg{ 63478146Sgad /* the signal is ignored */ 63578146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 63626844Sjoerg} 637