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