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