Index: stable/2.2/usr.sbin/lpr/common_source/rmjob.c =================================================================== --- stable/2.2/usr.sbin/lpr/common_source/rmjob.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/common_source/rmjob.c (revision 29845) @@ -1,361 +1,365 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" #include "pathnames.h" /* * rmjob - remove the specified jobs from the queue. */ /* * Stuff for handling lprm specifications */ static char root[] = "root"; static int all = 0; /* eliminate all files (root only) */ static int cur_daemon; /* daemon's pid */ static char current[40]; /* active control file name */ extern uid_t uid, euid; /* real and effective user id's */ static void do_unlink __P((char *)); void rmjob() { register int i, nitems; int assasinated = 0; struct dirent **files; char *cp; if ((i = cgetent(&bp, printcapdb, printer)) == -2) fatal("can't open printer description file"); else if (i == -1) fatal("unknown printer"); else if (i == -3) fatal("potential reference loop detected in printcap file"); if (cgetstr(bp, "lp", &LP) < 0) LP = _PATH_DEFDEVLP; if (cgetstr(bp, "rp", &RP) < 0) RP = DEFLP; if (cgetstr(bp, "sd", &SD) < 0) SD = _PATH_DEFSPOOL; if (cgetstr(bp,"lo", &LO) < 0) LO = DEFLOCK; cgetstr(bp, "rm", &RM); if ((cp = checkremote())) printf("Warning: %s\n", cp); /* * If the format was `lprm -' and the user isn't the super-user, * then fake things to look like he said `lprm user'. */ if (users < 0) { if (getuid() == 0) all = 1; /* all files in local queue */ else { user[0] = person; users = 1; } } if (!strcmp(person, "-all")) { if (from == host) fatal("The login name \"-all\" is reserved"); all = 1; /* all those from 'from' */ person = root; } seteuid(euid); if (chdir(SD) < 0) fatal("cannot chdir to spool directory"); if ((nitems = scandir(".", &files, iscf, NULL)) < 0) fatal("cannot access spool directory"); seteuid(uid); if (nitems) { /* * Check for an active printer daemon (in which case we * kill it if it is reading our file) then remove stuff * (after which we have to restart the daemon). */ if (lockchk(LO) && chk(current)) { seteuid(euid); assasinated = kill(cur_daemon, SIGINT) == 0; seteuid(uid); if (!assasinated) fatal("cannot kill printer daemon"); } /* * process the files */ for (i = 0; i < nitems; i++) process(files[i]->d_name); } rmremote(); /* * Restart the printer daemon if it was killed */ if (assasinated && !startdaemon(printer)) fatal("cannot restart printer daemon\n"); exit(0); } /* * Process a lock file: collect the pid of the active * daemon and the file name of the active spool entry. * Return boolean indicating existence of a lock file. */ int lockchk(s) char *s; { register FILE *fp; register int i, n; seteuid(euid); if ((fp = fopen(s, "r")) == NULL) { if (errno == EACCES) fatal("can't access lock file"); else return(0); } seteuid(uid); if (!getline(fp)) { (void) fclose(fp); return(0); /* no daemon present */ } cur_daemon = atoi(line); if (kill(cur_daemon, 0) < 0 && errno != EPERM) { (void) fclose(fp); return(0); /* no daemon present */ } for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) { if (i > 5) { n = 1; break; } sleep(i); } current[n-1] = '\0'; (void) fclose(fp); return(1); } /* * Process a control file. */ void process(file) char *file; { FILE *cfp; if (!chk(file)) return; seteuid(euid); if ((cfp = fopen(file, "r")) == NULL) fatal("cannot open %s", file); seteuid(uid); while (getline(cfp)) { switch (line[0]) { case 'U': /* unlink associated files */ if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) break; if (from != host) printf("%s: ", host); do_unlink(line+1); } } (void) fclose(cfp); do_unlink(file); } static void do_unlink(file) char *file; { int ret; if (from != host) printf("%s: ", host); seteuid(euid); ret = unlink(file); seteuid(uid); printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file); } /* * Do the dirty work in checking */ int chk(file) char *file; { register int *r, n; register char **u, *cp; FILE *cfp; /* * Check for valid cf file name (mostly checking current). */ if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f') return(0); if (all && (from == host || !strcmp(from, file+6))) return(1); /* * get the owner's name from the control file. */ seteuid(euid); if ((cfp = fopen(file, "r")) == NULL) return(0); seteuid(uid); while (getline(cfp)) { if (line[0] == 'P') break; } (void) fclose(cfp); if (line[0] != 'P') return(0); if (users == 0 && requests == 0) return(!strcmp(file, current) && isowner(line+1, file)); /* * Check the request list */ for (n = 0, cp = file+3; isdigit(*cp); ) n = n * 10 + (*cp++ - '0'); for (r = requ; r < &requ[requests]; r++) if (*r == n && isowner(line+1, file)) return(1); /* * Check to see if it's in the user list */ for (u = user; u < &user[users]; u++) if (!strcmp(*u, line+1) && isowner(line+1, file)) return(1); return(0); } /* * If root is removing a file on the local machine, allow it. * If root is removing a file from a remote machine, only allow * files sent from the remote machine to be removed. * Normal users can only remove the file from where it was sent. */ int isowner(owner, file) char *owner, *file; { if (!strcmp(person, root) && (from == host || !strcmp(from, file+6))) return(1); if (!strcmp(person, owner) && !strcmp(from, file+6)) return(1); if (from != host) printf("%s: ", host); printf("%s: Permission denied\n", file); return(0); } /* * Check to see if we are sending files to a remote machine. If we are, * then try removing files on the remote machine. */ void rmremote() { register char *cp; register int i, rem; char buf[BUFSIZ]; if (!remote) return; /* not sending to a remote machine */ /* * Flush stdout so the user can see what has been deleted * while we wait (possibly) for the connection. */ fflush(stdout); (void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person); cp = buf; for (i = 0; i < users && cp-buf+1+strlen(user[i]) < sizeof(buf); i++) { cp += strlen(cp); *cp++ = ' '; strcpy(cp, user[i]); } for (i = 0; i < requests && cp-buf+10 < sizeof(buf) - 1; i++) { cp += strlen(cp); (void) sprintf(cp, " %d", requ[i]); } strcat(cp, "\n"); rem = getport(RM, 0); if (rem < 0) { if (from != host) printf("%s: ", host); printf("connection to %s is down\n", RM); } else { i = strlen(buf); if (write(rem, buf, i) != i) fatal("Lost connection"); while ((i = read(rem, buf, sizeof(buf))) > 0) (void) fwrite(buf, 1, i, stdout); (void) close(rem); } } /* * Return 1 if the filename begins with 'cf' */ int iscf(d) struct dirent *d; { return(d->d_name[0] == 'c' && d->d_name[1] == 'f'); } Index: stable/2.2/usr.sbin/lpr/common_source/startdaemon.c =================================================================== --- stable/2.2/usr.sbin/lpr/common_source/startdaemon.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/common_source/startdaemon.c (revision 29845) @@ -1,114 +1,109 @@ /* * Copyright (c) 1983, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ #include #include #include #include -#include +#include #include -#include #include +#include #include "lp.h" #include "pathnames.h" extern uid_t uid, euid; -static void perr __P((char *)); - /* * Tell the printer daemon that there are new files in the spool directory. */ int startdaemon(printer) char *printer; { struct sockaddr_un un; register int s, n; char buf[BUFSIZ]; s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { - perr("socket"); + warn("socket"); return(0); } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; strcpy(un.sun_path, _PATH_SOCKETNAME); #ifndef SUN_LEN #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif seteuid(euid); if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { seteuid(uid); - perr("connect"); + warn("connect"); (void) close(s); return(0); } seteuid(uid); if (snprintf(buf, sizeof(buf), "\1%s\n", printer) > sizeof(buf) - 1) { close(s); return (0); } n = strlen(buf); if (write(s, buf, n) != n) { - perr("write"); + warn("write"); (void) close(s); return(0); } if (read(s, buf, 1) == 1) { if (buf[0] == '\0') { /* everything is OK */ (void) close(s); return(1); } putchar(buf[0]); } while ((n = read(s, buf, sizeof(buf))) > 0) fwrite(buf, 1, n, stdout); (void) close(s); return(0); -} - -static void -perr(msg) - char *msg; -{ - (void)printf("%s: %s: %s\n", name, msg, strerror(errno)); } Index: stable/2.2/usr.sbin/lpr/lp/lp.1 =================================================================== --- stable/2.2/usr.sbin/lpr/lp/lp.1 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lp/lp.1 (revision 29845) @@ -1,110 +1,107 @@ .\" .\" Copyright (c) 1995 Joerg Wunsch .\" .\" All rights reserved. .\" .\" This program is free software. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by Joerg Wunsch .\" 4. The name of the developer may not be used to endorse or promote .\" products derived from this software without specific prior written .\" permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $Id: lp.1,v 1.2 1996/05/11 18:56:09 joerg Exp $ +.\" $Id: lp.1,v 1.2.2.1 1997/09/19 06:18:19 charnier Exp $ .\" .Dd January 22, 1995 .Dt LP 1 .Os .Sh NAME .Nm lp .Nd front-end to the print spooler .Sh SYNOPSIS .Nm lp .Op Fl c -.Op Fl d printer +.Op Fl d Ar printer .Op Fl n Ar num .Op Ar name ... .Sh DESCRIPTION .Nm Lp is a front-end to the print spooler as required by the .St -p1003.2 specification. It effectively invokes .Xr lpr 1 with the proper set of arguments. It generally prints the named files on the destination printer. .Pp -Option -.Fl c -makes the +The following options are available: +.Bl -tag -width indent +.It Fl c +Make the .Nm command exit only after further access to any of the input files is no longer required. The application can then safely delete or modify the files without affecting the output operation. - -To specify a particular printer, option -.Fl d Ar dest -can be used. If no +.It Fl d Ar dest +Specify a particular printer. If no .Fl d is provided on the command line, the contents of the environment variables .Ev LPDEST or .Ev PRINTER .Pq with this precedence are taken as the destination printer. - -Option -.Fl n Ar num -can be used to specify that +.It Fl n Ar num +Specify that .Ar num copies of each of the named files shall be printed. - +.El .Sh ENVIRONMENT As described above, the variables .Ev LPDEST and .Ev PRINTER are examined to select the destination printer. .Sh SEE ALSO .Xr lpr 1 .Sh STANDARDS The -.Nm lp +.Nm command is expected to comply with the .St -p1003.2 specification. .Sh AUTHOR This implementation of the .Nm command has been written by .if t J\(:org Wunsch. .if n Joerg Wunsch. .Sh BUGS The .St -p1003.2 specification does not provide any means to print non-text files. It rather requires the files to be printed to be text files limited to reasonable line lengths and printable characters. Index: stable/2.2/usr.sbin/lpr/lpc/lpc.8 =================================================================== --- stable/2.2/usr.sbin/lpr/lpc/lpc.8 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpc/lpc.8 (revision 29845) @@ -1,175 +1,175 @@ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)lpc.8 8.5 (Berkeley) 4/28/95 .\" .Dd April 28, 1995 .Dt LPC 8 .Os BSD 4.2 .Sh NAME .Nm lpc .Nd line printer control program .Sh SYNOPSIS .Nm lpc .Oo .Ar command .Op Ar argument ... .Oc .Sh DESCRIPTION .Nm Lpc is used by the system administrator to control the operation of the line printer system. For each line printer configured in .Pa /etc/printcap , .Nm lpc may be used to: .Bl -bullet -offset indent .It disable or enable a printer, .It disable or enable a printer's spooling queue, .It rearrange the order of jobs in a spooling queue, .It find the status of printers, and their associated spooling queues and printer daemons. .El .Pp Without any arguments, -.Nm lpc +.Nm will prompt for commands from the standard input. If arguments are supplied, -.Nm lpc +.Nm interprets the first argument as a command and the remaining arguments as parameters to the command. The standard input may be redirected causing -.Nm lpc +.Nm to read commands from file. Commands may be abbreviated; the following is the list of recognized commands. .Pp .Bl -tag -width Ds -compact .It Ic \&? No [ command ... ] .It Ic help No [ command ... ] Print a short description of each command specified in the argument list, or, if no argument is given, a list of the recognized commands. .Pp .It Ic abort No {\ all\ |\ printer\ } Terminate an active spooling daemon on the local host immediately and then disable printing (preventing new daemons from being started by .Xr lpr 1 ) for the specified printers. .Pp .It Ic clean No {\ all\ |\ printer\ } Remove any temporary files, data files, and control files that cannot be printed (i.e., do not form a complete printer job) from the specified printer queue(s) on the local machine. .Pp .It Ic disable No {\ all\ |\ printer\ } Turn the specified printer queues off. This prevents new printer jobs from being entered into the queue by .Xr lpr 1 . .Pp .It Ic down No {\ all\ |\ printer\ } message ... Turn the specified printer queue off, disable printing and put .Em message in the printer status file. The message doesn't need to be quoted, the remaining arguments are treated like .Xr echo 1 . This is normally used to take a printer down and let others know why .Xr lpq 1 will indicate the printer is down and print the status message). .Pp .It Ic enable No {\ all\ |\ printer\ } Enable spooling on the local queue for the listed printers. This will allow .Xr lpr 1 to put new jobs in the spool queue. .Pp .It Ic exit .It Ic quit Exit from lpc. .\" ne 1i .Pp .It Ic restart No {\ all\ |\ printer\ } Attempt to start a new printer daemon. This is useful when some abnormal condition causes the daemon to die unexpectedly, leaving jobs in the queue. .Xr Lpq 1 will report that there is no daemon present when this condition occurs. If the user is the super-user, try to abort the current daemon first (i.e., kill and restart a stuck daemon). .Pp .It Ic start No {\ all\ |\ printer\ } Enable printing and start a spooling daemon for the listed printers. .Pp .It Ic status No {\ all\ |\ printer\ } Display the status of daemons and queues on the local machine. .Pp .It Ic stop No {\ all\ |\ printer\ } Stop a spooling daemon after the current job completes and disable printing. .Pp .It Ic topq No printer\ [\ jobnum\ ...\ ]\ [\ user\ ...\ ] Place the jobs in the order listed at the top of the printer queue. .Pp .It Ic up No {\ all\ |\ printer\ } Enable everything and start a new printer daemon. Undoes the effects of .Ic down . .Sh FILES .Bl -tag -width /var/spool/*/lockx -compact .It Pa /etc/printcap printer description file .It Pa /var/spool/* spool directories .It Pa /var/spool/*/lock lock file for queue control .El .Sh SEE ALSO .Xr lpq 1 , .Xr lpr 1 , .Xr lprm 1 , .Xr printcap 5 , .Xr lpd 8 .Sh DIAGNOSTICS .Bl -tag -width Ds .It Sy "?Ambiguous command" abbreviation matches more than one command .It Sy "?Invalid command" no match was found .It Sy "?Privileged command" you must be a member of group "operator" or root to execute this command .El .Sh HISTORY The .Nm command appeared in .Bx 4.2 . Index: stable/2.2/usr.sbin/lpr/lpc/lpc.c =================================================================== --- stable/2.2/usr.sbin/lpr/lpc/lpc.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpc/lpc.c (revision 29845) @@ -1,321 +1,322 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ #include +#include #include -#include +#include #include -#include -#include -#include +#include #include -#include +#include +#include #include -#include +#include #include #include "lp.h" #include "lpc.h" #include "extern.h" #ifndef LPR_OPER #define LPR_OPER "operator" /* group name of lpr operators */ #endif /* * lpc -- line printer control program */ #define MAX_CMDLINE 200 #define MAX_MARGV 20 int fromatty; char cmdline[MAX_CMDLINE]; int margc; char *margv[MAX_MARGV]; int top; uid_t uid, euid; jmp_buf toplevel; static void cmdscanner __P((int)); static struct cmd *getcmd __P((char *)); static void intr __P((int)); static void makeargv __P((void)); static int ingroup __P((char *)); int main(argc, argv) int argc; char *argv[]; { register struct cmd *c; euid = geteuid(); uid = getuid(); seteuid(uid); name = argv[0]; openlog("lpd", 0, LOG_LPR); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); exit(1); } if (c == 0) { printf("?Invalid command\n"); exit(1); } if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); exit(1); } (*c->c_handler)(argc, argv); exit(0); } fromatty = isatty(fileno(stdin)); top = setjmp(toplevel) == 0; if (top) signal(SIGINT, intr); for (;;) { cmdscanner(top); top = 1; } } static void intr(signo) int signo; { if (!fromatty) exit(0); longjmp(toplevel, 1); } /* * Command parser. */ static void cmdscanner(top) int top; { register struct cmd *c; if (!top) putchar('\n'); for (;;) { if (fromatty) { printf("lpc> "); fflush(stdout); } if (fgets(cmdline, MAX_CMDLINE, stdin) == 0) quit(0, NULL); if (cmdline[0] == 0 || cmdline[0] == '\n') break; makeargv(); c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } if (c == 0) { printf("?Invalid command\n"); continue; } if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); continue; } (*c->c_handler)(margc, margv); } longjmp(toplevel, 0); } static struct cmd * getcmd(name) register char *name; { register char *p, *q; register struct cmd *c, *found; register int nmatches, longest; longest = 0; nmatches = 0; found = 0; for (c = cmdtab; (p = c->c_name); c++) { for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ return(c); if (!*q) { /* the name was a prefix */ if (q - name > longest) { longest = q - name; nmatches = 1; found = c; } else if (q - name == longest) nmatches++; } } if (nmatches > 1) return((struct cmd *)-1); return(found); } /* * Slice a string up into argc/argv. */ static void makeargv() { register char *cp; register char **argp = margv; register int n = 0; margc = 0; for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && n < MAX_MARGV; n++) { while (isspace(*cp)) cp++; if (*cp == '\0') break; *argp++ = cp; margc += 1; while (*cp != '\0' && !isspace(*cp)) cp++; if (*cp == '\0') break; *cp++ = '\0'; } *argp++ = 0; } #define HELPINDENT (sizeof ("directory")) /* * Help command. */ void help(argc, argv) int argc; char *argv[]; { register struct cmd *c; if (argc == 1) { register int i, j, w; int columns, width = 0, lines; printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c->c_name; c++) { int len = strlen(c->c_name); if (len > width) width = len; } width = (width + 8) &~ 7; columns = 80 / width; if (columns == 0) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { for (j = 0; j < columns; j++) { c = cmdtab + j * lines + i; if (c->c_name) printf("%s", c->c_name); if (c + lines >= &cmdtab[NCMDS]) { printf("\n"); break; } w = strlen(c->c_name); while (w < width) { w = (w + 8) &~ 7; putchar('\t'); } } } return; } while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (c == (struct cmd *)-1) printf("?Ambiguous help command %s\n", arg); else if (c == (struct cmd *)0) printf("?Invalid help command %s\n", arg); else printf("%-*s\t%s\n", HELPINDENT, c->c_name, c->c_help); } } /* * return non-zero if the user is a member of the given group */ static int ingroup(grname) char *grname; { static struct group *gptr=NULL; static gid_t groups[NGROUPS]; register gid_t gid; register int i; if (gptr == NULL) { if ((gptr = getgrnam(grname)) == NULL) { - fprintf(stderr, "Warning: unknown group '%s'\n", - grname); + warnx("warning: unknown group '%s'", grname); return(0); } - if (getgroups(NGROUPS, groups) < 0) { - perror("getgroups"); - exit(1); - } + if (getgroups(NGROUPS, groups) < 0) + err(1, "getgroups"); } gid = gptr->gr_gid; for (i = 0; i < NGROUPS; i++) if (gid == groups[i]) return(1); return(0); } Index: stable/2.2/usr.sbin/lpr/lpd/lpd.8 =================================================================== --- stable/2.2/usr.sbin/lpr/lpd/lpd.8 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpd/lpd.8 (revision 29845) @@ -1,256 +1,256 @@ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)lpd.8 8.3 (Berkeley) 4/19/94 .\" .Dd April 19, 1994 .Dt LPD 8 .Os BSD 4.2 .Sh NAME .Nm lpd .Nd line printer spooler daemon .Sh SYNOPSIS .Nm lpd .Op Fl dl .Op Ar port# .Sh DESCRIPTION .Nm Lpd is the line printer daemon (spool area handler) and is normally invoked at boot time from the .Xr rc 8 file. It makes a single pass through the .Xr printcap 5 file to find out about the existing printers and prints any files left after a crash. It then uses the system calls .Xr listen 2 and .Xr accept 2 to receive requests to print files in the queue, transfer files to the spooling area, display the queue, or remove jobs from the queue. In each case, it forks a child to handle the request so the parent can continue to listen for more requests. .Pp Available options: .Bl -tag -width Ds .It Fl d Turn on .Dv SO_DEBUG on the Internet listening socket (see .Xr setsockopt 2 ) . .It Fl l The .Fl l flag causes -.Nm lpd +.Nm to log valid requests received from the network. This can be useful for debugging purposes. .It Ar "port#" The Internet port number used to rendezvous with other processes is normally obtained with .Xr getservbyname 3 but can be changed with the .Ar port# argument. .El .Pp Access control is provided by two means. First, all requests must come from one of the machines listed in the file .Pa /etc/hosts.equiv or .Pa /etc/hosts.lpd . Second, if the .Li rs capability is specified in the .Xr printcap entry for the printer being accessed, .Em lpr requests will only be honored for those users with accounts on the machine with the printer. .Pp The file .Em minfree in each spool directory contains the number of disk blocks to leave free so that the line printer queue won't completely fill the disk. The .Em minfree file can be edited with your favorite text editor. .Pp The daemon begins processing files after it has successfully set the lock for exclusive access (described a bit later), and scans the spool directory for files beginning with .Em cf . Lines in each .Em cf file specify files to be printed or non-printing actions to be performed. Each such line begins with a key character to specify what to do with the remainder of the line. .Bl -tag -width Ds .It J Job Name. String to be used for the job name on the burst page. .It C Classification. String to be used for the classification line on the burst page. .It L Literal. The line contains identification info from the password file and causes the banner page to be printed. .It T Title. String to be used as the title for .Xr pr 1 . .It H Host Name. Name of the machine where .Xr lpr was invoked. .It P Person. Login name of the person who invoked .Xr lpr . This is used to verify ownership by .Xr lprm . .It M Send mail to the specified user when the current print job completes. .It f Formatted File. Name of a file to print which is already formatted. .It l Like ``f'' but passes control characters and does not make page breaks. .It p Name of a file to print using .Xr pr 1 as a filter. .It t Troff File. The file contains .Xr troff 1 output (cat phototypesetter commands). .It n Ditroff File. The file contains device independent troff output. .It r DVI File. The file contains .Tn Tex l output DVI format from Standford. .It g Graph File. The file contains data produced by .Xr plot 3 . .It c Cifplot File. The file contains data produced by .Em cifplot . .It v The file contains a raster image. .It r The file contains text data with FORTRAN carriage control characters. .It \&1 Troff Font R. Name of the font file to use instead of the default. .It \&2 Troff Font I. Name of the font file to use instead of the default. .It \&3 Troff Font B. Name of the font file to use instead of the default. .It \&4 Troff Font S. Name of the font file to use instead of the default. .It W Width. Changes the page width (in characters) used by .Xr pr 1 and the text filters. .It I Indent. The number of characters to indent the output by (in ascii). .It U Unlink. Name of file to remove upon completion of printing. .It N File name. The name of the file which is being printed, or a blank for the standard input (when .Xr lpr is invoked in a pipeline). .El .Pp If a file cannot be opened, a message will be logged via .Xr syslog 3 using the .Em LOG_LPR facility. .Nm Lpd will try up to 20 times to reopen a file it expects to be there, after which it will skip the file to be printed. .Pp .Nm Lpd uses .Xr flock 2 to provide exclusive access to the lock file and to prevent multiple daemons from becoming active simultaneously. If the daemon should be killed or die unexpectedly, the lock file need not be removed. The lock file is kept in a readable .Tn ASCII form and contains two lines. The first is the process id of the daemon and the second is the control file name of the current job being printed. The second line is updated to reflect the current status of -.Nm lpd +.Nm for the programs .Xr lpq 1 and .Xr lprm 1 . .Sh FILES .Bl -tag -width "/var/spool/*/minfree" -compact .It Pa /etc/printcap printer description file .It Pa /var/spool/* spool directories .It Pa /var/spool/*/minfree minimum free space to leave .It Pa /dev/lp* line printer devices .It Pa /var/run/printer socket for local requests .It Pa /etc/hosts.equiv lists machine names allowed printer access .It Pa /etc/hosts.lpd lists machine names allowed printer access, but not under same administrative control. .El .Sh SEE ALSO .Xr lpq 1 , .Xr lpr 1 , .Xr lprm 1 , .Xr setsockopt 2 , .Xr syslog 3 , .Xr hosts.lpd 5 , .Xr printcap 5 , .Xr lpc 8 , .Xr pac 8 .Rs .%T "4.2 BSD Line Printer Spooler Manual" .Re .Sh HISTORY An .Nm daemon appeared in Version 6 AT&T UNIX. Index: stable/2.2/usr.sbin/lpr/lpd/lpd.c =================================================================== --- stable/2.2/usr.sbin/lpr/lpd/lpd.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpd/lpd.c (revision 29845) @@ -1,610 +1,615 @@ /* * Copyright (c) 1983, 1993, 1994 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ /* * lpd -- line printer daemon. * * Listen for a connection and perform the requested operation. * Operations are: * \1printer\n * check the queue for jobs and print any found. * \2printer\n * receive a job from another machine and queue it. * \3printer [users ...] [jobs ...]\n * return the current state of the queue (short form). * \4printer [users ...] [jobs ...]\n * return the current state of the queue (long form). * \5printer person [users ...] [jobs ...]\n * remove jobs from the queue. * * Strategy to maintain protected spooling area: * 1. Spooling area is writable only by daemon and spooling group * 2. lpr runs setuid root and setgrp spooling group; it uses * root to access any file it wants (verifying things before * with an access call) and group id to know how it should * set up ownership of files in the spooling area. * 3. Files in spooling area are owned by root, group spooling * group, with mode 660. * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to * access files and printer. Users can't get to anything * w/o help of lpq and lprm programs. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" #include "pathnames.h" #include "extern.h" int lflag; /* log requests flag */ int from_remote; /* from remote socket */ static void reapchild __P((int)); static void mcleanup __P((int)); static void doit __P((void)); static void startup __P((void)); static void chkhost __P((struct sockaddr_in *)); static int ckqueue __P((char *)); static void usage __P((void)); uid_t uid, euid; int main(argc, argv) int argc; char **argv; { int f, funix, finet, options, fromlen, i, errs; fd_set defreadfds; struct sockaddr_un un, fromunix; struct sockaddr_in sin, frominet; int omask, lfd; struct servent *sp, serv; euid = geteuid(); /* these shouldn't be different */ uid = getuid(); options = 0; gethostname(host, sizeof(host)); name = "lpd"; if (euid != 0) errx(EX_NOPERM,"must run as root"); errs = 0; while ((i = getopt(argc, argv, "dl")) != -1) switch (i) { case 'd': options |= SO_DEBUG; break; case 'l': lflag++; break; default: errs++; } argc -= optind; argv += optind; if (errs) usage(); if (argc == 1) { if ((i = atoi(argv[0])) == 0) usage(); if (i < 0 || i > USHRT_MAX) errx(EX_USAGE, "port # %d is invalid", i); serv.s_port = htons(i); sp = &serv; argc--; } else { sp = getservbyname("printer", "tcp"); if (sp == NULL) errx(EX_OSFILE, "printer/tcp: unknown service"); } if (argc != 0) usage(); #ifndef DEBUG /* * Set up standard environment by detaching from the parent. */ daemon(0, 0); #endif openlog("lpd", LOG_PID, LOG_LPR); syslog(LOG_INFO, "restarted"); (void) umask(0); lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); if (lfd < 0) { syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); exit(1); } if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { if (errno == EWOULDBLOCK) /* active deamon present */ exit(0); syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); exit(1); } ftruncate(lfd, 0); /* * write process id for others to know */ sprintf(line, "%u\n", getpid()); f = strlen(line); if (write(lfd, line, f) != f) { syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); exit(1); } signal(SIGCHLD, reapchild); /* * Restart all the printers. */ startup(); (void) unlink(_PATH_SOCKETNAME); funix = socket(AF_UNIX, SOCK_STREAM, 0); if (funix < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); } #define mask(s) (1 << ((s) - 1)) omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); (void) umask(07); signal(SIGHUP, mcleanup); signal(SIGINT, mcleanup); signal(SIGQUIT, mcleanup); signal(SIGTERM, mcleanup); memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; strcpy(un.sun_path, _PATH_SOCKETNAME); #ifndef SUN_LEN #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { syslog(LOG_ERR, "ubind: %m"); exit(1); } (void) umask(0); sigsetmask(omask); FD_ZERO(&defreadfds); FD_SET(funix, &defreadfds); listen(funix, 5); finet = socket(AF_INET, SOCK_STREAM, 0); if (finet >= 0) { if (options & SO_DEBUG) if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); mcleanup(0); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = sp->s_port; if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { syslog(LOG_ERR, "bind: %m"); mcleanup(0); } FD_SET(finet, &defreadfds); listen(finet, 5); } /* * Main loop: accept, do a request, continue. */ memset(&frominet, 0, sizeof(frominet)); memset(&fromunix, 0, sizeof(fromunix)); for (;;) { int domain, nfds, s; fd_set readfds; FD_COPY(&defreadfds, &readfds); nfds = select(20, &readfds, 0, 0, 0); if (nfds <= 0) { if (nfds < 0 && errno != EINTR) syslog(LOG_WARNING, "select: %m"); continue; } if (FD_ISSET(funix, &readfds)) { domain = AF_UNIX, fromlen = sizeof(fromunix); s = accept(funix, (struct sockaddr *)&fromunix, &fromlen); } else /* if (FD_ISSET(finet, &readfds)) */ { domain = AF_INET, fromlen = sizeof(frominet); s = accept(finet, (struct sockaddr *)&frominet, &fromlen); if (frominet.sin_port == htons(20)) { close(s); continue; } } if (s < 0) { if (errno != EINTR) syslog(LOG_WARNING, "accept: %m"); continue; } if (fork() == 0) { signal(SIGCHLD, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); (void) close(funix); (void) close(finet); dup2(s, 1); (void) close(s); if (domain == AF_INET) { from_remote = 1; chkhost(&frominet); } else from_remote = 0; doit(); exit(0); } (void) close(s); } } static void reapchild(signo) int signo; { union wait status; while (wait3((int *)&status, WNOHANG, 0) > 0) ; } static void mcleanup(signo) int signo; { if (lflag) syslog(LOG_INFO, "exiting"); unlink(_PATH_SOCKETNAME); exit(0); } /* * Stuff for handling job specifications */ char *user[MAXUSERS]; /* users to process */ int users; /* # of users in user array */ int requ[MAXREQUESTS]; /* job number of spool entries */ int requests; /* # of spool requests */ char *person; /* name of person doing lprm */ char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ char cbuf[BUFSIZ]; /* command line buffer */ char *cmdnames[] = { "null", "printjob", "recvjob", "displayq short", "displayq long", "rmjob" }; static void doit() { register char *cp; register int n; for (;;) { cp = cbuf; do { if (cp >= &cbuf[sizeof(cbuf) - 1]) fatal("Command line too long"); if ((n = read(1, cp, 1)) != 1) { if (n < 0) fatal("Lost connection"); return; } } while (*cp++ != '\n'); *--cp = '\0'; cp = cbuf; if (lflag) { if (*cp >= '\1' && *cp <= '\5') syslog(LOG_INFO, "%s requests %s %s", from, cmdnames[*cp], cp+1); else syslog(LOG_INFO, "bad request (%d) from %s", *cp, from); } switch (*cp++) { case '\1': /* check the queue and print any jobs there */ printer = cp; printjob(); break; case '\2': /* receive files to be queued */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); } printer = cp; recvjob(); break; case '\3': /* display the queue (short form) */ case '\4': /* display the queue (long form) */ printer = cp; while (*cp) { if (*cp != ' ') { cp++; continue; } *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0') break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) fatal("Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) fatal("Too many users"); user[users++] = cp; } } displayq(cbuf[0] - '\3'); exit(0); case '\5': /* remove a job from the queue */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); } printer = cp; while (*cp && *cp != ' ') cp++; if (!*cp) break; *cp++ = '\0'; person = cp; while (*cp) { if (*cp != ' ') { cp++; continue; } *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0') break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) fatal("Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) fatal("Too many users"); user[users++] = cp; } } rmjob(); break; } fatal("Illegal service request"); } } /* * Make a pass through the printcap database and start printing any * files left from the last time the machine went down. */ static void startup() { char *buf; register char *cp; int pid; char *spooldirs[16]; /* Which spooldirs are active? */ int i; /* Printer index presently processed */ int j; /* Printer index of potential conflict */ char *spooldir; /* Spooldir of present printer */ int canfreespool; /* Is the spooldir malloc()ed? */ /* * Restart the daemons and test for spooldir conflict. */ i = 0; while (cgetnext(&buf, printcapdb) > 0) { /* Check for duplicate spooldirs */ canfreespool = 1; if (cgetstr(buf, "sd", &spooldir) <= 0) { spooldir = _PATH_DEFSPOOL; canfreespool = 0; } if (i < sizeof(spooldirs)/sizeof(spooldirs[0])) spooldirs[i] = spooldir; for (j = 0; j < MIN(i,sizeof(spooldirs)/sizeof(spooldirs[0])); j++) { if (strcmp(spooldir, spooldirs[j]) == 0) { syslog(LOG_ERR, "startup: duplicate spool directories: %s", spooldir); mcleanup(0); } } if (canfreespool && i >= sizeof(spooldirs)/sizeof(spooldirs[0])) free(spooldir); i++; /* Spooldir test done */ if (ckqueue(buf) <= 0) { free(buf); continue; /* no work to do for this printer */ } for (cp = buf; *cp; cp++) if (*cp == '|' || *cp == ':') { *cp = '\0'; break; } if (lflag) syslog(LOG_INFO, "work for %s", buf); if ((pid = fork()) < 0) { syslog(LOG_WARNING, "startup: cannot fork"); mcleanup(0); } if (!pid) { printer = buf; cgetclose(); printjob(); /* NOTREACHED */ } else free(buf); } } /* * Make sure there's some work to do before forking off a child */ static int ckqueue(cap) char *cap; { register struct dirent *d; DIR *dirp; char *spooldir; if (cgetstr(cap, "sd", &spooldir) == -1) spooldir = _PATH_DEFSPOOL; if ((dirp = opendir(spooldir)) == NULL) return (-1); while ((d = readdir(dirp)) != NULL) { if (d->d_name[0] != 'c' || d->d_name[1] != 'f') continue; /* daemon control files only */ closedir(dirp); return (1); /* found something */ } closedir(dirp); return (0); } #define DUMMY ":nobody::" /* * Check to see if the from host has access to the line printer. */ static void chkhost(f) struct sockaddr_in *f; { register struct hostent *hp; register FILE *hostf; int first = 1; int good = 0; /* Need real hostname for temporary filenames */ hp = gethostbyaddr((char *)&f->sin_addr, sizeof(struct in_addr), f->sin_family); if (hp == NULL) fatal("Host name for your address (%s) unknown", inet_ntoa(f->sin_addr)); (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); from[sizeof(fromb) - 1] = '\0'; from = fromb; /* Check for spoof, ala rlogind */ hp = gethostbyname(fromb); if (!hp) fatal("hostname for your address (%s) unknown", inet_ntoa(f->sin_addr)); for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, sizeof(f->sin_addr))) good = 1; } if (good == 0) fatal("address for your hostname (%s) not matched", inet_ntoa(f->sin_addr)); hostf = fopen(_PATH_HOSTSEQUIV, "r"); again: if (hostf) { if (__ivaliduser(hostf, f->sin_addr.s_addr, DUMMY, DUMMY) == 0) { (void) fclose(hostf); return; } (void) fclose(hostf); } if (first == 1) { first = 0; hostf = fopen(_PATH_HOSTSLPD, "r"); goto again; } fatal("Your host does not have line printer access"); /*NOTREACHED*/ } -void +static void usage() { - errx(EX_USAGE, "usage: lpd [-dl] [port#]"); + fprintf(stderr, "usage: lpd [-dl] [port#]\n"); + exit(EX_USAGE); } Index: stable/2.2/usr.sbin/lpr/lpd/recvjob.c =================================================================== --- stable/2.2/usr.sbin/lpr/lpd/recvjob.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpd/recvjob.c (revision 29845) @@ -1,366 +1,370 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ /* * Receive printer jobs from the network, queue them and * start the printer daemon. */ #include #include #include #include #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" #include "extern.h" #include "pathnames.h" #define ack() (void) write(1, sp, 1); static char dfname[NAME_MAX]; /* data files */ static int minfree; /* keep at least minfree blocks available */ static char *sp = ""; static char tfname[NAME_MAX]; /* tmp copy of cf before linking */ static int chksize __P((int)); static void frecverr __P((const char *, ...)); static int noresponse __P((void)); static void rcleanup __P((int)); static int read_number __P((char *)); static int readfile __P((char *, int)); static int readjob __P((void)); void recvjob() { struct stat stb; int status; /* * Perform lookup for printer name or abbreviation */ if ((status = cgetent(&bp, printcapdb, printer)) == -2) frecverr("cannot open printer description file"); else if (status == -1) frecverr("unknown printer %s", printer); else if (status == -3) fatal("potential reference loop detected in printcap file"); if (cgetstr(bp, "lf", &LF) == -1) LF = _PATH_CONSOLE; if (cgetstr(bp, "sd", &SD) == -1) SD = _PATH_DEFSPOOL; if (cgetstr(bp, "lo", &LO) == -1) LO = DEFLOCK; (void) close(2); /* set up log file */ if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { syslog(LOG_ERR, "%s: %m", LF); (void) open(_PATH_DEVNULL, O_WRONLY); } if (chdir(SD) < 0) frecverr("%s: %s: %m", printer, SD); if (stat(LO, &stb) == 0) { if (stb.st_mode & 010) { /* queue is disabled */ putchar('\1'); /* return error code */ exit(1); } } else if (stat(SD, &stb) < 0) frecverr("%s: %s: %m", printer, SD); minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ signal(SIGTERM, rcleanup); signal(SIGPIPE, rcleanup); if (readjob()) printjob(); } /* * Read printer jobs sent by lpd and copy them to the spooling directory. * Return the number of jobs successfully transfered. */ static int readjob() { register int size, nfiles; register char *cp; ack(); nfiles = 0; for (;;) { /* * Read a command to tell us what to do */ cp = line; do { if ((size = read(1, cp, 1)) != 1) { if (size < 0) - frecverr("%s: Lost connection", + frecverr("%s: lost connection", printer); return(nfiles); } } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); if (cp - line + 1 >= sizeof(line)) frecverr("readjob overflow"); *--cp = '\0'; cp = line; switch (*cp++) { case '\1': /* cleanup because data sent was bad */ rcleanup(0); continue; case '\2': /* read cf file */ size = 0; while (*cp >= '0' && *cp <= '9') size = size * 10 + (*cp++ - '0'); if (*cp++ != ' ') break; /* * host name has been authenticated, we use our * view of the host name since we may be passed * something different than what gethostbyaddr() * returns */ strncpy(cp + 6, from, sizeof(line) + line - cp - 7); line[sizeof(line) - 1 ] = '\0'; strncpy(tfname, cp, sizeof(tfname) - 1); tfname[sizeof (tfname) - 1] = '\0'; tfname[0] = 't'; if (strchr(tfname, '/')) frecverr("readjob: %s: illegal path name", tfname); if (!chksize(size)) { (void) write(1, "\2", 1); continue; } if (!readfile(tfname, size)) { rcleanup(0); continue; } if (link(tfname, cp) < 0) frecverr("%s: %m", tfname); (void) unlink(tfname); tfname[0] = '\0'; nfiles++; continue; case '\3': /* read df file */ size = 0; while (*cp >= '0' && *cp <= '9') size = size * 10 + (*cp++ - '0'); if (*cp++ != ' ') break; if (!chksize(size)) { (void) write(1, "\2", 1); continue; } (void) strncpy(dfname, cp, sizeof(dfname) - 1); dfname[sizeof(dfname) - 1] = '\0'; if (strchr(dfname, '/')) frecverr("readjob: %s: illegal path name", dfname); (void) readfile(dfname, size); continue; } frecverr("protocol screwup: %s", line); } } /* * Read files send by lpd and copy them to the spooling directory. */ static int readfile(file, size) char *file; int size; { register char *cp; char buf[BUFSIZ]; register int i, j, amt; int fd, err; fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); if (fd < 0) frecverr("readfile: %s: illegal path name: %m", file); ack(); err = 0; for (i = 0; i < size; i += BUFSIZ) { amt = BUFSIZ; cp = buf; if (i + amt > size) amt = size - i; do { j = read(1, cp, amt); if (j <= 0) - frecverr("Lost connection"); + frecverr("lost connection"); amt -= j; cp += j; } while (amt > 0); amt = BUFSIZ; if (i + amt > size) amt = size - i; if (write(fd, buf, amt) != amt) { err++; break; } } (void) close(fd); if (err) frecverr("%s: write error", file); if (noresponse()) { /* file sent had bad data in it */ (void) unlink(file); return(0); } ack(); return(1); } static int noresponse() { char resp; if (read(1, &resp, 1) != 1) - frecverr("Lost connection"); + frecverr("lost connection"); if (resp == '\0') return(0); return(1); } /* * Check to see if there is enough space on the disk for size bytes. * 1 == OK, 0 == Not OK. */ static int chksize(size) int size; { int spacefree; struct statfs sfb; if (statfs(".", &sfb) < 0) { syslog(LOG_ERR, "%s: %m", "statfs(\".\")"); return (1); } spacefree = sfb.f_bavail * (sfb.f_bsize / 512); size = (size + 511) / 512; if (minfree + size > spacefree) return(0); return(1); } static int read_number(fn) char *fn; { char lin[80]; register FILE *fp; if ((fp = fopen(fn, "r")) == NULL) return (0); if (fgets(lin, 80, fp) == NULL) { fclose(fp); return (0); } fclose(fp); return (atoi(lin)); } /* * Remove all the files associated with the current job being transfered. */ static void rcleanup(signo) int signo; { if (tfname[0]) (void) unlink(tfname); if (dfname[0]) do { do (void) unlink(dfname); while (dfname[2]-- != 'A'); dfname[2] = 'z'; } while (dfname[0]-- != 'd'); dfname[0] = '\0'; } #ifdef __STDC__ #include #else #include #endif static void #ifdef __STDC__ frecverr(const char *msg, ...) #else frecverr(msg, va_alist) char *msg; va_dcl #endif { va_list ap; #ifdef __STDC__ va_start(ap, msg); #else va_start(ap); #endif rcleanup(0); syslog(LOG_ERR, "%s", fromb); vsyslog(LOG_ERR, msg, ap); va_end(ap); putchar('\1'); /* return error code */ exit(1); } Index: stable/2.2/usr.sbin/lpr/lpq/lpq.1 =================================================================== --- stable/2.2/usr.sbin/lpr/lpq/lpq.1 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpq/lpq.1 (revision 29845) @@ -1,136 +1,136 @@ .\" Copyright (c) 1983, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)lpq.1 8.2 (Berkeley) 4/28/95 .\" .Dd April 28, 1995 .Dt LPQ 1 .Os BSD 4.2 .Sh NAME .Nm lpq .Nd spool queue examination program .Sh SYNOPSIS .Nm lpq .Op Fl a .Op Fl l .Op Fl P Ns Ar printer .Op job # ... .Op user ... .Sh DESCRIPTION .Nm Lpq examines the spooling area used by .Xr lpd 8 for printing files on the line printer, and reports the status of the specified jobs or all jobs associated with a user. .Nm Lpq invoked without any arguments reports on any jobs currently in the queue. .Pp Options: .Pp .Bl -tag -width indent .It Fl P Specify a particular printer, otherwise the default line printer is used (or the value of the .Ev PRINTER variable in the environment). All other arguments supplied are interpreted as user names or job numbers to filter out only those jobs of interest. .It Fl l Information about each of the files comprising the job entry is printed. Normally, only as much information as will fit on one line is displayed. .It Fl a Report on the local queues for all printers, rather than just the specified printer. .El .Pp For each job submitted (i.e. invocation of .Xr lpr 1 ) -.Nm lpq +.Nm reports the user's name, current rank in the queue, the names of files comprising the job, the job identifier (a number which may be supplied to .Xr lprm 1 for removing a specific job), and the total size in bytes. Job ordering is dependent on the algorithm used to scan the spooling directory and is supposed to be .Tn FIFO (First in First Out). File names comprising a job may be unavailable (when .Xr lpr 1 is used as a sink in a pipeline) in which case the file is indicated as ``(standard input)''. .Pp If -.Nm lpq +.Nm warns that there is no daemon present (i.e. due to some malfunction), the .Xr lpc 8 command can be used to restart the printer daemon. .Sh ENVIRONMENT If the following environment variable exists, it is used by .Nm lpq : .Bl -tag -width PRINTER .It Ev PRINTER Specifies an alternate default printer. .El .Sh FILES .Bl -tag -width "/var/spool/*/lock" -compact .It Pa /etc/printcap To determine printer characteristics. .It Pa /var/spool/* The spooling directory, as determined from printcap. .It Pa /var/spool/*/cf* Control files specifying jobs. .It Pa /var/spool/*/lock The lock file to obtain the currently active job. .El .Sh SEE ALSO .Xr lpr 1 , .Xr lprm 1 , .Xr lpc 8 , .Xr lpd 8 .Sh HISTORY .Nm Lpq appeared in .Bx 3 . .Sh BUGS Due to the dynamic nature of the information in the spooling directory -.Nm lpq +.Nm may report unreliably. Output formatting is sensitive to the line length of the terminal; this can results in widely spaced columns. .Sh DIAGNOSTICS Unable to open various files. The lock file being malformed. Garbage files when there is no daemon active, but files in the spooling directory. Index: stable/2.2/usr.sbin/lpr/lpq/lpq.c =================================================================== --- stable/2.2/usr.sbin/lpr/lpq/lpq.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpq/lpq.c (revision 29845) @@ -1,178 +1,177 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95"; #endif /* not lint */ /* * Spool Queue examination program * * lpq [-a] [-l] [-Pprinter] [user...] [job...] * * -a show all non-null queues on the local machine * -l long output * -P used to identify printer as per lpr/lprm */ #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" #include "pathnames.h" int requ[MAXREQUESTS]; /* job number of spool entries */ int requests; /* # of spool requests */ char *user[MAXUSERS]; /* users to process */ int users; /* # of users in user array */ uid_t uid, euid; static int ckqueue __P((char *)); -void usage __P((void)); +static void usage __P((void)); int main(argc, argv) register int argc; register char **argv; { extern char *optarg; extern int optind; int ch, aflag, lflag; char *buf, *cp; euid = geteuid(); uid = getuid(); seteuid(uid); name = *argv; - if (gethostname(host, sizeof(host))) { - perror("lpq: gethostname"); - exit(1); - } + if (gethostname(host, sizeof(host))) + err(1, "gethostname"); openlog("lpd", 0, LOG_LPR); aflag = lflag = 0; while ((ch = getopt(argc, argv, "alP:")) != -1) switch((char)ch) { case 'a': ++aflag; break; case 'l': /* long output */ ++lflag; break; case 'P': /* printer name */ printer = optarg; break; case '?': default: usage(); } if (!aflag && printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; for (argc -= optind, argv += optind; argc; --argc, ++argv) if (isdigit(argv[0][0])) { if (requests >= MAXREQUESTS) fatal("too many requests"); requ[requests++] = atoi(*argv); } else { if (users >= MAXUSERS) fatal("too many users"); user[users++] = *argv; } if (aflag) { while (cgetnext(&buf, printcapdb) > 0) { if (ckqueue(buf) <= 0) { free(buf); continue; /* no jobs */ } for (cp = buf; *cp; cp++) if (*cp == '|' || *cp == ':') { *cp = '\0'; break; } printer = buf; printf("%s:\n", printer); displayq(lflag); free(buf); printf("\n"); } } else displayq(lflag); exit(0); } static int ckqueue(cap) char *cap; { register struct dirent *d; DIR *dirp; char *spooldir; if (cgetstr(cap, "sd", &spooldir) == -1) spooldir = _PATH_DEFSPOOL; if ((dirp = opendir(spooldir)) == NULL) return (-1); while ((d = readdir(dirp)) != NULL) { if (d->d_name[0] != 'c' || d->d_name[1] != 'f') continue; /* daemon control files only */ closedir(dirp); return (1); /* found something */ } closedir(dirp); return (0); } -void +static void usage() { - puts("usage: lpq [-a] [-l] [-Pprinter] [user ...] [job ...]"); + fprintf(stderr, + "usage: lpq [-a] [-l] [-Pprinter] [user ...] [job ...]\n"); exit(1); } Index: stable/2.2/usr.sbin/lpr/lpr/lpr.1 =================================================================== --- stable/2.2/usr.sbin/lpr/lpr/lpr.1 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpr/lpr.1 (revision 29845) @@ -1,253 +1,253 @@ .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" From @(#)lpr.1 8.1 (Berkeley) 6/6/93 -.\" $Id$ +.\" $Id: lpr.1,v 1.5 1996/05/11 19:00:54 joerg Exp $ .\" " .Dd June 6, 1993 .Dt LPR 1 .Os BSD 4 .Sh NAME .Nm lpr .Nd off line print .Sh SYNOPSIS .Nm lpr .Op Fl P Ns Ar printer .Op Fl \&# Ns Ar num .Op Fl C Ar class .Op Fl J Ar job .Op Fl T Ar title .Op Fl U Ar user .Op Fl i Ar numcols .Op Fl 1234 Ar font .Op Fl w Ns Ar num .Op Fl cdfghlnmprstv .Op Ar name ... .Sh DESCRIPTION .Nm Lpr uses a spooling daemon to print the named files when facilities become available. If no names appear, the standard input is assumed. .Pp The following single letter options are used to notify the line printer spooler that the files are not standard text files. The spooling daemon will use the appropriate filters to print the data accordingly. .Bl -tag -width indent .It Fl c The files are assumed to contain data produced by .Xr cifplot 1 .It Fl d The files are assumed to contain data from .Em tex .Pf ( Tn DVI format from Stanford). .It Fl f Use a filter which interprets the first character of each line as a standard .Tn FORTRAN carriage control character. .It Fl g The files are assumed to contain standard plot data as produced by the .Xr plot routines (see also .Xr plot for the filters used by the printer spooler). .It Fl l Use a filter which allows control characters to be printed and suppresses page breaks. .It Fl n The files are assumed to contain data from .Em ditroff (device independent troff). .It Fl p Use .Xr pr 1 to format the files. .It Fl t The files are assumed to contain data from .Xr troff 1 (cat phototypesetter commands). .It Fl v The files are assumed to contain a raster image for devices like the Benson Varian. .El .Pp These options apply to the handling of the print job: .Bl -tag -width indent .It Fl P Force output to a specific printer. Normally, the default printer is used (site dependent), or the value of the environment variable .Ev PRINTER is used. .It Fl h Suppress the printing of the burst page. .It Fl m Send mail upon completion. .It Fl r Remove the file upon completion of spooling or upon completion of printing (with the .Fl s option). .It Fl s Use symbolic links. Usually files are copied to the spool directory. The .Fl s option will use .Xr symlink 2 to link data files rather than trying to copy them so large files can be printed. This means the files should not be modified or removed until they have been printed. .El .Pp The remaining options apply to copies, the page display, and headers: .Bl -tag -width indent .It Fl \&# Ns Ar num The quantity .Ar num is the number of copies desired of each file named. For example, .Bd -literal -offset indent lpr \-#3 foo.c bar.c more.c .Ed would result in 3 copies of the file foo.c, followed by 3 copies of the file bar.c, etc. On the other hand, .Bd -literal -offset indent cat foo.c bar.c more.c \&| lpr \-#3 .Ed .Pp will give three copies of the concatenation of the files. Often a site will disable this feature to encourage use of a photocopier instead. .It Xo .Fl Ns Oo Cm 1234 Oc Ar font .Xc Specifies a .Ar font to be mounted on font position .Ar i . The daemon will construct a .Li .railmag file referencing the font pathname. .It Fl C Ar class Job classification to use on the burst page. For example, .Bd -literal -offset indent lpr \-C EECS foo.c .Ed .Pp causes the system name (the name returned by .Xr hostname 1 ) to be replaced on the burst page by .Tn EECS , and the file foo.c to be printed. .It Fl J Ar job Job name to print on the burst page. Normally, the first file's name is used. .It Fl T Ar title Title name for .Xr pr 1 , instead of the file name. .It Fl U Ar user User name to print on the burst page, also for accounting purposes. This option is only honored if the real user-id is daemon (or that specified in the printcap file instead of daemon), and is intended for those instances where print filters wish to requeue jobs. .It Fl i numcols The output is indented by .Pq Ar numcols . .It Fl w Ns Ar num Uses .Ar num as the page width for .Xr pr 1 . .El .Sh ENVIRONMENT If the following environment variable exists, it is used by .Nm lpr : .Bl -tag -width PRINTER .It Ev PRINTER Specifies an alternate default printer. .El .Sh FILES .Bl -tag -width /var/spool/output/*/tf* -compact .It Pa /etc/passwd Personal identification. .It Pa /etc/printcap Printer capabilities data base. .It Pa /usr/sbin/lpd Line printer daemons. .It Pa /var/spool/output/* Directories used for spooling. .It Pa /var/spool/output/*/cf* Daemon control files. .It Pa /var/spool/output/*/df* Data files specified in "cf" files. .It Pa /var/spool/output/*/tf* Temporary copies of "cf" files. .El .Sh SEE ALSO .Xr lpq 1 , .Xr lprm 1 , .Xr pr 1 , .Xr symlink 2 , .Xr printcap 5 , .Xr lpc 8 , .Xr lpd 8 .Sh HISTORY The -.Nm lpr +.Nm command appeared in .Bx 3 . .Sh DIAGNOSTICS If you try to spool too large a file, it will be truncated. .Nm Lpr will object to printing binary files. If a user other than root prints a file and spooling is disabled, -.Nm lpr +.Nm will print a message saying so and will not put jobs in the queue. If a connection to .Xr lpd 8 on the local machine cannot be made, -.Nm lpr +.Nm will say that the daemon cannot be started. Diagnostics may be printed in the daemon's log file regarding missing spool files by .Xr lpd 8 . .Sh BUGS Fonts for .Xr troff 1 and .Xr tex reside on the host with the printer. It is currently not possible to use local font libraries. Index: stable/2.2/usr.sbin/lpr/lpr/lpr.c =================================================================== --- stable/2.2/usr.sbin/lpr/lpr/lpr.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lpr/lpr.c (revision 29845) @@ -1,789 +1,792 @@ /* * Copyright (c) 1983, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "From: @(#)lpr.c 8.4 (Berkeley) 4/28/95" - "\n$Id: lpr.c,v 1.10.2.3 1997/07/08 21:07:21 dima Exp $\n"; +#if 0 +static char sccsid[] = "@(#)from: lpr.c 8.4 (Berkeley) 4/28/95"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ /* * lpr -- off line print * * Allows multiple printers and printers on remote machines by * using information from a printer data base. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" #include "pathnames.h" static char *cfname; /* daemon control files, linked from tf's */ static char *class = host; /* class title on header page */ static char *dfname; /* data files */ static char *fonts[4]; /* troff font names */ static char format = 'f'; /* format char for printing files */ static int hdr = 1; /* print header or not (default is yes) */ static int iflag; /* indentation wanted */ static int inchar; /* location to increment char in file names */ static int indent; /* amount to indent */ static char *jobname; /* job name on header page */ static int mailflg; /* send mail */ static int nact; /* number of jobs to act on */ static int ncopies = 1; /* # of copies to make */ static char *person; /* user name */ static int qflag; /* q job, but don't exec daemon */ static int rflag; /* remove files upon completion */ static int sflag; /* symbolic link flag */ static int tfd; /* control file descriptor */ static char *tfname; /* tmp copy of cf before linking */ static char *title; /* pr'ing title */ static int userid; /* user id */ static char *width; /* width for versatec printing */ static struct stat statb; static void card __P((int, char *)); static int checkwriteperm __P((char*, char *)); static void chkprinter __P((char *)); static void cleanup __P((int)); static void copy __P((int, char [])); static void fatal2 __P((const char *, ...)); static char *itoa __P((int)); static char *linked __P((char *)); static char *lmktemp __P((char *, int, int)); static void mktemps __P((void)); static int nfile __P((char *)); static int test __P((char *)); static void usage __P((void)); uid_t uid, euid; int main(argc, argv) int argc; char *argv[]; { struct passwd *pw; struct group *gptr; register char *arg, *cp; char buf[BUFSIZ]; int c, i, f, errs; struct stat stb; euid = geteuid(); uid = getuid(); seteuid(uid); if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, cleanup); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, cleanup); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, cleanup); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, cleanup); name = argv[0]; gethostname(host, sizeof(host)); openlog("lpd", 0, LOG_LPR); errs = 0; while ((c = getopt(argc, argv, ":#:1:2:3:4:C:J:P:T:U:cdfghi:lnmprstvw:")) != EOF) switch (c) { case '#': /* n copies */ i = atoi(optarg); if (i > 0) ncopies = i; break; case '1': /* troff fonts */ case '2': case '3': case '4': fonts[optopt - '1'] = optarg; break; case 'C': /* classification spec */ hdr++; class = optarg; break; case 'J': /* job name */ hdr++; jobname = optarg; break; case 'P': /* specifiy printer name */ printer = optarg; break; case 'T': /* pr's title line */ title = optarg; break; case 'U': /* user name */ hdr++; person = optarg; break; case 'c': /* print cifplot output */ case 'd': /* print tex output (dvi files) */ case 'g': /* print graph(1G) output */ case 'l': /* literal output */ case 'n': /* print ditroff output */ case 't': /* print troff output (cat files) */ case 'p': /* print using ``pr'' */ case 'v': /* print vplot output */ format = optopt; break; case 'f': /* print fortran output */ format = 'r'; break; case 'h': /* toggle want of header page */ hdr = !hdr; break; case 'i': /* indent output */ iflag++; indent = atoi(optarg); break; case 'm': /* send mail when done */ mailflg++; break; case 'q': /* just queue job */ qflag++; break; case 'r': /* remove file when done */ rflag++; break; case 's': /* try to link files */ sflag++; break; case 'w': /* versatec page width */ width = optarg; break; case ':': /* catch "missing argument" error */ if (optopt == 'i') { iflag++; /* -i without args is valid */ indent = 8; } else errs++; break; default: errs++; } argc -= optind; argv += optind; if (errs) usage(); if (printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; chkprinter(printer); if (SC && ncopies > 1) fatal2("multiple copies are not allowed"); if (MC > 0 && ncopies > MC) fatal2("only %d copies are allowed", MC); /* * Get the identity of the person doing the lpr using the same * algorithm as lprm. */ userid = getuid(); if (userid != DU || person == 0) { if ((pw = getpwuid(userid)) == NULL) fatal2("Who are you?"); person = pw->pw_name; } /* * Check for restricted group access. */ if (RG != NULL && userid != DU) { if ((gptr = getgrnam(RG)) == NULL) fatal2("Restricted group specified incorrectly"); if (gptr->gr_gid != getgid()) { while (*gptr->gr_mem != NULL) { if ((strcmp(person, *gptr->gr_mem)) == 0) break; gptr->gr_mem++; } if (*gptr->gr_mem == NULL) fatal2("Not a member of the restricted group"); } } /* * Check to make sure queuing is enabled if userid is not root. */ (void) snprintf(buf, sizeof(buf), "%s/%s", SD, LO); if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010)) fatal2("Printer queue is disabled"); /* * Initialize the control file. */ mktemps(); tfd = nfile(tfname); seteuid(euid); (void) fchown(tfd, DU, -1); /* owned by daemon for protection */ seteuid(uid); card('H', host); card('P', person); if (hdr) { if (jobname == NULL) { if (argc == 0) jobname = "stdin"; else jobname = (arg = strrchr(argv[0], '/')) ? arg+1 : argv[0]; } card('J', jobname); card('C', class); card('L', person); } if (iflag) card('I', itoa(indent)); if (mailflg) card('M', person); if (format == 't' || format == 'n' || format == 'd') for (i = 0; i < 4; i++) if (fonts[i] != NULL) card('1'+i, fonts[i]); if (width != NULL) card('W', width); /* * Read the files and spool them. */ if (argc == 0) copy(0, " "); else while (argc--) { if (argv[0][0] == '-' && argv[0][1] == '\0') { /* use stdin */ copy(0, " "); argv++; continue; } if ((f = test(arg = *argv++)) < 0) continue; /* file unreasonable */ if (sflag && (cp = linked(arg)) != NULL) { (void) snprintf(buf, sizeof(buf), "%d %d", statb.st_dev, statb.st_ino); card('S', buf); if (format == 'p') card('T', title ? title : arg); for (i = 0; i < ncopies; i++) card(format, &dfname[inchar-2]); card('U', &dfname[inchar-2]); if (f) card('U', cp); card('N', arg); dfname[inchar]++; nact++; continue; } if (sflag) printf("%s: %s: not linked, copying instead\n", name, arg); if ((i = open(arg, O_RDONLY)) < 0) { printf("%s: cannot open %s\n", name, arg); } else { copy(i, arg); (void) close(i); if (f && unlink(arg) < 0) printf("%s: %s: not removed\n", name, arg); } } if (nact) { (void) close(tfd); tfname[inchar]--; /* * Touch the control file to fix position in the queue. */ seteuid(euid); if ((tfd = open(tfname, O_RDWR)) >= 0) { char c; if (read(tfd, &c, 1) == 1 && lseek(tfd, (off_t)0, 0) == 0 && write(tfd, &c, 1) != 1) { printf("%s: cannot touch %s\n", name, tfname); tfname[inchar]++; cleanup(0); } (void) close(tfd); } if (link(tfname, cfname) < 0) { printf("%s: cannot rename %s\n", name, cfname); tfname[inchar]++; cleanup(0); } unlink(tfname); seteuid(uid); if (qflag) /* just q things up */ exit(0); if (!startdaemon(printer)) printf("jobs queued, but cannot start daemon.\n"); exit(0); } cleanup(0); return (1); /* NOTREACHED */ } /* * Create the file n and copy from file descriptor f. */ static void copy(f, n) int f; char n[]; { register int fd, i, nr, nc; char buf[BUFSIZ]; if (format == 'p') card('T', title ? title : n); for (i = 0; i < ncopies; i++) card(format, &dfname[inchar-2]); card('U', &dfname[inchar-2]); card('N', n); fd = nfile(dfname); nr = nc = 0; while ((i = read(f, buf, BUFSIZ)) > 0) { if (write(fd, buf, i) != i) { printf("%s: %s: temp file write error\n", name, n); break; } nc += i; if (nc >= BUFSIZ) { nc -= BUFSIZ; nr++; if (MX > 0 && nr > MX) { printf("%s: %s: copy file is too large\n", name, n); break; } } } (void) close(fd); if (nc==0 && nr==0) printf("%s: %s: empty input file\n", name, f ? n : "stdin"); else nact++; } /* * Try and link the file to dfname. Return a pointer to the full * path name if successful. */ static char * linked(file) register char *file; { register char *cp; static char buf[MAXPATHLEN]; register int ret; if (*file != '/') { if (getcwd(buf, sizeof(buf)) == NULL) return(NULL); while (file[0] == '.') { switch (file[1]) { case '/': file += 2; continue; case '.': if (file[2] == '/') { if ((cp = strrchr(buf, '/')) != NULL) *cp = '\0'; file += 3; continue; } } break; } strncat(buf, "/", sizeof(buf) - strlen(buf) - 1); strncat(buf, file, sizeof(buf) - strlen(buf) - 1); file = buf; } seteuid(euid); ret = symlink(file, dfname); seteuid(uid); return(ret ? NULL : file); } /* * Put a line into the control file. */ static void card(c, p2) register int c; register char *p2; { char buf[BUFSIZ]; register char *p1 = buf; register int len = 2; *p1++ = c; while ((c = *p2++) != '\0' && len < sizeof(buf)) { *p1++ = (c == '\n') ? ' ' : c; len++; } *p1++ = '\n'; write(tfd, buf, len); } /* * Create a new file in the spool directory. */ static int nfile(n) char *n; { register int f; int oldumask = umask(0); /* should block signals */ seteuid(euid); f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD); (void) umask(oldumask); if (f < 0) { printf("%s: cannot create %s\n", name, n); cleanup(0); } if (fchown(f, userid, -1) < 0) { printf("%s: cannot chown %s\n", name, n); cleanup(0); /* cleanup does exit */ } seteuid(uid); if (++n[inchar] > 'z') { if (++n[inchar-2] == 't') { printf("too many files - break up the job\n"); cleanup(0); } n[inchar] = 'A'; } else if (n[inchar] == '[') n[inchar] = 'a'; return(f); } /* * Cleanup after interrupts and errors. */ static void cleanup(signo) int signo; { register i; signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); i = inchar; seteuid(euid); if (tfname) do unlink(tfname); while (tfname[i]-- != 'A'); if (cfname) do unlink(cfname); while (cfname[i]-- != 'A'); if (dfname) do { do unlink(dfname); while (dfname[i]-- != 'A'); dfname[i] = 'z'; } while (dfname[i-2]-- != 'd'); exit(1); } /* * Test to see if this is a printable file. * Return -1 if it is not, 0 if its printable, and 1 if * we should remove it after printing. */ static int test(file) char *file; { struct exec execb; char *path; register int fd; register char *cp; if (access(file, 4) < 0) { printf("%s: cannot access %s\n", name, file); return(-1); } if (stat(file, &statb) < 0) { printf("%s: cannot stat %s\n", name, file); return(-1); } if ((statb.st_mode & S_IFMT) == S_IFDIR) { printf("%s: %s is a directory\n", name, file); return(-1); } if (statb.st_size == 0) { printf("%s: %s is an empty file\n", name, file); return(-1); } if ((fd = open(file, O_RDONLY)) < 0) { printf("%s: cannot open %s\n", name, file); return(-1); } if (read(fd, &execb, sizeof(execb)) == sizeof(execb) && !N_BADMAG(execb)) { printf("%s: %s is an executable program", name, file); goto error1; } (void) close(fd); if (rflag) { if ((cp = strrchr(file, '/')) == NULL) { if (checkwriteperm(file,".") == 0) return(1); } else { if (cp == file) { fd = checkwriteperm(file,"/"); } else { path = alloca(strlen(file) + 1); strcpy(path,file); *cp = '\0'; fd = checkwriteperm(path,file); *cp = '/'; } if (fd == 0) return(1); } printf("%s: %s: is not removable by you\n", name, file); } return(0); error1: printf(" and is unprintable\n"); (void) close(fd); return(-1); } static int checkwriteperm(file, directory) char *file, *directory; { struct stat stats; if (access(directory, W_OK) == 0) { stat(directory, &stats); if (stats.st_mode & S_ISVTX) { stat(file, &stats); if(stats.st_uid == userid) { return(0); } } else return(0); } return(-1); } /* * itoa - integer to string conversion */ static char * itoa(i) register int i; { static char b[10] = "########"; register char *p; p = &b[8]; do *p-- = i%10 + '0'; while (i /= 10); return(++p); } /* * Perform lookup for printer name or abbreviation -- */ static void chkprinter(s) char *s; { int status; if ((status = cgetent(&bp, printcapdb, s)) == -2) fatal2("cannot open printer description file"); else if (status == -1) fatal2("%s: unknown printer", s); if (cgetstr(bp, "sd", &SD) == -1) SD = _PATH_DEFSPOOL; if (cgetstr(bp, "lo", &LO) == -1) LO = DEFLOCK; cgetstr(bp, "rg", &RG); if (cgetnum(bp, "mx", &MX) < 0) MX = DEFMX; if (cgetnum(bp,"mc", &MC) < 0) MC = DEFMAXCOPIES; if (cgetnum(bp, "du", &DU) < 0) DU = DEFUID; SC = (cgetcap(bp, "sc", ':') != NULL); } /* * Tell the user what we wanna get. */ static void usage() { - fprintf(stderr, -"usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]\n" -"[-i[numcols]] [-1234 font] [-wnum] [-cdfghlnmprstv] [name ...]\n"); + fprintf(stderr, "%s\n%s\n", +"usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]", +"[-i[numcols]] [-1234 font] [-wnum] [-cdfghlnmprstv] [name ...]"); exit(1); } /* * Make the temp files. */ static void mktemps() { register int len, fd, n; register char *cp; char buf[BUFSIZ]; char *lmktemp(); (void) snprintf(buf, sizeof(buf), "%s/.seq", SD); seteuid(euid); if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) { printf("%s: cannot create %s\n", name, buf); exit(1); } if (flock(fd, LOCK_EX)) { printf("%s: cannot lock %s\n", name, buf); exit(1); } seteuid(uid); n = 0; if ((len = read(fd, buf, sizeof(buf))) > 0) { for (cp = buf; len--; ) { if (*cp < '0' || *cp > '9') break; n = n * 10 + (*cp++ - '0'); } } len = strlen(SD) + strlen(host) + 8; tfname = lmktemp("tf", n, len); cfname = lmktemp("cf", n, len); dfname = lmktemp("df", n, len); inchar = strlen(SD) + 3; n = (n + 1) % 1000; (void) lseek(fd, (off_t)0, 0); snprintf(buf, sizeof(buf), "%03d\n", n); (void) write(fd, buf, strlen(buf)); (void) close(fd); /* unlocks as well */ } /* * Make a temp file name. */ static char * lmktemp(id, num, len) char *id; int num, len; { register char *s; if ((s = malloc(len)) == NULL) fatal2("out of memory"); (void) snprintf(s, len, "%s/%sA%03d%s", SD, id, num, host); return(s); } #ifdef __STDC__ #include #else #include #endif static void #ifdef __STDC__ fatal2(const char *msg, ...) #else fatal2(msg, va_alist) char *msg; va_dcl #endif { va_list ap; #ifdef __STDC__ va_start(ap, msg); #else va_start(ap); #endif printf("%s: ", name); vprintf(msg, ap); putchar('\n'); va_end(ap); exit(1); } Index: stable/2.2/usr.sbin/lpr/lprm/lprm.1 =================================================================== --- stable/2.2/usr.sbin/lpr/lprm/lprm.1 (revision 29844) +++ stable/2.2/usr.sbin/lpr/lprm/lprm.1 (revision 29845) @@ -1,145 +1,145 @@ .\" Copyright (c) 1983, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)lprm.1 8.1 (Berkeley) 6/6/93 .\" .Dd June 6, 1993 .Dt LPRM 1 .Os BSD 4.2 .Sh NAME .Nm lprm .Nd remove jobs from the line printer spooling queue .Sh SYNOPSIS .Nm lprm .Op Fl P Ns Ar printer .Op Fl .Op job # ... .Op Ar user ... .Sh DESCRIPTION .Nm Lprm will remove a job, or jobs, from a printer's spool queue. Since the spooling directory is protected from users, using -.Nm lprm +.Nm is normally the only method by which a user may remove a job. The owner of a job is determined by the user's login name and host name on the machine where the .Xr lpr 1 command was invoked. .Pp Options and arguments: .Bl -tag -width indent .It Fl P Ns Ar printer Specify the queue associated with a specific .Ar printer (otherwise the default printer is used). .It Fl If a single .Sq Fl is given, -.Nm lprm +.Nm will remove all jobs which a user owns. If the super-user employs this flag, the spool queue will be emptied entirely. .It Ar user -Causes -.Nm lprm +Cause +.Nm to attempt to remove any jobs queued belonging to that user (or users). This form of invoking -.Nm lprm +.Nm is useful only to the super-user. .It Ar job\ \&# A user may dequeue an individual job by specifying its job number. This number may be obtained from the .Xr lpq 1 program, e.g. .Pp .Bd -literal -offset indent \&% lpq \-l 1st:ken [job #013ucbarpa] (standard input) 100 bytes % lprm 13 .Ed .El .Pp If neither arguments or options are given, -.Nm Lprm +.Nm will delete the currently active job if it is owned by the user who invoked .Nm lprm . .Pp .Nm Lprm announces the names of any files it removes and is silent if there are no jobs in the queue which match the request list. .Pp .Nm Lprm will kill off an active daemon, if necessary, before removing any spooling files. If a daemon is killed, a new one is automatically restarted upon completion of file removals. .Sh ENVIRONMENT If the following environment variable exists, it is utilized by .Nm lprm . .Bl -tag -width PRINTER .It Ev PRINTER If the environment variable .Ev PRINTER exists, and a printer has not been specified with the .Fl P option, the default printer is assumed from .Ev PRINTER . .El .Sh FILES .Bl -tag -width /var/spool/*/lock/ -compact .It Pa /etc/printcap Printer characteristics file. .It Pa /var/spool/* Spooling directories. .It Pa /var/spool/*/lock Lock file used to obtain the pid of the current daemon and the job number of the currently active job. .El .Sh SEE ALSO .Xr lpq 1 , .Xr lpr 1 , .Xr lpd 8 .Sh DIAGNOSTICS ``Permission denied" if the user tries to remove files other than his own. .Sh BUGS Since there are race conditions possible in the update of the lock file, the currently active job may be incorrectly identified. .Sh HISTORY The -.Nm lprm +.Nm command appeared in .Bx 3.0 . Index: stable/2.2/usr.sbin/lpr/lprm/lprm.c =================================================================== --- stable/2.2/usr.sbin/lpr/lprm/lprm.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/lprm/lprm.c (revision 29845) @@ -1,148 +1,152 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ /* * lprm - remove the current user's spool entry * * lprm [-] [[job #] [user] ...] * * Using information in the lock file, lprm will kill the * currently active daemon (if necessary), remove the associated files, * and startup a new daemon. Priviledged users may remove anyone's spool * entries, otherwise one can only remove their own. */ #include #include #include #include #include #include #include #include #include #include "lp.h" #include "lp.local.h" /* * Stuff for handling job specifications */ char *person; /* name of person doing lprm */ int requ[MAXREQUESTS]; /* job number of spool entries */ int requests; /* # of spool requests */ char *user[MAXUSERS]; /* users to process */ int users; /* # of users in user array */ uid_t uid, euid; /* real and effective user id's */ static char luser[16]; /* buffer for person */ -void usage __P((void)); +static void usage __P((void)); int main(argc, argv) int argc; char *argv[]; { register char *arg; struct passwd *p; uid = getuid(); euid = geteuid(); seteuid(uid); /* be safe */ name = argv[0]; gethostname(host, sizeof(host)); openlog("lpd", 0, LOG_LPR); if ((p = getpwuid(getuid())) == NULL) fatal("Who are you?"); if (strlen(p->pw_name) >= sizeof(luser)) fatal("Your name is too long"); strcpy(luser, p->pw_name); person = luser; while (--argc) { if ((arg = *++argv)[0] == '-') switch (arg[1]) { case 'P': if (arg[2]) printer = &arg[2]; else if (argc > 1) { argc--; printer = *++argv; } break; case '\0': if (!users) { users = -1; break; } default: usage(); } else { if (users < 0) usage(); if (isdigit(arg[0])) { if (requests >= MAXREQUESTS) fatal("Too many requests"); requ[requests++] = atoi(arg); } else { if (users >= MAXUSERS) fatal("Too many users"); user[users++] = arg; } } } if (printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; rmjob(); exit(0); } -void +static void usage() { fprintf(stderr, "usage: lprm [-] [-Pprinter] [[job #] [user] ...]\n"); exit(2); } Index: stable/2.2/usr.sbin/lpr/pac/pac.8 =================================================================== --- stable/2.2/usr.sbin/lpr/pac/pac.8 (revision 29844) +++ stable/2.2/usr.sbin/lpr/pac/pac.8 (revision 29845) @@ -1,106 +1,106 @@ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)pac.8 8.1 (Berkeley) 6/6/93 .\" .Dd June 6, 1993 .Dt PAC 8 .Os BSD 4.2 .Sh NAME .Nm pac .Nd printer/plotter accounting information .Sh SYNOPSIS .Nm pac .Op Fl P Ns Ar printer .Op Fl c .Op Fl m .Op Fl p Ns Ar price .Op Fl s .Op Fl r .Op Ar name ... .Sh DESCRIPTION .Nm Pac reads the printer/plotter accounting files, accumulating the number of pages (the usual case) or feet (for raster devices) of paper consumed by each user, and printing out how much each user consumed in pages or feet and dollars. .Pp Options and operands available: .Bl -tag -width PPprinter .It Fl P Ns Ar printer Accounting is done for the named printer. Normally, accounting is done for the default printer (site dependent) or the value of the environment variable .Ev PRINTER is used. .It Fl c -flag causes the output to be sorted by cost; usually the +Cause the output to be sorted by cost; usually the output is sorted alphabetically by name. .It Fl m -flag causes the host name to be ignored in the accounting file. This +Cause the host name to be ignored in the accounting file. This allows for a user on multiple machines to have all of his printing charges grouped together. .It Fl p Ns Ar price The value .Ar price is used for the cost in dollars instead of the default value of 0.02 or the price specified in .Pa /etc/printcap . .It Fl r Reverse the sorting order. .It Fl s Accounting information is summarized on the summary accounting file; this summarization is necessary since on a busy system, the accounting file can grow by several lines per day. .It Ar names Statistics are only printed for user(s) .Ar name ; usually, statistics are printed for every user who has used any paper. .El .Sh FILES .Bl -tag -width /var/account/?_sum -compact .It Pa /var/account/?acct raw accounting files .It Pa /var/account/?_sum summary accounting files .It Pa /etc/printcap printer capability data base .El .Sh SEE ALSO .Xr printcap 5 .Sh BUGS The relationship between the computed price and reality is as yet unknown. .Sh HISTORY The .Nm command appeared in .Bx 4.0 . Index: stable/2.2/usr.sbin/lpr/pac/pac.c =================================================================== --- stable/2.2/usr.sbin/lpr/pac/pac.c (revision 29844) +++ stable/2.2/usr.sbin/lpr/pac/pac.c (revision 29845) @@ -1,448 +1,457 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ /* * Do Printer accounting summary. * Currently, usage is * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...] * to print the usage information for the named people. */ #include #include #include #include #include #include "lp.h" #include "lp.local.h" static char *acctfile; /* accounting file (input data) */ static int allflag = 1; /* Get stats on everybody */ static int errs; static int hcount; /* Count of hash entries */ static int mflag = 0; /* disregard machine names */ static int pflag = 0; /* 1 if -p on cmd line */ static float price = 0.02; /* cost per page (or what ever) */ static long price100; /* per-page cost in 100th of a cent */ static int reverse; /* Reverse sort order */ static int sort; /* Sort by cost */ static char *sumfile; /* summary file */ static int summarize; /* Compress accounting file */ uid_t uid, euid; /* * Grossness follows: * Names to be accumulated are hashed into the following * table. */ #define HSHSIZE 97 /* Number of hash buckets */ struct hent { struct hent *h_link; /* Forward hash link */ char *h_name; /* Name of this user */ float h_feetpages; /* Feet or pages of paper */ int h_count; /* Number of runs */ }; static struct hent *hashtab[HSHSIZE]; /* Hash table proper */ static void account __P((FILE *)); static int any __P((int, char [])); static int chkprinter __P((char *)); static void dumpit __P((void)); static int hash __P((char [])); static struct hent *enter __P((char [])); static struct hent *lookup __P((char [])); static int qucmp __P((const void *, const void *)); static void rewrite __P((void)); +static void usage __P((void)); int main(argc, argv) int argc; char **argv; { register FILE *acct; register char *cp; euid = geteuid(); /* these aren't used in pac(1) */ uid = getuid(); while (--argc) { cp = *++argv; if (*cp++ == '-') { switch(*cp++) { case 'P': /* * Printer name. */ printer = cp; continue; case 'p': /* * get the price. */ price = atof(cp); pflag = 1; continue; case 's': /* * Summarize and compress accounting file. */ summarize++; continue; case 'c': /* * Sort by cost. */ sort++; continue; case 'm': /* * disregard machine names for each user */ mflag = 1; continue; case 'r': /* * Reverse sorting order. */ reverse++; continue; default: -fprintf(stderr, - "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); - exit(1); + usage(); } } (void) enter(--cp); allflag = 0; } if (printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; if (!chkprinter(printer)) { printf("pac: unknown printer %s\n", printer); exit(2); } if ((acct = fopen(acctfile, "r")) == NULL) { perror(acctfile); exit(1); } account(acct); fclose(acct); if ((acct = fopen(sumfile, "r")) != NULL) { account(acct); fclose(acct); } if (summarize) rewrite(); else dumpit(); exit(errs); } +static void +usage() +{ + fprintf(stderr, + "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); + exit(1); +} + /* * Read the entire accounting file, accumulating statistics * for the users that we have in the hash table. If allflag * is set, then just gather the facts on everyone. * Note that we must accomodate both the active and summary file * formats here. * Host names are ignored if the -m flag is present. */ static void account(acct) register FILE *acct; { char linebuf[BUFSIZ]; double t; register char *cp, *cp2; register struct hent *hp; register int ic; while (fgets(linebuf, BUFSIZ, acct) != NULL) { cp = linebuf; while (any(*cp, " \t")) cp++; t = atof(cp); while (any(*cp, ".0123456789")) cp++; while (any(*cp, " \t")) cp++; for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) ; ic = atoi(cp2); *cp2 = '\0'; if (mflag && strchr(cp, ':')) cp = strchr(cp, ':') + 1; hp = lookup(cp); if (hp == NULL) { if (!allflag) continue; hp = enter(cp); } hp->h_feetpages += t; if (ic) hp->h_count += ic; else hp->h_count++; } } /* * Sort the hashed entries by name or footage * and print it all out. */ static void dumpit() { struct hent **base; register struct hent *hp, **ap; register int hno, c, runs; float feet; hp = hashtab[0]; hno = 1; base = (struct hent **) calloc(sizeof hp, hcount); for (ap = base, c = hcount; c--; ap++) { while (hp == NULL) hp = hashtab[hno++]; *ap = hp; hp = hp->h_link; } qsort(base, hcount, sizeof hp, qucmp); printf(" Login pages/feet runs price\n"); feet = 0.0; runs = 0; for (ap = base, c = hcount; c--; ap++) { hp = *ap; runs += hp->h_count; feet += hp->h_feetpages; printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, hp->h_feetpages, hp->h_count, hp->h_feetpages * price); } if (allflag) { printf("\n"); printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, runs, feet * price); } } /* * Rewrite the summary file with the summary information we have accumulated. */ static void rewrite() { register struct hent *hp; register int i; register FILE *acctf; if ((acctf = fopen(sumfile, "w")) == NULL) { - perror(sumfile); + warn("%s", sumfile); errs++; return; } for (i = 0; i < HSHSIZE; i++) { hp = hashtab[i]; while (hp != NULL) { fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, hp->h_name, hp->h_count); hp = hp->h_link; } } fflush(acctf); if (ferror(acctf)) { - perror(sumfile); + warn("%s", sumfile); errs++; } fclose(acctf); if ((acctf = fopen(acctfile, "w")) == NULL) - perror(acctfile); + warn("%s", acctfile); else fclose(acctf); } /* * Hashing routines. */ /* * Enter the name into the hash table and return the pointer allocated. */ static struct hent * enter(name) char name[]; { register struct hent *hp; register int h; if ((hp = lookup(name)) != NULL) return(hp); h = hash(name); hcount++; hp = (struct hent *) calloc(sizeof *hp, 1); hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); strcpy(hp->h_name, name); hp->h_feetpages = 0.0; hp->h_count = 0; hp->h_link = hashtab[h]; hashtab[h] = hp; return(hp); } /* * Lookup a name in the hash table and return a pointer * to it. */ static struct hent * lookup(name) char name[]; { register int h; register struct hent *hp; h = hash(name); for (hp = hashtab[h]; hp != NULL; hp = hp->h_link) if (strcmp(hp->h_name, name) == 0) return(hp); return(NULL); } /* * Hash the passed name and return the index in * the hash table to begin the search. */ static int hash(name) char name[]; { register int h; register char *cp; for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) ; return((h & 0x7fffffff) % HSHSIZE); } /* * Other stuff */ static int any(ch, str) int ch; char str[]; { register int c = ch; register char *cp = str; while (*cp) if (*cp++ == c) return(1); return(0); } /* * The qsort comparison routine. * The comparison is ascii collating order * or by feet of typesetter film, according to sort. */ static int qucmp(a, b) const void *a, *b; { register struct hent *h1, *h2; register int r; h1 = *(struct hent **)a; h2 = *(struct hent **)b; if (sort) r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages; else r = strcmp(h1->h_name, h2->h_name); return(reverse ? -r : r); } /* * Perform lookup for printer name or abbreviation -- */ static int chkprinter(s) register char *s; { int stat; if ((stat = cgetent(&bp, printcapdb, s)) == -2) { printf("pac: can't open printer description file\n"); exit(3); } else if (stat == -1) return(0); else if (stat == -3) fatal("potential reference loop detected in printcap file"); if (cgetstr(bp, "af", &acctfile) == -1) { printf("accounting not enabled for printer %s\n", printer); exit(2); } if (!pflag && (cgetnum(bp, "pc", &price100) == 0)) price = price100/10000.0; sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); - if (sumfile == NULL) { - perror("pac"); - exit(1); - } + if (sumfile == NULL) + errx(1, "calloc failed"); strcpy(sumfile, acctfile); strcat(sumfile, "_sum"); return(1); }