1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * %sccs.include.redist.c%
11  */
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)common.c	8.5 (Berkeley) 04/28/95";
15 #endif /* not lint */
16 
17 #include <sys/param.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20 
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netdb.h>
24 
25 #include <dirent.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include "lp.h"
32 #include "pathnames.h"
33 
34 /*
35  * Routines and data common to all the line printer functions.
36  */
37 
38 char	*AF;		/* accounting file */
39 long	 BR;		/* baud rate if lp is a tty */
40 char	*CF;		/* name of cifplot filter (per job) */
41 char	*DF;		/* name of tex filter (per job) */
42 long	 DU;		/* daeomon user-id */
43 long	 FC;		/* flags to clear if lp is a tty */
44 char	*FF;		/* form feed string */
45 long	 FS;		/* flags to set if lp is a tty */
46 char	*GF;		/* name of graph(1G) filter (per job) */
47 long	 HL;		/* print header last */
48 char	*IF;		/* name of input filter (created per job) */
49 char	*LF;		/* log file for error messages */
50 char	*LO;		/* lock file name */
51 char	*LP;		/* line printer device name */
52 long	 MC;		/* maximum number of copies allowed */
53 long	 MX;		/* maximum number of blocks to copy */
54 char	*NF;		/* name of ditroff filter (per job) */
55 char	*OF;		/* name of output filter (created once) */
56 char	*PF;		/* name of vrast filter (per job) */
57 long	 PL;		/* page length */
58 long	 PW;		/* page width */
59 long	 PX;		/* page width in pixels */
60 long	 PY;		/* page length in pixels */
61 char	*RF;		/* name of fortran text filter (per job) */
62 char    *RG;		/* resricted group */
63 char	*RM;		/* remote machine name */
64 char	*RP;		/* remote printer name */
65 long	 RS;		/* restricted to those with local accounts */
66 long	 RW;		/* open LP for reading and writing */
67 long	 SB;		/* short banner instead of normal header */
68 long	 SC;		/* suppress multiple copies */
69 char	*SD;		/* spool directory */
70 long	 SF;		/* suppress FF on each print job */
71 long	 SH;		/* suppress header page */
72 char	*ST;		/* status file name */
73 char	*TF;		/* name of troff filter (per job) */
74 char	*TR;		/* trailer string to be output when Q empties */
75 char	*VF;		/* name of vplot filter (per job) */
76 long	 XC;		/* flags to clear for local mode */
77 long	 XS;		/* flags to set for local mode */
78 
79 char	line[BUFSIZ];
80 char	*bp;		/* pointer into printcap buffer. */
81 char	*name;		/* program name */
82 char	*printer;	/* printer name */
83 			/* host machine name */
84 char	host[MAXHOSTNAMELEN];
85 char	*from = host;	/* client's machine name */
86 int	remote;		/* true if sending files to a remote host */
87 char	*printcapdb[2] = { _PATH_PRINTCAP, 0 };
88 
89 static int compar __P((const void *, const void *));
90 
91 /*
92  * Create a TCP connection to host "rhost" at port "rport".
93  * If rport == 0, then use the printer service port.
94  * Most of this code comes from rcmd.c.
95  */
96 int
97 getport(rhost, rport)
98 	char *rhost;
99 	int rport;
100 {
101 	struct hostent *hp;
102 	struct servent *sp;
103 	struct sockaddr_in sin;
104 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
105 	int err;
106 
107 	/*
108 	 * Get the host address and port number to connect to.
109 	 */
110 	if (rhost == NULL)
111 		fatal("no remote host to connect to");
112 	bzero((char *)&sin, sizeof(sin));
113 	sin.sin_addr.s_addr = inet_addr(rhost);
114 	if (sin.sin_addr.s_addr != INADDR_NONE)
115 		sin.sin_family = AF_INET;
116 	else {
117 		hp = gethostbyname(rhost);
118 		if (hp == NULL)
119 			fatal("unknown host %s", rhost);
120 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
121 		sin.sin_family = hp->h_addrtype;
122 	}
123 	if (rport == 0) {
124 		sp = getservbyname("printer", "tcp");
125 		if (sp == NULL)
126 			fatal("printer/tcp: unknown service");
127 		sin.sin_port = sp->s_port;
128 	} else
129 		sin.sin_port = htons(rport);
130 
131 	/*
132 	 * Try connecting to the server.
133 	 */
134 retry:
135 	s = rresvport(&lport);
136 	if (s < 0)
137 		return(-1);
138 	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
139 		err = errno;
140 		(void) close(s);
141 		errno = err;
142 		if (errno == EADDRINUSE) {
143 			lport--;
144 			goto retry;
145 		}
146 		if (errno == ECONNREFUSED && timo <= 16) {
147 			sleep(timo);
148 			timo *= 2;
149 			goto retry;
150 		}
151 		return(-1);
152 	}
153 	return(s);
154 }
155 
156 /*
157  * Getline reads a line from the control file cfp, removes tabs, converts
158  *  new-line to null and leaves it in line.
159  * Returns 0 at EOF or the number of characters read.
160  */
161 int
162 getline(cfp)
163 	FILE *cfp;
164 {
165 	register int linel = 0;
166 	register char *lp = line;
167 	register c;
168 
169 	while ((c = getc(cfp)) != '\n') {
170 		if (c == EOF)
171 			return(0);
172 		if (c == '\t') {
173 			do {
174 				*lp++ = ' ';
175 				linel++;
176 			} while ((linel & 07) != 0);
177 			continue;
178 		}
179 		*lp++ = c;
180 		linel++;
181 	}
182 	*lp++ = '\0';
183 	return(linel);
184 }
185 
186 /*
187  * Scan the current directory and make a list of daemon files sorted by
188  * creation time.
189  * Return the number of entries and a pointer to the list.
190  */
191 int
192 getq(namelist)
193 	struct queue *(*namelist[]);
194 {
195 	register struct dirent *d;
196 	register struct queue *q, **queue;
197 	register int nitems;
198 	struct stat stbuf;
199 	DIR *dirp;
200 	int arraysz;
201 
202 	if ((dirp = opendir(SD)) == NULL)
203 		return(-1);
204 	if (fstat(dirp->dd_fd, &stbuf) < 0)
205 		goto errdone;
206 
207 	/*
208 	 * Estimate the array size by taking the size of the directory file
209 	 * and dividing it by a multiple of the minimum size entry.
210 	 */
211 	arraysz = (stbuf.st_size / 24);
212 	queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
213 	if (queue == NULL)
214 		goto errdone;
215 
216 	nitems = 0;
217 	while ((d = readdir(dirp)) != NULL) {
218 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
219 			continue;	/* daemon control files only */
220 		if (stat(d->d_name, &stbuf) < 0)
221 			continue;	/* Doesn't exist */
222 		q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
223 		if (q == NULL)
224 			goto errdone;
225 		q->q_time = stbuf.st_mtime;
226 		strcpy(q->q_name, d->d_name);
227 		/*
228 		 * Check to make sure the array has space left and
229 		 * realloc the maximum size.
230 		 */
231 		if (++nitems > arraysz) {
232 			arraysz *= 2;
233 			queue = (struct queue **)realloc((char *)queue,
234 				arraysz * sizeof(struct queue *));
235 			if (queue == NULL)
236 				goto errdone;
237 		}
238 		queue[nitems-1] = q;
239 	}
240 	closedir(dirp);
241 	if (nitems)
242 		qsort(queue, nitems, sizeof(struct queue *), compar);
243 	*namelist = queue;
244 	return(nitems);
245 
246 errdone:
247 	closedir(dirp);
248 	return(-1);
249 }
250 
251 /*
252  * Compare modification times.
253  */
254 static int
255 compar(p1, p2)
256 	const void *p1, *p2;
257 {
258 	if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
259 		return(-1);
260 	if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
261 		return(1);
262 	return(0);
263 }
264 
265 /*
266  * Figure out whether the local machine is the same
267  * as the remote machine (RM) entry (if it exists).
268  */
269 char *
270 checkremote()
271 {
272 	char name[MAXHOSTNAMELEN];
273 	register struct hostent *hp;
274 	static char errbuf[128];
275 
276 	remote = 0;	/* assume printer is local */
277 	if (RM != NULL) {
278 		/* get the official name of the local host */
279 		gethostname(name, sizeof(name));
280 		name[sizeof(name)-1] = '\0';
281 		hp = gethostbyname(name);
282 		if (hp == (struct hostent *) NULL) {
283 		    (void) snprintf(errbuf, sizeof(errbuf),
284 			"unable to get official name for local machine %s",
285 			name);
286 		    return errbuf;
287 		} else (void) strcpy(name, hp->h_name);
288 
289 		/* get the official name of RM */
290 		hp = gethostbyname(RM);
291 		if (hp == (struct hostent *) NULL) {
292 		    (void) snprintf(errbuf, sizeof(errbuf),
293 			"unable to get official name for remote machine %s",
294 			RM);
295 		    return errbuf;
296 		}
297 
298 		/*
299 		 * if the two hosts are not the same,
300 		 * then the printer must be remote.
301 		 */
302 		if (strcasecmp(name, hp->h_name) != 0)
303 			remote = 1;
304 	}
305 	return NULL;
306 }
307 
308 /* sleep n milliseconds */
309 void
310 delay(n)
311 {
312 	struct timeval tdelay;
313 
314 	if (n <= 0 || n > 10000)
315 		fatal("unreasonable delay period (%d)", n);
316 	tdelay.tv_sec = n / 1000;
317 	tdelay.tv_usec = n * 1000 % 1000000;
318 	(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
319 }
320 
321 #if __STDC__
322 #include <stdarg.h>
323 #else
324 #include <varargs.h>
325 #endif
326 
327 void
328 #if __STDC__
329 fatal(const char *msg, ...)
330 #else
331 fatal(msg, va_alist)
332 	char *msg;
333         va_dcl
334 #endif
335 {
336 	va_list ap;
337 #if __STDC__
338 	va_start(ap, msg);
339 #else
340 	va_start(ap);
341 #endif
342 	if (from != host)
343 		(void)printf("%s: ", host);
344 	(void)printf("%s: ", name);
345 	if (printer)
346 		(void)printf("%s: ", printer);
347 	(void)vprintf(msg, ap);
348 	va_end(ap);
349 	(void)putchar('\n');
350 	exit(1);
351 }
352