122426Sdist /*
222426Sdist  * Copyright (c) 1983 Regents of the University of California.
334203Sbostic  * All rights reserved.
434203Sbostic  *
5*56120Selan  * Redistribution and use in source and binary forms, with or without
6*56120Selan  * modification, are permitted provided that the following conditions
7*56120Selan  * are met:
8*56120Selan  * 1. Redistributions of source code must retain the above copyright
9*56120Selan  *    notice, this list of conditions and the following disclaimer.
10*56120Selan  * 2. Redistributions in binary form must reproduce the above copyright
11*56120Selan  *    notice, this list of conditions and the following disclaimer in the
12*56120Selan  *    documentation and/or other materials provided with the distribution.
13*56120Selan  * 3. All advertising materials mentioning features or use of this software
14*56120Selan  *    must display the following acknowledgement:
15*56120Selan  *	This product includes software developed by the University of
16*56120Selan  *	California, Berkeley and its contributors.
17*56120Selan  * 4. Neither the name of the University nor the names of its contributors
18*56120Selan  *    may be used to endorse or promote products derived from this software
19*56120Selan  *    without specific prior written permission.
20*56120Selan  *
21*56120Selan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*56120Selan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*56120Selan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*56120Selan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*56120Selan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*56120Selan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*56120Selan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*56120Selan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*56120Selan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*56120Selan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*56120Selan  * SUCH DAMAGE.
3222426Sdist  */
3322426Sdist 
3413952Ssam #ifndef lint
35*56120Selan static char sccsid[] = "@(#)common.c	5.9 (Berkeley) 8/6/92";
3634203Sbostic #endif /* not lint */
3713952Ssam 
3855470Sbostic #include <sys/param.h>
3955470Sbostic #include <sys/stat.h>
4055470Sbostic 
4155470Sbostic #include <sys/socket.h>
4255470Sbostic #include <netinet/in.h>
4355470Sbostic #include <netdb.h>
4455470Sbostic 
4555470Sbostic #include <dirent.h>
4655470Sbostic #include <errno.h>
4755470Sbostic #include <unistd.h>
4855470Sbostic #include <stdlib.h>
4955470Sbostic #include <stdio.h>
5055470Sbostic #include <string.h>
5155470Sbostic #include "lp.h"
52*56120Selan #include "pathnames.h"
5355470Sbostic 
5412117Sralph /*
5512117Sralph  * Routines and data common to all the line printer functions.
5612117Sralph  */
5712117Sralph 
58*56120Selan char	*AF;		/* accounting file */
59*56120Selan long	 BR;		/* baud rate if lp is a tty */
60*56120Selan char	*CF;		/* name of cifplot filter (per job) */
61*56120Selan char	*DF;		/* name of tex filter (per job) */
62*56120Selan long	 DU;		/* daeomon user-id */
63*56120Selan long	 FC;		/* flags to clear if lp is a tty */
64*56120Selan char	*FF;		/* form feed string */
65*56120Selan long	 FS;		/* flags to set if lp is a tty */
66*56120Selan char	*GF;		/* name of graph(1G) filter (per job) */
67*56120Selan long	 HL;		/* print header last */
68*56120Selan char	*IF;		/* name of input filter (created per job) */
69*56120Selan char	*LF;		/* log file for error messages */
70*56120Selan char	*LO;		/* lock file name */
7112117Sralph char	*LP;		/* line printer device name */
72*56120Selan long	 MC;		/* maximum number of copies allowed */
73*56120Selan long	 MX;		/* maximum number of blocks to copy */
74*56120Selan char	*NF;		/* name of ditroff filter (per job) */
75*56120Selan char	*OF;		/* name of output filter (created once) */
76*56120Selan char	*PF;		/* name of vrast filter (per job) */
77*56120Selan long	 PL;		/* page length */
78*56120Selan long	 PW;		/* page width */
79*56120Selan long	 PX;		/* page width in pixels */
80*56120Selan long	 PY;		/* page length in pixels */
81*56120Selan char	*RF;		/* name of fortran text filter (per job) */
82*56120Selan char    *RG;		/* resricted group */
8312117Sralph char	*RM;		/* remote machine name */
8412117Sralph char	*RP;		/* remote printer name */
85*56120Selan long	 RS;		/* restricted to those with local accounts */
86*56120Selan long	 RW;		/* open LP for reading and writing */
87*56120Selan long	 SB;		/* short banner instead of normal header */
88*56120Selan long	 SC;		/* suppress multiple copies */
89*56120Selan char	*SD;		/* spool directory */
90*56120Selan long	 SF;		/* suppress FF on each print job */
91*56120Selan long	 SH;		/* suppress header page */
9212117Sralph char	*ST;		/* status file name */
9312117Sralph char	*TF;		/* name of troff filter (per job) */
94*56120Selan char	*TR;		/* trailer string to be output when Q empties */
9512117Sralph char	*VF;		/* name of vplot filter (per job) */
96*56120Selan long	 XC;		/* flags to clear for local mode */
97*56120Selan long	 XS;		/* flags to set for local mode */
9812117Sralph 
9912117Sralph char	line[BUFSIZ];
100*56120Selan char	*bp;		/* pointer into printcap buffer. */
10112117Sralph char	*name;		/* program name */
10212117Sralph char	*printer;	/* printer name */
10355470Sbostic 			/* host machine name */
10455470Sbostic char	host[MAXHOSTNAMELEN];
10512117Sralph char	*from = host;	/* client's machine name */
10638736Stef int	sendtorem;	/* are we sending to a remote? */
107*56120Selan char	*printcapdb[2] = { _PATH_PRINTCAP, 0 };
10812117Sralph 
10955470Sbostic static int compar __P((const void *, const void *));
11055470Sbostic 
11112117Sralph /*
11212117Sralph  * Create a connection to the remote printer server.
11312117Sralph  * Most of this code comes from rcmd.c.
11412117Sralph  */
11555470Sbostic int
11612528Sralph getport(rhost)
11712528Sralph 	char *rhost;
11812117Sralph {
11912117Sralph 	struct hostent *hp;
12012117Sralph 	struct servent *sp;
12112117Sralph 	struct sockaddr_in sin;
12212117Sralph 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
12312874Sralph 	int err;
12412117Sralph 
12512117Sralph 	/*
12612117Sralph 	 * Get the host address and port number to connect to.
12712117Sralph 	 */
12812528Sralph 	if (rhost == NULL)
12912117Sralph 		fatal("no remote host to connect to");
13012528Sralph 	hp = gethostbyname(rhost);
13112117Sralph 	if (hp == NULL)
13212528Sralph 		fatal("unknown host %s", rhost);
13312117Sralph 	sp = getservbyname("printer", "tcp");
13412117Sralph 	if (sp == NULL)
13512117Sralph 		fatal("printer/tcp: unknown service");
13612117Sralph 	bzero((char *)&sin, sizeof(sin));
13712117Sralph 	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
13812117Sralph 	sin.sin_family = hp->h_addrtype;
13912117Sralph 	sin.sin_port = sp->s_port;
14012117Sralph 
14112117Sralph 	/*
14212117Sralph 	 * Try connecting to the server.
14312117Sralph 	 */
14412117Sralph retry:
14512117Sralph 	s = rresvport(&lport);
14612117Sralph 	if (s < 0)
14712117Sralph 		return(-1);
14846910Sbostic 	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
14912874Sralph 		err = errno;
15012874Sralph 		(void) close(s);
15112874Sralph 		errno = err;
15212117Sralph 		if (errno == EADDRINUSE) {
15312117Sralph 			lport--;
15412117Sralph 			goto retry;
15512117Sralph 		}
15612117Sralph 		if (errno == ECONNREFUSED && timo <= 16) {
15712117Sralph 			sleep(timo);
15812117Sralph 			timo *= 2;
15912117Sralph 			goto retry;
16012117Sralph 		}
16112117Sralph 		return(-1);
16212117Sralph 	}
16312117Sralph 	return(s);
16412117Sralph }
16512117Sralph 
16612117Sralph /*
16712117Sralph  * Getline reads a line from the control file cfp, removes tabs, converts
16812117Sralph  *  new-line to null and leaves it in line.
16912117Sralph  * Returns 0 at EOF or the number of characters read.
17012117Sralph  */
17155470Sbostic int
17212117Sralph getline(cfp)
17312117Sralph 	FILE *cfp;
17412117Sralph {
17512117Sralph 	register int linel = 0;
17612117Sralph 	register char *lp = line;
17712117Sralph 	register c;
17812117Sralph 
17912117Sralph 	while ((c = getc(cfp)) != '\n') {
18012117Sralph 		if (c == EOF)
18112117Sralph 			return(0);
18212117Sralph 		if (c == '\t') {
18312117Sralph 			do {
18412117Sralph 				*lp++ = ' ';
18512117Sralph 				linel++;
18612117Sralph 			} while ((linel & 07) != 0);
18712117Sralph 			continue;
18812117Sralph 		}
18912117Sralph 		*lp++ = c;
19012117Sralph 		linel++;
19112117Sralph 	}
19212117Sralph 	*lp++ = '\0';
19312117Sralph 	return(linel);
19412117Sralph }
19512117Sralph 
19612117Sralph /*
19712117Sralph  * Scan the current directory and make a list of daemon files sorted by
19812117Sralph  * creation time.
19912117Sralph  * Return the number of entries and a pointer to the list.
20012117Sralph  */
20155470Sbostic int
20212117Sralph getq(namelist)
20312117Sralph 	struct queue *(*namelist[]);
20412117Sralph {
20555470Sbostic 	register struct dirent *d;
20612117Sralph 	register struct queue *q, **queue;
20712117Sralph 	register int nitems;
20812117Sralph 	struct stat stbuf;
20912117Sralph 	DIR *dirp;
21046910Sbostic 	int arraysz;
21112117Sralph 
21213170Sralph 	if ((dirp = opendir(SD)) == NULL)
21312117Sralph 		return(-1);
21412117Sralph 	if (fstat(dirp->dd_fd, &stbuf) < 0)
21512874Sralph 		goto errdone;
21612117Sralph 
21712117Sralph 	/*
21812117Sralph 	 * Estimate the array size by taking the size of the directory file
21912117Sralph 	 * and dividing it by a multiple of the minimum size entry.
22012117Sralph 	 */
22112117Sralph 	arraysz = (stbuf.st_size / 24);
22212117Sralph 	queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
22312117Sralph 	if (queue == NULL)
22412874Sralph 		goto errdone;
22512117Sralph 
22612117Sralph 	nitems = 0;
22712117Sralph 	while ((d = readdir(dirp)) != NULL) {
22812117Sralph 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
22912117Sralph 			continue;	/* daemon control files only */
23012117Sralph 		if (stat(d->d_name, &stbuf) < 0)
23112117Sralph 			continue;	/* Doesn't exist */
23212117Sralph 		q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
23312117Sralph 		if (q == NULL)
23412874Sralph 			goto errdone;
23512117Sralph 		q->q_time = stbuf.st_mtime;
23612117Sralph 		strcpy(q->q_name, d->d_name);
23712117Sralph 		/*
23812117Sralph 		 * Check to make sure the array has space left and
23912117Sralph 		 * realloc the maximum size.
24012117Sralph 		 */
24112117Sralph 		if (++nitems > arraysz) {
24212117Sralph 			queue = (struct queue **)realloc((char *)queue,
24312117Sralph 				(stbuf.st_size/12) * sizeof(struct queue *));
24412117Sralph 			if (queue == NULL)
24512874Sralph 				goto errdone;
24612117Sralph 		}
24712117Sralph 		queue[nitems-1] = q;
24812117Sralph 	}
24912117Sralph 	closedir(dirp);
25012117Sralph 	if (nitems)
25112117Sralph 		qsort(queue, nitems, sizeof(struct queue *), compar);
25212117Sralph 	*namelist = queue;
25312117Sralph 	return(nitems);
25412874Sralph 
25512874Sralph errdone:
25612874Sralph 	closedir(dirp);
25712874Sralph 	return(-1);
25812117Sralph }
25912117Sralph 
26012117Sralph /*
26112117Sralph  * Compare modification times.
26212117Sralph  */
26355470Sbostic static int
26412117Sralph compar(p1, p2)
26555470Sbostic 	const void *p1, *p2;
26612117Sralph {
26755470Sbostic 	if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
26812117Sralph 		return(-1);
26955470Sbostic 	if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
27012117Sralph 		return(1);
27112117Sralph 	return(0);
27212117Sralph }
27312117Sralph 
27438736Stef /*
27538736Stef  * Figure out whether the local machine is the same
27638736Stef  * as the remote machine (RM) entry (if it exists).
27738736Stef  */
27838736Stef char *
27938736Stef checkremote()
28038736Stef {
28138736Stef 	char name[MAXHOSTNAMELEN];
28238736Stef 	register struct hostent *hp;
28338736Stef 	static char errbuf[128];
28438736Stef 
28538736Stef 	sendtorem = 0;	/* assume printer is local */
28638736Stef 	if (RM != (char *)NULL) {
28738736Stef 		/* get the official name of the local host */
28838736Stef 		gethostname(name, sizeof(name));
28938736Stef 		name[sizeof(name)-1] = '\0';
29038736Stef 		hp = gethostbyname(name);
29138736Stef 		if (hp == (struct hostent *) NULL) {
29255470Sbostic 		    (void) snprintf(errbuf, sizeof(errbuf),
29338736Stef 			"unable to get official name for local machine %s",
29438736Stef 			name);
29538736Stef 		    return errbuf;
29638736Stef 		} else (void) strcpy(name, hp->h_name);
29738736Stef 
29838736Stef 		/* get the official name of RM */
29938736Stef 		hp = gethostbyname(RM);
30038736Stef 		if (hp == (struct hostent *) NULL) {
30155470Sbostic 		    (void) snprintf(errbuf, sizeof(errbuf),
30238736Stef 			"unable to get official name for remote machine %s",
30338736Stef 			RM);
30438736Stef 		    return errbuf;
30538736Stef 		}
30638736Stef 
30738736Stef 		/*
30838736Stef 		 * if the two hosts are not the same,
30938736Stef 		 * then the printer must be remote.
31038736Stef 		 */
31138736Stef 		if (strcmp(name, hp->h_name) != 0)
31238736Stef 			sendtorem = 1;
31338736Stef 	}
31438736Stef 	return (char *)0;
31538736Stef }
31638736Stef 
31755470Sbostic #if __STDC__
31855470Sbostic #include <stdarg.h>
31955470Sbostic #else
32055470Sbostic #include <varargs.h>
32155470Sbostic #endif
32255470Sbostic 
32355470Sbostic void
32455470Sbostic #if __STDC__
32555470Sbostic fatal(const char *msg, ...)
32655470Sbostic #else
32755470Sbostic fatal(msg, va_alist)
32812117Sralph 	char *msg;
32955470Sbostic         va_dcl
33055470Sbostic #endif
33112117Sralph {
33255470Sbostic 	va_list ap;
33355470Sbostic #if __STDC__
33455470Sbostic 	va_start(ap, msg);
33555470Sbostic #else
33655470Sbostic 	va_start(ap);
33755470Sbostic #endif
33812117Sralph 	if (from != host)
33955470Sbostic 		(void)printf("%s: ", host);
34055470Sbostic 	(void)printf("%s: ", name);
34112117Sralph 	if (printer)
34255470Sbostic 		(void)printf("%s: ", printer);
34355470Sbostic 	(void)vprintf(msg, ap);
34455470Sbostic 	va_end(ap);
34555470Sbostic 	(void)putchar('\n');
34612117Sralph 	exit(1);
34712117Sralph }
348