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