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> 4431492Swollman#include <errno.h> 4531492Swollman#include <fcntl.h> 461553Srgrimes#include <signal.h> 471553Srgrimes#include <stdio.h> 481553Srgrimes#include <stdlib.h> 491553Srgrimes#include <string.h> 5031492Swollman#define psignal foil_gcc_psignal 5131492Swollman#define sys_siglist foil_gcc_siglist 5231492Swollman#include <unistd.h> 5331492Swollman#undef psignal 5431492Swollman#undef sys_siglist 5531492Swollman 561553Srgrimes#include "lp.h" 571553Srgrimes#include "lp.local.h" 581553Srgrimes#include "pathnames.h" 591553Srgrimes 601553Srgrimes/* 611553Srgrimes * Routines to display the state of the queue. 621553Srgrimes */ 631553Srgrimes#define JOBCOL 40 /* column for job # in -l format */ 641553Srgrimes#define OWNCOL 7 /* start of Owner column in normal */ 651553Srgrimes#define SIZCOL 62 /* start of Size column in normal */ 661553Srgrimes 671553Srgrimes/* 68194859Sgad * isprint() takes a parameter of 'int', but expect values in the range 69194859Sgad * of unsigned char. Define a wrapper which takes a value of type 'char', 70194859Sgad * whether signed or unsigned, and ensure it ends up in the right range. 71194859Sgad */ 72194859Sgad#define isprintch(Anychar) isprint((u_char)(Anychar)) 73194859Sgad 74194859Sgad/* 751553Srgrimes * Stuff for handling job specifications 761553Srgrimes */ 7727618Simpextern uid_t uid, euid; 7827618Simp 791553Srgrimesstatic int col; /* column on screen */ 8082557Skrisstatic char current[MAXNAMLEN+1]; /* current file being printed */ 8182557Skrisstatic char file[MAXNAMLEN+1]; /* print file name */ 821553Srgrimesstatic int first; /* first file in ``files'' column? */ 831553Srgrimesstatic int garbage; /* # of garbage cf files */ 841553Srgrimesstatic int lflag; /* long output option */ 851553Srgrimesstatic int rank; /* order to be printed (-1=none, 0=active) */ 861553Srgrimesstatic long totsize; /* total print job size in bytes */ 871553Srgrimes 8878146Sgadstatic const char *head0 = "Rank Owner Job Files"; 8978146Sgadstatic const char *head1 = "Total Size\n"; 901553Srgrimes 9178146Sgadstatic void alarmhandler(int _signo); 92194859Sgadstatic void filtered_write(char *_obuffer, int _wlen, FILE *_wstream); 9378146Sgadstatic void warn(const struct printer *_pp); 9426844Sjoerg 951553Srgrimes/* 961553Srgrimes * Display the current state of the queue. Format = 1 if long format. 971553Srgrimes */ 981553Srgrimesvoid 9978146Sgaddisplayq(struct printer *pp, int format) 1001553Srgrimes{ 10168401Sgad register struct jobqueue *q; 10227618Simp register int i, nitems, fd, ret; 10382557Skris char *cp, *endp; 10468401Sgad struct jobqueue **queue; 1051553Srgrimes struct stat statb; 1061553Srgrimes FILE *fp; 10726844Sjoerg void (*savealrm)(int); 1081553Srgrimes 1091553Srgrimes lflag = format; 1101553Srgrimes totsize = 0; 1111553Srgrimes rank = -1; 11231492Swollman 11331492Swollman if ((cp = checkremote(pp))) { 1141553Srgrimes printf("Warning: %s\n", cp); 11531492Swollman free(cp); 11631492Swollman } 1171553Srgrimes 1181553Srgrimes /* 1191553Srgrimes * Print out local queue 1201553Srgrimes * Find all the control files in the spooling directory 1211553Srgrimes */ 12227618Simp seteuid(euid); 12331492Swollman if (chdir(pp->spool_dir) < 0) 12431492Swollman fatal(pp, "cannot chdir to spooling directory: %s", 12531492Swollman strerror(errno)); 12627618Simp seteuid(uid); 12731492Swollman if ((nitems = getq(pp, &queue)) < 0) 12831492Swollman fatal(pp, "cannot examine spooling area\n"); 12927618Simp seteuid(euid); 13031492Swollman ret = stat(pp->lock_file, &statb); 13127618Simp seteuid(uid); 13227618Simp if (ret >= 0) { 13331492Swollman if (statb.st_mode & LFM_PRINT_DIS) { 13431492Swollman if (pp->remote) 13578300Sgad printf("%s: ", local_host); 13631492Swollman printf("Warning: %s is down: ", pp->printer); 13727618Simp seteuid(euid); 13831492Swollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 13927618Simp seteuid(uid); 1401553Srgrimes if (fd >= 0) { 1411553Srgrimes while ((i = read(fd, line, sizeof(line))) > 0) 1421553Srgrimes (void) fwrite(line, 1, i, stdout); 1431553Srgrimes (void) close(fd); /* unlocks as well */ 1441553Srgrimes } else 1451553Srgrimes putchar('\n'); 1461553Srgrimes } 14731492Swollman if (statb.st_mode & LFM_QUEUE_DIS) { 14831492Swollman if (pp->remote) 14978300Sgad printf("%s: ", local_host); 15031492Swollman printf("Warning: %s queue is turned off\n", 15131492Swollman pp->printer); 1521553Srgrimes } 1531553Srgrimes } 1541553Srgrimes 1551553Srgrimes if (nitems) { 15627618Simp seteuid(euid); 15731492Swollman fp = fopen(pp->lock_file, "r"); 15827618Simp seteuid(uid); 1591553Srgrimes if (fp == NULL) 16031492Swollman warn(pp); 1611553Srgrimes else { 1621553Srgrimes /* get daemon pid */ 1631553Srgrimes cp = current; 16482557Skris endp = cp + sizeof(current) - 1; 16582557Skris while ((i = getc(fp)) != EOF && i != '\n') { 16682557Skris if (cp < endp) 16782557Skris *cp++ = i; 16882557Skris } 1691553Srgrimes *cp = '\0'; 1701553Srgrimes i = atoi(current); 17127618Simp if (i <= 0) { 17227618Simp ret = -1; 17327618Simp } else { 17427618Simp seteuid(euid); 17527618Simp ret = kill(i, 0); 17627618Simp seteuid(uid); 17727618Simp } 17827618Simp if (ret < 0) { 17931492Swollman warn(pp); 18027618Simp } else { 1811553Srgrimes /* read current file name */ 1821553Srgrimes cp = current; 18382557Skris endp = cp + sizeof(current) - 1; 18482557Skris while ((i = getc(fp)) != EOF && i != '\n') { 18582557Skris if (cp < endp) 18682557Skris *cp++ = i; 18782557Skris } 1881553Srgrimes *cp = '\0'; 1891553Srgrimes /* 1901553Srgrimes * Print the status file. 1911553Srgrimes */ 19231492Swollman if (pp->remote) 19378300Sgad printf("%s: ", local_host); 19427618Simp seteuid(euid); 19531492Swollman fd = open(pp->status_file, O_RDONLY|O_SHLOCK); 19627618Simp seteuid(uid); 1971553Srgrimes if (fd >= 0) { 19831492Swollman while ((i = read(fd, line, 19931492Swollman sizeof(line))) > 0) 20031492Swollman fwrite(line, 1, i, stdout); 20131492Swollman close(fd); /* unlocks as well */ 2021553Srgrimes } else 2031553Srgrimes putchar('\n'); 2041553Srgrimes } 2051553Srgrimes (void) fclose(fp); 2061553Srgrimes } 2071553Srgrimes /* 2081553Srgrimes * Now, examine the control files and print out the jobs to 2091553Srgrimes * be done for each user. 2101553Srgrimes */ 2111553Srgrimes if (!lflag) 2121553Srgrimes header(); 2131553Srgrimes for (i = 0; i < nitems; i++) { 2141553Srgrimes q = queue[i]; 21568401Sgad inform(pp, q->job_cfname); 2161553Srgrimes free(q); 2171553Srgrimes } 2181553Srgrimes free(queue); 2191553Srgrimes } 22031492Swollman if (!pp->remote) { 2211553Srgrimes if (nitems == 0) 2221553Srgrimes puts("no entries"); 2231553Srgrimes return; 2241553Srgrimes } 2251553Srgrimes 2261553Srgrimes /* 2271553Srgrimes * Print foreign queue 2281553Srgrimes * Note that a file in transit may show up in either queue. 2291553Srgrimes */ 2301553Srgrimes if (nitems) 2311553Srgrimes putchar('\n'); 23231492Swollman (void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3', 23331492Swollman pp->remote_queue); 2341553Srgrimes cp = line; 23527757Simp for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) { 2361553Srgrimes cp += strlen(cp); 2371553Srgrimes (void) sprintf(cp, " %d", requ[i]); 2381553Srgrimes } 23922466Simp for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < 24027757Simp sizeof(line) - 1; i++) { 2411553Srgrimes cp += strlen(cp); 2421553Srgrimes *cp++ = ' '; 2431553Srgrimes (void) strcpy(cp, user[i]); 2441553Srgrimes } 2451553Srgrimes strcat(line, "\n"); 24626844Sjoerg savealrm = signal(SIGALRM, alarmhandler); 24731492Swollman alarm(pp->conn_timeout); 24831492Swollman fd = getport(pp, pp->remote_host, 0); 24931020Sjoerg alarm(0); 25026844Sjoerg (void)signal(SIGALRM, savealrm); 2511553Srgrimes if (fd < 0) { 25278300Sgad if (from_host != local_host) 25378300Sgad printf("%s: ", local_host); 25431492Swollman printf("connection to %s is down\n", pp->remote_host); 2551553Srgrimes } 2561553Srgrimes else { 2571553Srgrimes i = strlen(line); 2581553Srgrimes if (write(fd, line, i) != i) 25931492Swollman fatal(pp, "Lost connection"); 2601553Srgrimes while ((i = read(fd, line, sizeof(line))) > 0) 261194859Sgad filtered_write(line, i, stdout); 262194859Sgad filtered_write(NULL, -1, stdout); 2631553Srgrimes (void) close(fd); 2641553Srgrimes } 2651553Srgrimes} 2661553Srgrimes 2671553Srgrimes/* 268194859Sgad * The lpq-info read from remote hosts may contain unprintable characters, 269194859Sgad * or carriage-returns instead of line-feeds. Clean those up before echoing 270194859Sgad * the lpq-info line(s) to stdout. The info may also be missing any kind of 271194859Sgad * end-of-line character. This also turns CRLF and LFCR into a plain LF. 272194859Sgad * 273194859Sgad * This routine may be called multiple times to process a single set of 274194859Sgad * information, and after a set is finished this routine must be called 275194859Sgad * one extra time with NULL specified as the buffer address. 276194859Sgad */ 277194859Sgadstatic void 278194859Sgadfiltered_write(char *wbuffer, int wlen, FILE *wstream) 279194859Sgad{ 280194859Sgad static char lastchar, savedchar; 281194859Sgad char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end; 282194859Sgad int destlen; 283194859Sgad char destbuf[BUFSIZ]; 284194859Sgad 285194859Sgad if (wbuffer == NULL) { 286194859Sgad if (savedchar != '\0') { 287194859Sgad if (savedchar == '\r') 288194859Sgad savedchar = '\n'; 289194859Sgad fputc(savedchar, wstream); 290194859Sgad lastchar = savedchar; 291194859Sgad savedchar = '\0'; 292194859Sgad } 293194859Sgad if (lastchar != '\0' && lastchar != '\n') 294194859Sgad fputc('\n', wstream); 295194859Sgad lastchar = '\0'; 296194859Sgad return; 297194859Sgad } 298194859Sgad 299194859Sgad dest_ch = &destbuf[0]; 300194859Sgad dest_end = dest_ch + sizeof(destbuf); 301194859Sgad chkptr = wbuffer; 302194859Sgad w_end = wbuffer + wlen; 303194859Sgad lastchar = '\0'; 304194859Sgad if (savedchar != '\0') { 305194859Sgad chkptr = &savedchar; 306194859Sgad nxtptr = wbuffer; 307194859Sgad } else 308194859Sgad nxtptr = chkptr + 1; 309194859Sgad 310194859Sgad while (chkptr < w_end) { 311194859Sgad if (nxtptr < w_end) { 312194859Sgad if ((*chkptr == '\r' && *nxtptr == '\n') || 313194859Sgad (*chkptr == '\n' && *nxtptr == '\r')) { 314194859Sgad *dest_ch++ = '\n'; 315194859Sgad /* want to skip past that second character */ 316194859Sgad nxtptr++; 317194859Sgad goto check_next; 318194859Sgad } 319194859Sgad } else { 320194859Sgad /* This is the last byte in the buffer given on this 321194859Sgad * call, so check if it could be the first-byte of a 322194859Sgad * significant two-byte sequence. If it is, then 323194859Sgad * don't write it out now, but save for checking in 324194859Sgad * the next call. 325194859Sgad */ 326194859Sgad savedchar = '\0'; 327194859Sgad if (*chkptr == '\r' || *chkptr == '\n') { 328194859Sgad savedchar = *chkptr; 329194859Sgad break; 330194859Sgad } 331194859Sgad } 332194859Sgad if (*chkptr == '\r') 333194859Sgad *dest_ch++ = '\n'; 334194859Sgad#if 0 /* XXX - don't translate unprintable characters (yet) */ 335194859Sgad else if (*chkptr != '\t' && *chkptr != '\n' && 336194859Sgad !isprintch(*chkptr)) 337194859Sgad *dest_ch++ = '?'; 338194859Sgad#endif 339194859Sgad else 340194859Sgad *dest_ch++ = *chkptr; 341194859Sgad 342194859Sgadcheck_next: 343194859Sgad chkptr = nxtptr; 344194859Sgad nxtptr = chkptr + 1; 345194859Sgad if (dest_ch >= dest_end) { 346194859Sgad destlen = dest_ch - &destbuf[0]; 347194859Sgad fwrite(destbuf, 1, destlen, wstream); 348194859Sgad lastchar = destbuf[destlen - 1]; 349194859Sgad dest_ch = &destbuf[0]; 350194859Sgad } 351194859Sgad } 352194859Sgad destlen = dest_ch - &destbuf[0]; 353194859Sgad if (destlen > 0) { 354194859Sgad fwrite(destbuf, 1, destlen, wstream); 355194859Sgad lastchar = destbuf[destlen - 1]; 356194859Sgad } 357194859Sgad} 358194859Sgad 359194859Sgad/* 3601553Srgrimes * Print a warning message if there is no daemon present. 3611553Srgrimes */ 36228621Sjoergstatic void 36378146Sgadwarn(const struct printer *pp) 3641553Srgrimes{ 36531492Swollman if (pp->remote) 36678300Sgad printf("%s: ", local_host); 3671553Srgrimes puts("Warning: no daemon present"); 3681553Srgrimes current[0] = '\0'; 3691553Srgrimes} 3701553Srgrimes 3711553Srgrimes/* 3721553Srgrimes * Print the header for the short listing format 3731553Srgrimes */ 3741553Srgrimesvoid 37578146Sgadheader(void) 3761553Srgrimes{ 37779739Sgad printf("%s", head0); 3781553Srgrimes col = strlen(head0)+1; 3791553Srgrimes blankfill(SIZCOL); 38079739Sgad printf("%s", head1); 3811553Srgrimes} 3821553Srgrimes 3831553Srgrimesvoid 38478146Sgadinform(const struct printer *pp, char *cf) 3851553Srgrimes{ 386139464Sgad int copycnt, jnum; 38768100Sgad char savedname[MAXPATHLEN+1]; 38868100Sgad FILE *cfp; 3891553Srgrimes 3901553Srgrimes /* 3911553Srgrimes * There's a chance the control file has gone away 3921553Srgrimes * in the meantime; if this is the case just keep going 3931553Srgrimes */ 39427618Simp seteuid(euid); 3951553Srgrimes if ((cfp = fopen(cf, "r")) == NULL) 3961553Srgrimes return; 39727618Simp seteuid(uid); 3981553Srgrimes 3991553Srgrimes if (rank < 0) 4001553Srgrimes rank = 0; 40131492Swollman if (pp->remote || garbage || strcmp(cf, current)) 4021553Srgrimes rank++; 40368100Sgad 40468100Sgad /* 40568100Sgad * The cf-file may include commands to print more than one datafile 40668100Sgad * from the user. For each datafile, the cf-file contains at least 40768100Sgad * one line which starts with some format-specifier ('a'-'z'), and 40868100Sgad * a second line ('N'ame) which indicates the original name the user 40968100Sgad * specified for that file. There can be multiple format-spec lines 41068100Sgad * for a single Name-line, if the user requested multiple copies of 41168100Sgad * that file. Standard lpr puts the format-spec line(s) before the 41268100Sgad * Name-line, while lprNG puts the Name-line before the format-spec 41368100Sgad * line(s). This section needs to handle the lines in either order. 41468100Sgad */ 41568100Sgad copycnt = 0; 41668100Sgad file[0] = '\0'; 41768100Sgad savedname[0] = '\0'; 418139464Sgad jnum = calc_jobnum(cf, NULL); 4191553Srgrimes while (getline(cfp)) { 4201553Srgrimes switch (line[0]) { 4211553Srgrimes case 'P': /* Was this file specified in the user's list? */ 4221553Srgrimes if (!inlist(line+1, cf)) { 4231553Srgrimes fclose(cfp); 4241553Srgrimes return; 4251553Srgrimes } 4261553Srgrimes if (lflag) { 4271553Srgrimes printf("\n%s: ", line+1); 4281553Srgrimes col = strlen(line+1) + 2; 4291553Srgrimes prank(rank); 4301553Srgrimes blankfill(JOBCOL); 4311553Srgrimes printf(" [job %s]\n", cf+3); 4321553Srgrimes } else { 4331553Srgrimes col = 0; 4341553Srgrimes prank(rank); 4351553Srgrimes blankfill(OWNCOL); 436139464Sgad printf("%-10s %-3d ", line+1, jnum); 4371553Srgrimes col += 16; 4381553Srgrimes first = 1; 4391553Srgrimes } 4401553Srgrimes continue; 4411553Srgrimes default: /* some format specifer and file name? */ 4421553Srgrimes if (line[0] < 'a' || line[0] > 'z') 44368100Sgad break; 44468100Sgad if (copycnt == 0 || strcmp(file, line+1) != 0) { 44580133Sgad strlcpy(file, line + 1, sizeof(file)); 44622466Simp } 44768100Sgad copycnt++; 44868100Sgad /* 44968100Sgad * deliberately 'continue' to another getline(), so 45068100Sgad * all format-spec lines for this datafile are read 45168100Sgad * in and counted before calling show() 45268100Sgad */ 4531553Srgrimes continue; 4541553Srgrimes case 'N': 45580133Sgad strlcpy(savedname, line + 1, sizeof(savedname)); 45668100Sgad break; 45768100Sgad } 45868100Sgad if ((file[0] != '\0') && (savedname[0] != '\0')) { 45968100Sgad show(savedname, file, copycnt); 46068100Sgad copycnt = 0; 4611553Srgrimes file[0] = '\0'; 46268100Sgad savedname[0] = '\0'; 4631553Srgrimes } 4641553Srgrimes } 4651553Srgrimes fclose(cfp); 46668100Sgad /* check for a file which hasn't been shown yet */ 46768100Sgad if (file[0] != '\0') { 46868100Sgad if (savedname[0] == '\0') { 46968100Sgad /* a safeguard in case the N-ame line is missing */ 47080133Sgad strlcpy(savedname, file, sizeof(savedname)); 47168100Sgad } 47268100Sgad show(savedname, file, copycnt); 47368100Sgad } 4741553Srgrimes if (!lflag) { 4751553Srgrimes blankfill(SIZCOL); 4761553Srgrimes printf("%ld bytes\n", totsize); 4771553Srgrimes totsize = 0; 4781553Srgrimes } 4791553Srgrimes} 4801553Srgrimes 4811553Srgrimesint 48278146Sgadinlist(char *uname, char *cfile) 4831553Srgrimes{ 484139464Sgad int *r, jnum; 485139464Sgad char **u; 486139464Sgad const char *cfhost; 4871553Srgrimes 4881553Srgrimes if (users == 0 && requests == 0) 4891553Srgrimes return(1); 4901553Srgrimes /* 4911553Srgrimes * Check to see if it's in the user list 4921553Srgrimes */ 4931553Srgrimes for (u = user; u < &user[users]; u++) 49478146Sgad if (!strcmp(*u, uname)) 4951553Srgrimes return(1); 4961553Srgrimes /* 4971553Srgrimes * Check the request list 4981553Srgrimes */ 499139464Sgad jnum = calc_jobnum(cfile, &cfhost); 5001553Srgrimes for (r = requ; r < &requ[requests]; r++) 501139464Sgad if (*r == jnum && !strcmp(cfhost, from_host)) 5021553Srgrimes return(1); 5031553Srgrimes return(0); 5041553Srgrimes} 5051553Srgrimes 5061553Srgrimesvoid 50778146Sgadshow(const char *nfile, const char *datafile, int copies) 5081553Srgrimes{ 5091553Srgrimes if (strcmp(nfile, " ") == 0) 5101553Srgrimes nfile = "(standard input)"; 5111553Srgrimes if (lflag) 51278146Sgad ldump(nfile, datafile, copies); 5131553Srgrimes else 51478146Sgad dump(nfile, datafile, copies); 5151553Srgrimes} 5161553Srgrimes 5171553Srgrimes/* 5181553Srgrimes * Fill the line with blanks to the specified column 5191553Srgrimes */ 5201553Srgrimesvoid 52178146Sgadblankfill(int tocol) 5221553Srgrimes{ 52378146Sgad while (col++ < tocol) 5241553Srgrimes putchar(' '); 5251553Srgrimes} 5261553Srgrimes 5271553Srgrimes/* 5281553Srgrimes * Give the abbreviated dump of the file names 5291553Srgrimes */ 5301553Srgrimesvoid 53178146Sgaddump(const char *nfile, const char *datafile, int copies) 5321553Srgrimes{ 5331553Srgrimes struct stat lbuf; 53468101Sgad const char etctmpl[] = ", ..."; 53568101Sgad char etc[sizeof(etctmpl)]; 53668101Sgad char *lastsep; 53768101Sgad short fill, nlen; 53868101Sgad short rem, remetc; 5391553Srgrimes 5401553Srgrimes /* 54168101Sgad * Print as many filenames as will fit 54268101Sgad * (leaving room for the 'total size' field) 5431553Srgrimes */ 54468101Sgad fill = first ? 0 : 2; /* fill space for ``, '' */ 54568101Sgad nlen = strlen(nfile); 54668101Sgad rem = SIZCOL - 1 - col; 54768101Sgad if (nlen + fill > rem) { 54868101Sgad if (first) { 54968101Sgad /* print the right-most part of the name */ 55068101Sgad printf("...%s ", &nfile[3+nlen-rem]); 55168101Sgad col = SIZCOL; 55268101Sgad } else if (rem > 0) { 55368101Sgad /* fit as much of the etc-string as we can */ 55468101Sgad remetc = rem; 55568101Sgad if (rem > strlen(etctmpl)) 55668101Sgad remetc = strlen(etctmpl); 55768101Sgad etc[0] = '\0'; 55868101Sgad strncat(etc, etctmpl, remetc); 55979739Sgad printf("%s", etc); 56068101Sgad col += remetc; 56168101Sgad rem -= remetc; 56268101Sgad /* room for the last segment of this filename? */ 56368101Sgad lastsep = strrchr(nfile, '/'); 56468101Sgad if ((lastsep != NULL) && (rem > strlen(lastsep))) { 56568101Sgad /* print the right-most part of this name */ 56668101Sgad printf("%s", lastsep); 56768101Sgad col += strlen(lastsep); 56868101Sgad } else { 56968101Sgad /* do not pack any more names in here */ 57068101Sgad blankfill(SIZCOL); 57168101Sgad } 5721553Srgrimes } 5731553Srgrimes } else { 57468101Sgad if (!first) 5751553Srgrimes printf(", "); 5761553Srgrimes printf("%s", nfile); 57768101Sgad col += nlen + fill; 5781553Srgrimes } 57968101Sgad first = 0; 58068101Sgad 58127618Simp seteuid(euid); 58278146Sgad if (*datafile && !stat(datafile, &lbuf)) 5831553Srgrimes totsize += copies * lbuf.st_size; 58427618Simp seteuid(uid); 5851553Srgrimes} 5861553Srgrimes 5871553Srgrimes/* 5881553Srgrimes * Print the long info about the file 5891553Srgrimes */ 5901553Srgrimesvoid 59178146Sgadldump(const char *nfile, const char *datafile, int copies) 5921553Srgrimes{ 5931553Srgrimes struct stat lbuf; 5941553Srgrimes 5951553Srgrimes putchar('\t'); 5961553Srgrimes if (copies > 1) 5971553Srgrimes printf("%-2d copies of %-19s", copies, nfile); 5981553Srgrimes else 5991553Srgrimes printf("%-32s", nfile); 60078146Sgad if (*datafile && !stat(datafile, &lbuf)) 60135998Sjb printf(" %qd bytes", (long long) lbuf.st_size); 6021553Srgrimes else 6031553Srgrimes printf(" ??? bytes"); 6041553Srgrimes putchar('\n'); 6051553Srgrimes} 6061553Srgrimes 6071553Srgrimes/* 6081553Srgrimes * Print the job's rank in the queue, 6091553Srgrimes * update col for screen management 6101553Srgrimes */ 6111553Srgrimesvoid 61278146Sgadprank(int n) 6131553Srgrimes{ 6141553Srgrimes char rline[100]; 61578146Sgad static const char *r[] = { 6161553Srgrimes "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 6171553Srgrimes }; 6181553Srgrimes 6191553Srgrimes if (n == 0) { 6201553Srgrimes printf("active"); 6211553Srgrimes col += 6; 6221553Srgrimes return; 6231553Srgrimes } 6241553Srgrimes if ((n/10)%10 == 1) 6251553Srgrimes (void)snprintf(rline, sizeof(rline), "%dth", n); 6261553Srgrimes else 6271553Srgrimes (void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]); 6281553Srgrimes col += strlen(rline); 6291553Srgrimes printf("%s", rline); 6301553Srgrimes} 63126844Sjoerg 63226844Sjoergvoid 63378146Sgadalarmhandler(int signo __unused) 63426844Sjoerg{ 63578146Sgad /* the signal is ignored */ 63678146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 63726844Sjoerg} 638