122426Sdist /*
261840Sbostic  * Copyright (c) 1983, 1993
361840Sbostic  *	The Regents of the University of California.  All rights reserved.
465779Sbostic  * (c) UNIX System Laboratories, Inc.
565779Sbostic  * All or some portions of this file are derived from material licensed
665779Sbostic  * to the University of California by American Telephone and Telegraph
765779Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865779Sbostic  * the permission of UNIX System Laboratories, Inc.
934203Sbostic  *
1056248Selan  * %sccs.include.redist.c%
1122426Sdist  */
1222426Sdist 
1313952Ssam #ifndef lint
14*69060Stef static char sccsid[] = "@(#)common.c	8.5 (Berkeley) 04/28/95";
1534203Sbostic #endif /* not lint */
1613952Ssam 
1755470Sbostic #include <sys/param.h>
1855470Sbostic #include <sys/stat.h>
19*69060Stef #include <sys/time.h>
2055470Sbostic 
2155470Sbostic #include <sys/socket.h>
2255470Sbostic #include <netinet/in.h>
2355470Sbostic #include <netdb.h>
2455470Sbostic 
2555470Sbostic #include <dirent.h>
2655470Sbostic #include <errno.h>
2755470Sbostic #include <unistd.h>
2855470Sbostic #include <stdlib.h>
2955470Sbostic #include <stdio.h>
3055470Sbostic #include <string.h>
3155470Sbostic #include "lp.h"
3256120Selan #include "pathnames.h"
3355470Sbostic 
3412117Sralph /*
3512117Sralph  * Routines and data common to all the line printer functions.
3612117Sralph  */
3712117Sralph 
3856120Selan char	*AF;		/* accounting file */
3956120Selan long	 BR;		/* baud rate if lp is a tty */
4056120Selan char	*CF;		/* name of cifplot filter (per job) */
4156120Selan char	*DF;		/* name of tex filter (per job) */
4256120Selan long	 DU;		/* daeomon user-id */
4356120Selan long	 FC;		/* flags to clear if lp is a tty */
4456120Selan char	*FF;		/* form feed string */
4556120Selan long	 FS;		/* flags to set if lp is a tty */
4656120Selan char	*GF;		/* name of graph(1G) filter (per job) */
4756120Selan long	 HL;		/* print header last */
4856120Selan char	*IF;		/* name of input filter (created per job) */
4956120Selan char	*LF;		/* log file for error messages */
5056120Selan char	*LO;		/* lock file name */
5112117Sralph char	*LP;		/* line printer device name */
5256120Selan long	 MC;		/* maximum number of copies allowed */
5356120Selan long	 MX;		/* maximum number of blocks to copy */
5456120Selan char	*NF;		/* name of ditroff filter (per job) */
5556120Selan char	*OF;		/* name of output filter (created once) */
5656120Selan char	*PF;		/* name of vrast filter (per job) */
5756120Selan long	 PL;		/* page length */
5856120Selan long	 PW;		/* page width */
5956120Selan long	 PX;		/* page width in pixels */
6056120Selan long	 PY;		/* page length in pixels */
6156120Selan char	*RF;		/* name of fortran text filter (per job) */
6256120Selan char    *RG;		/* resricted group */
6312117Sralph char	*RM;		/* remote machine name */
6412117Sralph char	*RP;		/* remote printer name */
6556120Selan long	 RS;		/* restricted to those with local accounts */
6656120Selan long	 RW;		/* open LP for reading and writing */
6756120Selan long	 SB;		/* short banner instead of normal header */
6856120Selan long	 SC;		/* suppress multiple copies */
6956120Selan char	*SD;		/* spool directory */
7056120Selan long	 SF;		/* suppress FF on each print job */
7156120Selan long	 SH;		/* suppress header page */
7212117Sralph char	*ST;		/* status file name */
7312117Sralph char	*TF;		/* name of troff filter (per job) */
7456120Selan char	*TR;		/* trailer string to be output when Q empties */
7512117Sralph char	*VF;		/* name of vplot filter (per job) */
7656120Selan long	 XC;		/* flags to clear for local mode */
7756120Selan long	 XS;		/* flags to set for local mode */
7812117Sralph 
7912117Sralph char	line[BUFSIZ];
8056120Selan char	*bp;		/* pointer into printcap buffer. */
8112117Sralph char	*name;		/* program name */
8212117Sralph char	*printer;	/* printer name */
8355470Sbostic 			/* host machine name */
8455470Sbostic char	host[MAXHOSTNAMELEN];
8512117Sralph char	*from = host;	/* client's machine name */
8669009Stef int	remote;		/* true if sending files to a remote host */
8756120Selan char	*printcapdb[2] = { _PATH_PRINTCAP, 0 };
8812117Sralph 
8955470Sbostic static int compar __P((const void *, const void *));
9055470Sbostic 
9112117Sralph /*
9269009Stef  * Create a TCP connection to host "rhost" at port "rport".
9369009Stef  * If rport == 0, then use the printer service port.
9412117Sralph  * Most of this code comes from rcmd.c.
9512117Sralph  */
9655470Sbostic int
getport(rhost,rport)9769009Stef getport(rhost, rport)
9812528Sralph 	char *rhost;
9969009Stef 	int rport;
10012117Sralph {
10112117Sralph 	struct hostent *hp;
10212117Sralph 	struct servent *sp;
10312117Sralph 	struct sockaddr_in sin;
10412117Sralph 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
10512874Sralph 	int err;
10612117Sralph 
10712117Sralph 	/*
10812117Sralph 	 * Get the host address and port number to connect to.
10912117Sralph 	 */
11012528Sralph 	if (rhost == NULL)
11112117Sralph 		fatal("no remote host to connect to");
11212117Sralph 	bzero((char *)&sin, sizeof(sin));
11369009Stef 	sin.sin_addr.s_addr = inet_addr(rhost);
11469009Stef 	if (sin.sin_addr.s_addr != INADDR_NONE)
11569009Stef 		sin.sin_family = AF_INET;
11669009Stef 	else {
11769009Stef 		hp = gethostbyname(rhost);
11869009Stef 		if (hp == NULL)
11969009Stef 			fatal("unknown host %s", rhost);
12069009Stef 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
12169009Stef 		sin.sin_family = hp->h_addrtype;
12269009Stef 	}
12369009Stef 	if (rport == 0) {
12469009Stef 		sp = getservbyname("printer", "tcp");
12569009Stef 		if (sp == NULL)
12669009Stef 			fatal("printer/tcp: unknown service");
12769009Stef 		sin.sin_port = sp->s_port;
12869009Stef 	} else
12969009Stef 		sin.sin_port = htons(rport);
13012117Sralph 
13112117Sralph 	/*
13212117Sralph 	 * Try connecting to the server.
13312117Sralph 	 */
13412117Sralph retry:
13512117Sralph 	s = rresvport(&lport);
13612117Sralph 	if (s < 0)
13712117Sralph 		return(-1);
13846910Sbostic 	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
13912874Sralph 		err = errno;
14012874Sralph 		(void) close(s);
14112874Sralph 		errno = err;
14212117Sralph 		if (errno == EADDRINUSE) {
14312117Sralph 			lport--;
14412117Sralph 			goto retry;
14512117Sralph 		}
14612117Sralph 		if (errno == ECONNREFUSED && timo <= 16) {
14712117Sralph 			sleep(timo);
14812117Sralph 			timo *= 2;
14912117Sralph 			goto retry;
15012117Sralph 		}
15112117Sralph 		return(-1);
15212117Sralph 	}
15312117Sralph 	return(s);
15412117Sralph }
15512117Sralph 
15612117Sralph /*
15712117Sralph  * Getline reads a line from the control file cfp, removes tabs, converts
15812117Sralph  *  new-line to null and leaves it in line.
15912117Sralph  * Returns 0 at EOF or the number of characters read.
16012117Sralph  */
16155470Sbostic int
getline(cfp)16212117Sralph getline(cfp)
16312117Sralph 	FILE *cfp;
16412117Sralph {
16512117Sralph 	register int linel = 0;
16612117Sralph 	register char *lp = line;
16712117Sralph 	register c;
16812117Sralph 
16912117Sralph 	while ((c = getc(cfp)) != '\n') {
17012117Sralph 		if (c == EOF)
17112117Sralph 			return(0);
17212117Sralph 		if (c == '\t') {
17312117Sralph 			do {
17412117Sralph 				*lp++ = ' ';
17512117Sralph 				linel++;
17612117Sralph 			} while ((linel & 07) != 0);
17712117Sralph 			continue;
17812117Sralph 		}
17912117Sralph 		*lp++ = c;
18012117Sralph 		linel++;
18112117Sralph 	}
18212117Sralph 	*lp++ = '\0';
18312117Sralph 	return(linel);
18412117Sralph }
18512117Sralph 
18612117Sralph /*
18712117Sralph  * Scan the current directory and make a list of daemon files sorted by
18812117Sralph  * creation time.
18912117Sralph  * Return the number of entries and a pointer to the list.
19012117Sralph  */
19155470Sbostic int
19212117Sralph getq(namelist)
19312117Sralph 	struct queue *(*namelist[]);
19412117Sralph {
19555470Sbostic 	register struct dirent *d;
19612117Sralph 	register struct queue *q, **queue;
19712117Sralph 	register int nitems;
19812117Sralph 	struct stat stbuf;
19912117Sralph 	DIR *dirp;
20046910Sbostic 	int arraysz;
20112117Sralph 
20213170Sralph 	if ((dirp = opendir(SD)) == NULL)
20312117Sralph 		return(-1);
20412117Sralph 	if (fstat(dirp->dd_fd, &stbuf) < 0)
20512874Sralph 		goto errdone;
20612117Sralph 
20712117Sralph 	/*
20812117Sralph 	 * Estimate the array size by taking the size of the directory file
20912117Sralph 	 * and dividing it by a multiple of the minimum size entry.
21012117Sralph 	 */
21112117Sralph 	arraysz = (stbuf.st_size / 24);
21212117Sralph 	queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
21312117Sralph 	if (queue == NULL)
21412874Sralph 		goto errdone;
21512117Sralph 
21612117Sralph 	nitems = 0;
21712117Sralph 	while ((d = readdir(dirp)) != NULL) {
21812117Sralph 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
21912117Sralph 			continue;	/* daemon control files only */
22012117Sralph 		if (stat(d->d_name, &stbuf) < 0)
22112117Sralph 			continue;	/* Doesn't exist */
22212117Sralph 		q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
22312117Sralph 		if (q == NULL)
22412874Sralph 			goto errdone;
22512117Sralph 		q->q_time = stbuf.st_mtime;
22612117Sralph 		strcpy(q->q_name, d->d_name);
22712117Sralph 		/*
22812117Sralph 		 * Check to make sure the array has space left and
22912117Sralph 		 * realloc the maximum size.
23012117Sralph 		 */
23112117Sralph 		if (++nitems > arraysz) {
23268971Stef 			arraysz *= 2;
23312117Sralph 			queue = (struct queue **)realloc((char *)queue,
23468971Stef 				arraysz * sizeof(struct queue *));
23512117Sralph 			if (queue == NULL)
23612874Sralph 				goto errdone;
23712117Sralph 		}
23812117Sralph 		queue[nitems-1] = q;
23912117Sralph 	}
24012117Sralph 	closedir(dirp);
24112117Sralph 	if (nitems)
24212117Sralph 		qsort(queue, nitems, sizeof(struct queue *), compar);
24312117Sralph 	*namelist = queue;
24412117Sralph 	return(nitems);
24512874Sralph 
24612874Sralph errdone:
24712874Sralph 	closedir(dirp);
24812874Sralph 	return(-1);
24912117Sralph }
25012117Sralph 
25112117Sralph /*
25212117Sralph  * Compare modification times.
25312117Sralph  */
25455470Sbostic static int
compar(p1,p2)25512117Sralph compar(p1, p2)
25655470Sbostic 	const void *p1, *p2;
25712117Sralph {
25855470Sbostic 	if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
25912117Sralph 		return(-1);
26055470Sbostic 	if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
26112117Sralph 		return(1);
26212117Sralph 	return(0);
26312117Sralph }
26412117Sralph 
26538736Stef /*
26638736Stef  * Figure out whether the local machine is the same
26738736Stef  * as the remote machine (RM) entry (if it exists).
26838736Stef  */
26938736Stef char *
checkremote()27038736Stef checkremote()
27138736Stef {
27238736Stef 	char name[MAXHOSTNAMELEN];
27338736Stef 	register struct hostent *hp;
27438736Stef 	static char errbuf[128];
27538736Stef 
27669009Stef 	remote = 0;	/* assume printer is local */
27769009Stef 	if (RM != NULL) {
27838736Stef 		/* get the official name of the local host */
27938736Stef 		gethostname(name, sizeof(name));
28038736Stef 		name[sizeof(name)-1] = '\0';
28138736Stef 		hp = gethostbyname(name);
28238736Stef 		if (hp == (struct hostent *) NULL) {
28355470Sbostic 		    (void) snprintf(errbuf, sizeof(errbuf),
28438736Stef 			"unable to get official name for local machine %s",
28538736Stef 			name);
28638736Stef 		    return errbuf;
28738736Stef 		} else (void) strcpy(name, hp->h_name);
28838736Stef 
28938736Stef 		/* get the official name of RM */
29038736Stef 		hp = gethostbyname(RM);
29138736Stef 		if (hp == (struct hostent *) NULL) {
29255470Sbostic 		    (void) snprintf(errbuf, sizeof(errbuf),
29338736Stef 			"unable to get official name for remote machine %s",
29438736Stef 			RM);
29538736Stef 		    return errbuf;
29638736Stef 		}
29738736Stef 
29838736Stef 		/*
29938736Stef 		 * if the two hosts are not the same,
30038736Stef 		 * then the printer must be remote.
30138736Stef 		 */
30268971Stef 		if (strcasecmp(name, hp->h_name) != 0)
30369009Stef 			remote = 1;
30438736Stef 	}
30568971Stef 	return NULL;
30638736Stef }
30738736Stef 
30869009Stef /* sleep n milliseconds */
30969009Stef void
delay(n)31069009Stef delay(n)
31169009Stef {
31269009Stef 	struct timeval tdelay;
31369009Stef 
31469009Stef 	if (n <= 0 || n > 10000)
31569009Stef 		fatal("unreasonable delay period (%d)", n);
31669009Stef 	tdelay.tv_sec = n / 1000;
31769009Stef 	tdelay.tv_usec = n * 1000 % 1000000;
31869009Stef 	(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
31969009Stef }
32069009Stef 
32155470Sbostic #if __STDC__
32255470Sbostic #include <stdarg.h>
32355470Sbostic #else
32455470Sbostic #include <varargs.h>
32555470Sbostic #endif
32655470Sbostic 
32755470Sbostic void
32855470Sbostic #if __STDC__
fatal(const char * msg,...)32955470Sbostic fatal(const char *msg, ...)
33055470Sbostic #else
33155470Sbostic fatal(msg, va_alist)
33212117Sralph 	char *msg;
33355470Sbostic         va_dcl
33455470Sbostic #endif
33512117Sralph {
33655470Sbostic 	va_list ap;
33755470Sbostic #if __STDC__
33855470Sbostic 	va_start(ap, msg);
33955470Sbostic #else
34055470Sbostic 	va_start(ap);
34155470Sbostic #endif
34212117Sralph 	if (from != host)
34355470Sbostic 		(void)printf("%s: ", host);
34455470Sbostic 	(void)printf("%s: ", name);
34512117Sralph 	if (printer)
34655470Sbostic 		(void)printf("%s: ", printer);
34755470Sbostic 	(void)vprintf(msg, ap);
34855470Sbostic 	va_end(ap);
34955470Sbostic 	(void)putchar('\n');
35012117Sralph 	exit(1);
35112117Sralph }
352