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