1 /* $NetBSD: common.c,v 1.39 2009/01/18 09:57:26 lukem Exp $ */
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.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
40 static char sccsid
[] = "@(#)common.c 8.5 (Berkeley) 4/28/95";
42 __RCSID("$NetBSD: common.c,v 1.39 2009/01/18 09:57:26 lukem Exp $");
46 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
64 #include "pathnames.h"
67 * Routines and data common to all the line printer functions.
70 const char *AF
; /* accounting file */
71 long BR
; /* baud rate if lp is a tty */
72 const char *CF
; /* name of cifplot filter (per job) */
73 const char *DF
; /* name of tex filter (per job) */
74 long DU
; /* daeomon user-id */
75 long FC
; /* flags to clear if lp is a tty */
76 const char *FF
; /* form feed string */
77 long FS
; /* flags to set if lp is a tty */
78 const char *GF
; /* name of graph(1G) filter (per job) */
79 long HL
; /* print header last */
80 const char *IF
; /* name of input filter (created per job) */
81 const char *LF
; /* log file for error messages */
82 const char *LO
; /* lock file name */
83 const char *LP
; /* line printer device name */
84 long MC
; /* maximum number of copies allowed */
85 const char *MS
; /* stty flags to set if lp is a tty */
86 long MX
; /* maximum number of blocks to copy */
87 const char *NF
; /* name of ditroff filter (per job) */
88 const char *OF
; /* name of output filter (created once) */
89 const char *PF
; /* name of postscript filter (per job) */
90 long PL
; /* page length */
91 long PW
; /* page width */
92 long PX
; /* page width in pixels */
93 long PY
; /* page length in pixels */
94 const char *RF
; /* name of fortran text filter (per job) */
95 const char *RG
; /* resricted group */
96 const char *RM
; /* remote machine name */
97 const char *RP
; /* remote printer name */
98 long RS
; /* restricted to those with local accounts */
99 long RW
; /* open LP for reading and writing */
100 long SB
; /* short banner instead of normal header */
101 long SC
; /* suppress multiple copies */
102 const char *SD
; /* spool directory */
103 long SF
; /* suppress FF on each print job */
104 long SH
; /* suppress header page */
105 const char *ST
; /* status file name */
106 const char *TF
; /* name of troff filter (per job) */
107 const char *TR
; /* trailer string to be output when Q empties */
108 const char *VF
; /* name of vplot/vrast filter (per job) */
109 long XC
; /* flags to clear for local mode */
110 long XS
; /* flags to set for local mode */
113 int remote
; /* true if sending files to a remote host */
115 extern uid_t uid
, euid
;
117 static int compar(const void *, const void *);
120 gethost(const char *hname
)
122 const char *p
= strchr(hname
, '@');
123 return p
? ++p
: hname
;
127 * Create a TCP connection to host "rhost". If "rhost" is of the
128 * form port@host, use the specified port. Otherwise use the
129 * default printer port. Most of this code comes from rcmd.c.
132 getport(const char *rhost
)
134 struct addrinfo hints
, *res
, *r
;
136 int s
, lport
= IPPORT_RESERVED
- 1;
139 char hbuf
[NI_MAXSERV
], *ptr
;
140 const char *port
= "printer";
141 const char *hostname
= rhost
;
144 * Get the host address and port number to connect to.
147 fatal("no remote host to connect to");
148 (void)strlcpy(hbuf
, rhost
, sizeof(hbuf
));
149 for (ptr
= hbuf
; *ptr
; ptr
++)
156 (void)memset(&hints
, 0, sizeof(hints
));
157 hints
.ai_family
= PF_UNSPEC
;
158 hints
.ai_socktype
= SOCK_STREAM
;
159 error
= getaddrinfo(hostname
, port
, &hints
, &res
);
161 fatal("printer/tcp: %s", gai_strerror(error
));
164 * Try connecting to the server.
169 for (r
= res
; r
; r
= r
->ai_next
) {
173 s
= rresvport_af(&lport
, r
->ai_family
);
177 if (connect(s
, r
->ai_addr
, r
->ai_addrlen
) < 0) {
182 if (errno
== EADDRINUSE
) {
185 } else if (errno
== ECONNREFUSED
)
191 if (s
< 0 && trial
== refuse
&& timo
<= 16) {
202 * Getline reads a line from the control file cfp, removes tabs, converts
203 * new-line to null and leaves it in line.
204 * Returns 0 at EOF or the number of characters read.
213 while ((c
= getc(cfp
)) != '\n' && linel
+1<sizeof(line
)) {
220 } while ((linel
& 07) != 0 && linel
+1 < sizeof(line
));
231 * Scan the current directory and make a list of daemon files sorted by
233 * Return the number of entries and a pointer to the list.
236 getq(struct queue
**namelist
[])
239 struct queue
*q
, **queue
= NULL
, **nqueue
;
242 u_int nitems
= 0, arraysz
;
249 if (fstat(dirp
->dd_fd
, &stbuf
) < 0)
253 * Estimate the array size by taking the size of the directory file
254 * and dividing it by a multiple of the minimum size entry.
256 arraysz
= (int)(stbuf
.st_size
/ 24);
257 queue
= calloc(arraysz
, sizeof(struct queue
*));
261 while ((d
= readdir(dirp
)) != NULL
) {
262 if (d
->d_name
[0] != 'c' || d
->d_name
[1] != 'f'
263 || d
->d_name
[2] == '\0')
264 continue; /* daemon control files only */
266 if (stat(d
->d_name
, &stbuf
) < 0) {
268 continue; /* Doesn't exist */
271 q
= (struct queue
*)malloc(sizeof(time_t)+strlen(d
->d_name
)+1);
274 q
->q_time
= stbuf
.st_mtime
;
275 strcpy(q
->q_name
, d
->d_name
); /* XXX: strcpy is safe */
277 * Check to make sure the array has space left and
278 * realloc the maximum size.
280 if (++nitems
> arraysz
) {
281 nqueue
= (struct queue
**)realloc(queue
,
282 arraysz
* 2 * sizeof(struct queue
*));
283 if (nqueue
== NULL
) {
287 (void)memset(&nqueue
[arraysz
], 0,
288 arraysz
* sizeof(struct queueue
*));
296 qsort(queue
, nitems
, sizeof(struct queue
*), compar
);
301 freeq(queue
, nitems
);
307 freeq(struct queue
**namelist
, u_int nitems
)
310 if (namelist
== NULL
)
312 for (i
= 0; i
< nitems
; i
++)
319 * Compare modification times.
322 compar(const void *p1
, const void *p2
)
324 const struct queue
*const *q1
= p1
;
325 const struct queue
*const *q2
= p2
;
328 if ((*q1
)->q_time
< (*q2
)->q_time
)
330 if ((*q1
)->q_time
> (*q2
)->q_time
)
333 j1
= atoi((*q1
)->q_name
+3);
334 j2
= atoi((*q2
)->q_name
+3);
338 if ((j1
< j2
&& j2
-j1
< 500) || (j1
> j2
&& j1
-j2
> 500))
340 if ((j1
< j2
&& j2
-j1
> 500) || (j1
> j2
&& j1
-j2
< 500))
347 * Figure out whether the local machine is the same
348 * as the remote machine (RM) entry (if it exists).
353 char lname
[NI_MAXHOST
], rname
[NI_MAXHOST
];
354 struct addrinfo hints
, *res
, *res0
;
355 static char errbuf
[128];
357 struct ifaddrs
*ifap
, *ifa
;
358 const int niflags
= NI_NUMERICHOST
;
360 struct sockaddr_in6 sin6
;
361 struct sockaddr_in6
*sin6p
;
364 remote
= 0; /* assume printer is local on failure */
369 /* get the local interface addresses */
370 if (getifaddrs(&ifap
) < 0) {
371 (void)snprintf(errbuf
, sizeof(errbuf
),
372 "unable to get local interface address: %s",
377 /* get the remote host addresses (RM) */
378 memset(&hints
, 0, sizeof(hints
));
379 hints
.ai_flags
= AI_CANONNAME
;
380 hints
.ai_family
= PF_UNSPEC
;
381 hints
.ai_socktype
= SOCK_STREAM
;
383 error
= getaddrinfo(gethost(RM
), NULL
, &hints
, &res0
);
385 (void)snprintf(errbuf
, sizeof(errbuf
),
386 "unable to resolve remote machine %s: %s",
387 RM
, gai_strerror(error
));
392 remote
= 1; /* assume printer is remote */
394 for (res
= res0
; res
; res
= res
->ai_next
) {
395 if (getnameinfo(res
->ai_addr
, res
->ai_addrlen
,
396 rname
, sizeof(rname
), NULL
, 0, niflags
) != 0)
398 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
400 sin6p
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
401 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&&
402 ifa
->ifa_addr
->sa_len
== sizeof(sin6
) &&
403 IN6_IS_ADDR_LINKLOCAL(&sin6p
->sin6_addr
) &&
404 *(u_int16_t
*)&sin6p
->sin6_addr
.s6_addr
[2]) {
405 /* kame scopeid hack */
406 memcpy(&sin6
, ifa
->ifa_addr
, sizeof(sin6
));
408 ntohs(*(u_int16_t
*)&sin6p
->sin6_addr
.s6_addr
[2]);
409 sin6
.sin6_addr
.s6_addr
[2] = 0;
410 sin6
.sin6_addr
.s6_addr
[3] = 0;
411 if (getnameinfo((struct sockaddr
*)&sin6
,
412 sin6
.sin6_len
, lname
, sizeof(lname
),
413 NULL
, 0, niflags
) != 0)
417 if (getnameinfo(ifa
->ifa_addr
, ifa
->ifa_addr
->sa_len
,
418 lname
, sizeof(lname
), NULL
, 0, niflags
) != 0)
421 if (strcmp(rname
, lname
) == 0) {
433 /* sleep n milliseconds */
437 struct timespec tdelay
;
439 if (n
<= 0 || n
> 10000)
440 fatal("unreasonable delay period (%d)", n
);
441 tdelay
.tv_sec
= n
/ 1000;
442 tdelay
.tv_nsec
= (n
% 1000) * 1000000;
443 nanosleep(&tdelay
, NULL
);
447 getprintcap(const char *pr
)
453 if ((i
= cgetent(&bp
, printcapdb
, pr
)) == -2)
454 fatal("can't open printer description file");
456 fatal("unknown printer: %s", pr
);
458 fatal("potential reference loop detected in printcap file");
460 LP
= cgetstr(bp
, DEFLP
, &cp
) == -1 ? _PATH_DEFDEVLP
: cp
;
461 RP
= cgetstr(bp
, "rp", &cp
) == -1 ? DEFLP
: cp
;
462 SD
= cgetstr(bp
, "sd", &cp
) == -1 ? _PATH_DEFSPOOL
: cp
;
463 LO
= cgetstr(bp
, "lo", &cp
) == -1 ? DEFLOCK
: cp
;
464 ST
= cgetstr(bp
, "st", &cp
) == -1 ? DEFSTAT
: cp
;
465 RM
= cgetstr(bp
, "rm", &cp
) == -1 ? NULL
: cp
;
466 if ((dp
= checkremote()) != NULL
)
467 printf("Warning: %s\n", dp
);
468 LF
= cgetstr(bp
, "lf", &cp
) == -1 ? _PATH_CONSOLE
: cp
;
472 * Make sure there's some work to do before forking off a child
479 const char *spooldir
;
483 spooldir
= cgetstr(cap
, "sd", &sd
) == -1 ? _PATH_DEFSPOOL
: sd
;
484 if ((dirp
= opendir(spooldir
)) == NULL
) {
488 while ((d
= readdir(dirp
)) != NULL
) {
489 if (d
->d_name
[0] != 'c' || d
->d_name
[1] != 'f')
490 continue; /* daemon control files only */