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.3 (Berkeley) 04/27/95";
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 			arraysz *= 2;
222 			queue = (struct queue **)realloc((char *)queue,
223 				arraysz * sizeof(struct queue *));
224 			if (queue == NULL)
225 				goto errdone;
226 		}
227 		queue[nitems-1] = q;
228 	}
229 	closedir(dirp);
230 	if (nitems)
231 		qsort(queue, nitems, sizeof(struct queue *), compar);
232 	*namelist = queue;
233 	return(nitems);
234 
235 errdone:
236 	closedir(dirp);
237 	return(-1);
238 }
239 
240 /*
241  * Compare modification times.
242  */
243 static int
244 compar(p1, p2)
245 	const void *p1, *p2;
246 {
247 	if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time)
248 		return(-1);
249 	if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time)
250 		return(1);
251 	return(0);
252 }
253 
254 /*
255  * Figure out whether the local machine is the same
256  * as the remote machine (RM) entry (if it exists).
257  */
258 char *
259 checkremote()
260 {
261 	char name[MAXHOSTNAMELEN];
262 	register struct hostent *hp;
263 	static char errbuf[128];
264 
265 	sendtorem = 0;	/* assume printer is local */
266 	if (RM != (char *)NULL) {
267 		/* get the official name of the local host */
268 		gethostname(name, sizeof(name));
269 		name[sizeof(name)-1] = '\0';
270 		hp = gethostbyname(name);
271 		if (hp == (struct hostent *) NULL) {
272 		    (void) snprintf(errbuf, sizeof(errbuf),
273 			"unable to get official name for local machine %s",
274 			name);
275 		    return errbuf;
276 		} else (void) strcpy(name, hp->h_name);
277 
278 		/* get the official name of RM */
279 		hp = gethostbyname(RM);
280 		if (hp == (struct hostent *) NULL) {
281 		    (void) snprintf(errbuf, sizeof(errbuf),
282 			"unable to get official name for remote machine %s",
283 			RM);
284 		    return errbuf;
285 		}
286 
287 		/*
288 		 * if the two hosts are not the same,
289 		 * then the printer must be remote.
290 		 */
291 		if (strcasecmp(name, hp->h_name) != 0)
292 			sendtorem = 1;
293 	}
294 	return NULL;
295 }
296 
297 #if __STDC__
298 #include <stdarg.h>
299 #else
300 #include <varargs.h>
301 #endif
302 
303 void
304 #if __STDC__
305 fatal(const char *msg, ...)
306 #else
307 fatal(msg, va_alist)
308 	char *msg;
309         va_dcl
310 #endif
311 {
312 	va_list ap;
313 #if __STDC__
314 	va_start(ap, msg);
315 #else
316 	va_start(ap);
317 #endif
318 	if (from != host)
319 		(void)printf("%s: ", host);
320 	(void)printf("%s: ", name);
321 	if (printer)
322 		(void)printf("%s: ", printer);
323 	(void)vprintf(msg, ap);
324 	va_end(ap);
325 	(void)putchar('\n');
326 	exit(1);
327 }
328