1 /* $NetBSD: common.c,v 1.16 1999/12/05 22:10:57 jdolecek 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.16 1999/12/05 22:10:57 jdolecek 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 int remote; /* true if sending files to a remote host */ 116 117 extern uid_t uid, euid; 118 119 static int compar __P((const void *, const void *)); 120 121 /* 122 * Create a TCP connection to host "rhost" at port "rport". 123 * If rport == 0, then use the printer service port. 124 * Most of this code comes from rcmd.c. 125 */ 126 int 127 getport(rhost, rport) 128 char *rhost; 129 int rport; 130 { 131 struct hostent *hp; 132 struct servent *sp; 133 struct sockaddr_in sin; 134 u_int timo = 1; 135 int s, 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 memset(&sin, 0, sizeof(sin)); 144 if (inet_aton(rhost, &sin.sin_addr) == 1) 145 sin.sin_family = AF_INET; 146 else { 147 hp = gethostbyname(rhost); 148 if (hp == NULL) 149 fatal("unknown host %s", rhost); 150 memmove(&sin.sin_addr, hp->h_addr, (size_t)hp->h_length); 151 sin.sin_family = hp->h_addrtype; 152 } 153 if (rport == 0) { 154 sp = getservbyname("printer", "tcp"); 155 if (sp == NULL) 156 fatal("printer/tcp: unknown service"); 157 sin.sin_port = sp->s_port; 158 } else 159 sin.sin_port = htons(rport); 160 161 /* 162 * Try connecting to the server. 163 */ 164 retry: 165 seteuid(euid); 166 s = rresvport(&lport); 167 seteuid(uid); 168 if (s < 0) 169 return(-1); 170 if (connect(s, (const struct sockaddr *)&sin, sizeof(sin)) < 0) { 171 err = errno; 172 (void)close(s); 173 errno = err; 174 if (errno == EADDRINUSE) { 175 lport--; 176 goto retry; 177 } 178 if (errno == ECONNREFUSED && timo <= 16) { 179 sleep(timo); 180 timo *= 2; 181 goto retry; 182 } 183 return(-1); 184 } 185 return(s); 186 } 187 188 /* 189 * Getline reads a line from the control file cfp, removes tabs, converts 190 * new-line to null and leaves it in line. 191 * Returns 0 at EOF or the number of characters read. 192 */ 193 int 194 getline(cfp) 195 FILE *cfp; 196 { 197 int linel = 0, c; 198 char *lp = line; 199 200 while ((c = getc(cfp)) != '\n' && linel+1<sizeof(line)) { 201 if (c == EOF) 202 return(0); 203 if (c == '\t') { 204 do { 205 *lp++ = ' '; 206 linel++; 207 } while ((linel & 07) != 0 && linel+1 < sizeof(line)); 208 continue; 209 } 210 *lp++ = c; 211 linel++; 212 } 213 *lp++ = '\0'; 214 return(linel); 215 } 216 217 /* 218 * Scan the current directory and make a list of daemon files sorted by 219 * creation time. 220 * Return the number of entries and a pointer to the list. 221 */ 222 int 223 getq(namelist) 224 struct queue *(*namelist[]); 225 { 226 struct dirent *d; 227 struct queue *q, **queue; 228 struct stat stbuf; 229 DIR *dirp; 230 u_int nitems, arraysz; 231 232 seteuid(euid); 233 if ((dirp = opendir(SD)) == NULL) 234 return(-1); 235 if (fstat(dirp->dd_fd, &stbuf) < 0) 236 goto errdone; 237 seteuid(uid); 238 239 /* 240 * Estimate the array size by taking the size of the directory file 241 * and dividing it by a multiple of the minimum size entry. 242 */ 243 arraysz = (int)(stbuf.st_size / 24); 244 queue = (struct queue **)malloc(arraysz * sizeof(struct queue *)); 245 if (queue == NULL) 246 goto errdone; 247 248 nitems = 0; 249 while ((d = readdir(dirp)) != NULL) { 250 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 251 continue; /* daemon control files only */ 252 seteuid(euid); 253 if (stat(d->d_name, &stbuf) < 0) 254 continue; /* Doesn't exist */ 255 seteuid(uid); 256 q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1); 257 if (q == NULL) 258 goto errdone; 259 q->q_time = stbuf.st_mtime; 260 strcpy(q->q_name, d->d_name); /* XXX: strcpy is safe */ 261 /* 262 * Check to make sure the array has space left and 263 * realloc the maximum size. 264 */ 265 if (++nitems > arraysz) { 266 arraysz *= 2; 267 queue = (struct queue **)realloc(queue, 268 arraysz * sizeof(struct queue *)); 269 if (queue == NULL) 270 goto errdone; 271 } 272 queue[nitems-1] = q; 273 } 274 closedir(dirp); 275 if (nitems) 276 qsort(queue, nitems, sizeof(struct queue *), compar); 277 *namelist = queue; 278 return(nitems); 279 280 errdone: 281 closedir(dirp); 282 return(-1); 283 } 284 285 /* 286 * Compare modification times. 287 */ 288 static int 289 compar(p1, p2) 290 const void *p1, *p2; 291 { 292 if ((*(struct queue **)p1)->q_time < (*(struct queue **)p2)->q_time) 293 return(-1); 294 if ((*(struct queue **)p1)->q_time > (*(struct queue **)p2)->q_time) 295 return(1); 296 return(0); 297 } 298 299 /* 300 * Figure out whether the local machine is the same 301 * as the remote machine (RM) entry (if it exists). 302 */ 303 char * 304 checkremote() 305 { 306 char hname[MAXHOSTNAMELEN + 1]; 307 struct hostent *hp; 308 static char errbuf[128]; 309 310 remote = 0; /* assume printer is local */ 311 if (RM != NULL) { 312 /* get the official name of the local host */ 313 gethostname(hname, sizeof(hname)); 314 hname[sizeof(hname)-1] = '\0'; 315 hp = gethostbyname(hname); 316 if (hp == (struct hostent *) NULL) { 317 (void)snprintf(errbuf, sizeof(errbuf), 318 "unable to get official name for local machine %s", 319 hname); 320 return errbuf; 321 } else { 322 (void)strncpy(hname, hp->h_name, sizeof(hname) - 1); 323 hname[sizeof(hname) - 1] = '\0'; 324 } 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(hname, hp->h_name) != 0) 340 remote = 1; 341 } 342 return NULL; 343 } 344 345 /* sleep n milliseconds */ 346 void 347 delay(n) 348 int n; 349 { 350 struct timeval tdelay; 351 352 if (n <= 0 || n > 10000) 353 fatal("unreasonable delay period (%d)", n); 354 tdelay.tv_sec = n / 1000; 355 tdelay.tv_usec = n * 1000 % 1000000; 356 (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay); 357 } 358