1 1.44 andvar /* $NetBSD: common.c,v 1.44 2023/05/13 11:48:19 andvar Exp $ */ 2 1.8 jtc 3 1.4 cgd /* 4 1.5 cgd * Copyright (c) 1983, 1993 5 1.5 cgd * The Regents of the University of California. All rights reserved. 6 1.4 cgd * (c) UNIX System Laboratories, Inc. 7 1.4 cgd * All or some portions of this file are derived from material licensed 8 1.4 cgd * to the University of California by American Telephone and Telegraph 9 1.4 cgd * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 1.4 cgd * the permission of UNIX System Laboratories, Inc. 11 1.4 cgd * 12 1.4 cgd * Redistribution and use in source and binary forms, with or without 13 1.4 cgd * modification, are permitted provided that the following conditions 14 1.4 cgd * are met: 15 1.4 cgd * 1. Redistributions of source code must retain the above copyright 16 1.4 cgd * notice, this list of conditions and the following disclaimer. 17 1.4 cgd * 2. Redistributions in binary form must reproduce the above copyright 18 1.4 cgd * notice, this list of conditions and the following disclaimer in the 19 1.4 cgd * documentation and/or other materials provided with the distribution. 20 1.25 agc * 3. Neither the name of the University nor the names of its contributors 21 1.4 cgd * may be used to endorse or promote products derived from this software 22 1.4 cgd * without specific prior written permission. 23 1.4 cgd * 24 1.4 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.4 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.4 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.4 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.4 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.4 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.4 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.4 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.4 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.4 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.4 cgd * SUCH DAMAGE. 35 1.4 cgd */ 36 1.4 cgd 37 1.11 mrg #include <sys/cdefs.h> 38 1.4 cgd #ifndef lint 39 1.11 mrg #if 0 40 1.10 mrg static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95"; 41 1.11 mrg #else 42 1.44 andvar __RCSID("$NetBSD: common.c,v 1.44 2023/05/13 11:48:19 andvar Exp $"); 43 1.11 mrg #endif 44 1.4 cgd #endif /* not lint */ 45 1.4 cgd 46 1.5 cgd #include <sys/param.h> 47 1.5 cgd #include <sys/stat.h> 48 1.10 mrg #include <sys/time.h> 49 1.5 cgd 50 1.5 cgd #include <sys/socket.h> 51 1.5 cgd #include <netinet/in.h> 52 1.11 mrg #include <arpa/inet.h> 53 1.5 cgd #include <netdb.h> 54 1.5 cgd 55 1.5 cgd #include <dirent.h> 56 1.5 cgd #include <errno.h> 57 1.5 cgd #include <unistd.h> 58 1.5 cgd #include <stdlib.h> 59 1.5 cgd #include <stdio.h> 60 1.5 cgd #include <string.h> 61 1.21 itojun #include <ifaddrs.h> 62 1.5 cgd #include "lp.h" 63 1.28 christos #include "lp.local.h" 64 1.5 cgd #include "pathnames.h" 65 1.5 cgd 66 1.4 cgd /* 67 1.4 cgd * Routines and data common to all the line printer functions. 68 1.4 cgd */ 69 1.4 cgd 70 1.28 christos const char *AF; /* accounting file */ 71 1.28 christos long BR; /* baud rate if lp is a tty */ 72 1.28 christos const char *CF; /* name of cifplot filter (per job) */ 73 1.28 christos const char *DF; /* name of tex filter (per job) */ 74 1.28 christos long DU; /* daeomon user-id */ 75 1.28 christos long FC; /* flags to clear if lp is a tty */ 76 1.28 christos const char *FF; /* form feed string */ 77 1.28 christos long FS; /* flags to set if lp is a tty */ 78 1.28 christos const char *GF; /* name of graph(1G) filter (per job) */ 79 1.28 christos long HL; /* print header last */ 80 1.28 christos const char *IF; /* name of input filter (created per job) */ 81 1.28 christos const char *LF; /* log file for error messages */ 82 1.28 christos const char *LO; /* lock file name */ 83 1.28 christos const char *LP; /* line printer device name */ 84 1.28 christos long MC; /* maximum number of copies allowed */ 85 1.28 christos const char *MS; /* stty flags to set if lp is a tty */ 86 1.28 christos long MX; /* maximum number of blocks to copy */ 87 1.28 christos const char *NF; /* name of ditroff filter (per job) */ 88 1.28 christos const char *OF; /* name of output filter (created once) */ 89 1.31 garbled const char *PF; /* name of postscript filter (per job) */ 90 1.28 christos long PL; /* page length */ 91 1.28 christos long PW; /* page width */ 92 1.28 christos long PX; /* page width in pixels */ 93 1.28 christos long PY; /* page length in pixels */ 94 1.28 christos const char *RF; /* name of fortran text filter (per job) */ 95 1.28 christos const char *RG; /* resricted group */ 96 1.28 christos const char *RM; /* remote machine name */ 97 1.28 christos const char *RP; /* remote printer name */ 98 1.28 christos long RS; /* restricted to those with local accounts */ 99 1.28 christos long RW; /* open LP for reading and writing */ 100 1.28 christos long SB; /* short banner instead of normal header */ 101 1.28 christos long SC; /* suppress multiple copies */ 102 1.28 christos const char *SD; /* spool directory */ 103 1.28 christos long SF; /* suppress FF on each print job */ 104 1.28 christos long SH; /* suppress header page */ 105 1.28 christos const char *ST; /* status file name */ 106 1.28 christos const char *TF; /* name of troff filter (per job) */ 107 1.28 christos const char *TR; /* trailer string to be output when Q empties */ 108 1.31 garbled const char *VF; /* name of vplot/vrast filter (per job) */ 109 1.28 christos long XC; /* flags to clear for local mode */ 110 1.28 christos long XS; /* flags to set for local mode */ 111 1.4 cgd 112 1.4 cgd char line[BUFSIZ]; 113 1.10 mrg int remote; /* true if sending files to a remote host */ 114 1.5 cgd 115 1.6 hpeyerl extern uid_t uid, euid; 116 1.6 hpeyerl 117 1.23 wiz static int compar(const void *, const void *); 118 1.4 cgd 119 1.33 christos const char * 120 1.33 christos gethost(const char *hname) 121 1.33 christos { 122 1.33 christos const char *p = strchr(hname, '@'); 123 1.33 christos return p ? ++p : hname; 124 1.33 christos } 125 1.33 christos 126 1.4 cgd /* 127 1.33 christos * Create a TCP connection to host "rhost". If "rhost" is of the 128 1.33 christos * form port@host, use the specified port. Otherwise use the 129 1.33 christos * default printer port. Most of this code comes from rcmd.c. 130 1.4 cgd */ 131 1.5 cgd int 132 1.33 christos getport(const char *rhost) 133 1.4 cgd { 134 1.17 itojun struct addrinfo hints, *res, *r; 135 1.15 mrg u_int timo = 1; 136 1.15 mrg int s, lport = IPPORT_RESERVED - 1; 137 1.17 itojun int error; 138 1.18 itojun int refuse, trial; 139 1.33 christos char hbuf[NI_MAXSERV], *ptr; 140 1.33 christos const char *port = "printer"; 141 1.33 christos const char *hostname = rhost; 142 1.4 cgd 143 1.4 cgd /* 144 1.4 cgd * Get the host address and port number to connect to. 145 1.4 cgd */ 146 1.4 cgd if (rhost == NULL) 147 1.4 cgd fatal("no remote host to connect to"); 148 1.33 christos (void)strlcpy(hbuf, rhost, sizeof(hbuf)); 149 1.33 christos for (ptr = hbuf; *ptr; ptr++) 150 1.33 christos if (*ptr == '@') { 151 1.33 christos *ptr++ = '\0'; 152 1.33 christos port = hbuf; 153 1.33 christos hostname = ptr; 154 1.33 christos break; 155 1.33 christos } 156 1.33 christos (void)memset(&hints, 0, sizeof(hints)); 157 1.17 itojun hints.ai_family = PF_UNSPEC; 158 1.17 itojun hints.ai_socktype = SOCK_STREAM; 159 1.33 christos error = getaddrinfo(hostname, port, &hints, &res); 160 1.17 itojun if (error) 161 1.17 itojun fatal("printer/tcp: %s", gai_strerror(error)); 162 1.4 cgd 163 1.4 cgd /* 164 1.4 cgd * Try connecting to the server. 165 1.4 cgd */ 166 1.18 itojun retry: 167 1.17 itojun s = -1; 168 1.18 itojun refuse = trial = 0; 169 1.17 itojun for (r = res; r; r = r->ai_next) { 170 1.18 itojun trial++; 171 1.18 itojun retryport: 172 1.17 itojun seteuid(euid); 173 1.17 itojun s = rresvport_af(&lport, r->ai_family); 174 1.17 itojun seteuid(uid); 175 1.17 itojun if (s < 0) 176 1.17 itojun return(-1); 177 1.17 itojun if (connect(s, r->ai_addr, r->ai_addrlen) < 0) { 178 1.17 itojun error = errno; 179 1.17 itojun (void)close(s); 180 1.17 itojun s = -1; 181 1.17 itojun errno = error; 182 1.17 itojun if (errno == EADDRINUSE) { 183 1.17 itojun lport--; 184 1.18 itojun goto retryport; 185 1.18 itojun } else if (errno == ECONNREFUSED) 186 1.18 itojun refuse++; 187 1.17 itojun continue; 188 1.17 itojun } else 189 1.17 itojun break; 190 1.18 itojun } 191 1.18 itojun if (s < 0 && trial == refuse && timo <= 16) { 192 1.18 itojun sleep(timo); 193 1.18 itojun timo *= 2; 194 1.18 itojun goto retry; 195 1.4 cgd } 196 1.17 itojun if (res) 197 1.17 itojun freeaddrinfo(res); 198 1.4 cgd return(s); 199 1.4 cgd } 200 1.4 cgd 201 1.4 cgd /* 202 1.4 cgd * Getline reads a line from the control file cfp, removes tabs, converts 203 1.4 cgd * new-line to null and leaves it in line. 204 1.4 cgd * Returns 0 at EOF or the number of characters read. 205 1.4 cgd */ 206 1.39 lukem size_t 207 1.40 roy get_line(FILE *cfp) 208 1.4 cgd { 209 1.39 lukem size_t linel = 0; 210 1.39 lukem int c; 211 1.11 mrg char *lp = line; 212 1.4 cgd 213 1.11 mrg while ((c = getc(cfp)) != '\n' && linel+1<sizeof(line)) { 214 1.4 cgd if (c == EOF) 215 1.4 cgd return(0); 216 1.4 cgd if (c == '\t') { 217 1.4 cgd do { 218 1.4 cgd *lp++ = ' '; 219 1.4 cgd linel++; 220 1.11 mrg } while ((linel & 07) != 0 && linel+1 < sizeof(line)); 221 1.4 cgd continue; 222 1.4 cgd } 223 1.4 cgd *lp++ = c; 224 1.4 cgd linel++; 225 1.4 cgd } 226 1.4 cgd *lp++ = '\0'; 227 1.4 cgd return(linel); 228 1.4 cgd } 229 1.4 cgd 230 1.4 cgd /* 231 1.4 cgd * Scan the current directory and make a list of daemon files sorted by 232 1.4 cgd * creation time. 233 1.4 cgd * Return the number of entries and a pointer to the list. 234 1.4 cgd */ 235 1.5 cgd int 236 1.23 wiz getq(struct queue **namelist[]) 237 1.4 cgd { 238 1.11 mrg struct dirent *d; 239 1.35 christos struct queue *q, **queue = NULL, **nqueue; 240 1.4 cgd struct stat stbuf; 241 1.4 cgd DIR *dirp; 242 1.35 christos u_int nitems = 0, arraysz; 243 1.4 cgd 244 1.6 hpeyerl seteuid(euid); 245 1.22 wiz dirp = opendir(SD); 246 1.22 wiz seteuid(uid); 247 1.22 wiz if (dirp == NULL) 248 1.4 cgd return(-1); 249 1.4 cgd if (fstat(dirp->dd_fd, &stbuf) < 0) 250 1.4 cgd goto errdone; 251 1.4 cgd 252 1.4 cgd /* 253 1.4 cgd * Estimate the array size by taking the size of the directory file 254 1.4 cgd * and dividing it by a multiple of the minimum size entry. 255 1.4 cgd */ 256 1.15 mrg arraysz = (int)(stbuf.st_size / 24); 257 1.35 christos queue = calloc(arraysz, sizeof(struct queue *)); 258 1.4 cgd if (queue == NULL) 259 1.4 cgd goto errdone; 260 1.4 cgd 261 1.4 cgd while ((d = readdir(dirp)) != NULL) { 262 1.38 mlelstv if (d->d_name[0] != 'c' || d->d_name[1] != 'f' 263 1.38 mlelstv || d->d_name[2] == '\0') 264 1.4 cgd continue; /* daemon control files only */ 265 1.6 hpeyerl seteuid(euid); 266 1.22 wiz if (stat(d->d_name, &stbuf) < 0) { 267 1.22 wiz seteuid(uid); 268 1.4 cgd continue; /* Doesn't exist */ 269 1.22 wiz } 270 1.6 hpeyerl seteuid(uid); 271 1.4 cgd q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1); 272 1.4 cgd if (q == NULL) 273 1.4 cgd goto errdone; 274 1.4 cgd q->q_time = stbuf.st_mtime; 275 1.9 mrg strcpy(q->q_name, d->d_name); /* XXX: strcpy is safe */ 276 1.4 cgd /* 277 1.4 cgd * Check to make sure the array has space left and 278 1.4 cgd * realloc the maximum size. 279 1.4 cgd */ 280 1.4 cgd if (++nitems > arraysz) { 281 1.26 itojun nqueue = (struct queue **)realloc(queue, 282 1.26 itojun arraysz * 2 * sizeof(struct queue *)); 283 1.36 christos if (nqueue == NULL) { 284 1.37 christos free(q); 285 1.26 itojun goto errdone; 286 1.36 christos } 287 1.35 christos (void)memset(&nqueue[arraysz], 0, 288 1.44 andvar arraysz * sizeof(nqueue[0])); 289 1.26 itojun queue = nqueue; 290 1.10 mrg arraysz *= 2; 291 1.4 cgd } 292 1.4 cgd queue[nitems-1] = q; 293 1.4 cgd } 294 1.4 cgd closedir(dirp); 295 1.4 cgd if (nitems) 296 1.4 cgd qsort(queue, nitems, sizeof(struct queue *), compar); 297 1.4 cgd *namelist = queue; 298 1.4 cgd return(nitems); 299 1.4 cgd 300 1.4 cgd errdone: 301 1.35 christos freeq(queue, nitems); 302 1.4 cgd closedir(dirp); 303 1.4 cgd return(-1); 304 1.4 cgd } 305 1.4 cgd 306 1.35 christos void 307 1.35 christos freeq(struct queue **namelist, u_int nitems) 308 1.35 christos { 309 1.35 christos u_int i; 310 1.35 christos if (namelist == NULL) 311 1.35 christos return; 312 1.35 christos for (i = 0; i < nitems; i++) 313 1.35 christos if (namelist[i]) 314 1.35 christos free(namelist[i]); 315 1.35 christos free(namelist); 316 1.35 christos } 317 1.35 christos 318 1.4 cgd /* 319 1.4 cgd * Compare modification times. 320 1.4 cgd */ 321 1.5 cgd static int 322 1.23 wiz compar(const void *p1, const void *p2) 323 1.4 cgd { 324 1.28 christos const struct queue *const *q1 = p1; 325 1.28 christos const struct queue *const *q2 = p2; 326 1.38 mlelstv int j1, j2; 327 1.28 christos 328 1.28 christos if ((*q1)->q_time < (*q2)->q_time) 329 1.28 christos return -1; 330 1.28 christos if ((*q1)->q_time > (*q2)->q_time) 331 1.28 christos return 1; 332 1.38 mlelstv 333 1.38 mlelstv j1 = atoi((*q1)->q_name+3); 334 1.38 mlelstv j2 = atoi((*q2)->q_name+3); 335 1.38 mlelstv 336 1.38 mlelstv if (j1 == j2) 337 1.38 mlelstv return 0; 338 1.38 mlelstv if ((j1 < j2 && j2-j1 < 500) || (j1 > j2 && j1-j2 > 500)) 339 1.38 mlelstv return -1; 340 1.38 mlelstv if ((j1 < j2 && j2-j1 > 500) || (j1 > j2 && j1-j2 < 500)) 341 1.38 mlelstv return 1; 342 1.38 mlelstv 343 1.28 christos return 0; 344 1.4 cgd } 345 1.4 cgd 346 1.4 cgd /* 347 1.4 cgd * Figure out whether the local machine is the same 348 1.4 cgd * as the remote machine (RM) entry (if it exists). 349 1.4 cgd */ 350 1.28 christos const char * 351 1.23 wiz checkremote(void) 352 1.4 cgd { 353 1.43 prlw1 struct addrinfo hints, *res0; 354 1.4 cgd static char errbuf[128]; 355 1.17 itojun int error; 356 1.43 prlw1 struct ifaddrs *ifap; 357 1.43 prlw1 #if defined(INET6) && defined(__KAME__) 358 1.43 prlw1 char lname[NI_MAXHOST], rname[NI_MAXHOST]; 359 1.43 prlw1 struct addrinfo *res; 360 1.43 prlw1 struct ifaddrs *ifa; 361 1.21 itojun const int niflags = NI_NUMERICHOST; 362 1.21 itojun struct sockaddr_in6 sin6; 363 1.21 itojun struct sockaddr_in6 *sin6p; 364 1.21 itojun #endif 365 1.21 itojun 366 1.21 itojun remote = 0; /* assume printer is local on failure */ 367 1.4 cgd 368 1.21 itojun if (RM == NULL) 369 1.21 itojun return NULL; 370 1.21 itojun 371 1.21 itojun /* get the local interface addresses */ 372 1.21 itojun if (getifaddrs(&ifap) < 0) { 373 1.21 itojun (void)snprintf(errbuf, sizeof(errbuf), 374 1.21 itojun "unable to get local interface address: %s", 375 1.21 itojun strerror(errno)); 376 1.21 itojun return errbuf; 377 1.21 itojun } 378 1.4 cgd 379 1.21 itojun /* get the remote host addresses (RM) */ 380 1.21 itojun memset(&hints, 0, sizeof(hints)); 381 1.21 itojun hints.ai_flags = AI_CANONNAME; 382 1.21 itojun hints.ai_family = PF_UNSPEC; 383 1.21 itojun hints.ai_socktype = SOCK_STREAM; 384 1.33 christos error = getaddrinfo(gethost(RM), NULL, &hints, &res0); 385 1.21 itojun if (error) { 386 1.21 itojun (void)snprintf(errbuf, sizeof(errbuf), 387 1.21 itojun "unable to resolve remote machine %s: %s", 388 1.21 itojun RM, gai_strerror(error)); 389 1.21 itojun freeifaddrs(ifap); 390 1.21 itojun return errbuf; 391 1.21 itojun } 392 1.4 cgd 393 1.21 itojun remote = 1; /* assume printer is remote */ 394 1.17 itojun 395 1.43 prlw1 #if defined(INET6) && defined(__KAME__) 396 1.21 itojun for (res = res0; res; res = res->ai_next) { 397 1.21 itojun if (getnameinfo(res->ai_addr, res->ai_addrlen, 398 1.21 itojun rname, sizeof(rname), NULL, 0, niflags) != 0) 399 1.21 itojun continue; 400 1.21 itojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 401 1.21 itojun sin6p = (struct sockaddr_in6 *)ifa->ifa_addr; 402 1.21 itojun if (ifa->ifa_addr->sa_family == AF_INET6 && 403 1.41 christos ifa->ifa_addr->sa_len == sizeof(sin6)) { 404 1.42 christos inet6_getscopeid(sin6p, 3); 405 1.21 itojun if (getnameinfo((struct sockaddr *)&sin6, 406 1.21 itojun sin6.sin6_len, lname, sizeof(lname), 407 1.21 itojun NULL, 0, niflags) != 0) 408 1.21 itojun continue; 409 1.42 christos if (strcmp(rname, lname) == 0) { 410 1.42 christos remote = 0; 411 1.42 christos goto done; 412 1.42 christos } 413 1.21 itojun } 414 1.21 itojun } 415 1.4 cgd } 416 1.21 itojun done: 417 1.43 prlw1 #endif 418 1.21 itojun freeaddrinfo(res0); 419 1.21 itojun freeifaddrs(ifap); 420 1.10 mrg return NULL; 421 1.10 mrg } 422 1.10 mrg 423 1.10 mrg /* sleep n milliseconds */ 424 1.10 mrg void 425 1.23 wiz delay(int n) 426 1.10 mrg { 427 1.24 mycroft struct timespec tdelay; 428 1.10 mrg 429 1.10 mrg if (n <= 0 || n > 10000) 430 1.10 mrg fatal("unreasonable delay period (%d)", n); 431 1.10 mrg tdelay.tv_sec = n / 1000; 432 1.24 mycroft tdelay.tv_nsec = (n % 1000) * 1000000; 433 1.24 mycroft nanosleep(&tdelay, NULL); 434 1.4 cgd } 435 1.28 christos 436 1.28 christos void 437 1.28 christos getprintcap(const char *pr) 438 1.28 christos { 439 1.28 christos char *cp; 440 1.28 christos const char *dp; 441 1.28 christos int i; 442 1.28 christos 443 1.28 christos if ((i = cgetent(&bp, printcapdb, pr)) == -2) 444 1.28 christos fatal("can't open printer description file"); 445 1.28 christos else if (i == -1) 446 1.28 christos fatal("unknown printer: %s", pr); 447 1.28 christos else if (i == -3) 448 1.28 christos fatal("potential reference loop detected in printcap file"); 449 1.28 christos 450 1.28 christos LP = cgetstr(bp, DEFLP, &cp) == -1 ? _PATH_DEFDEVLP : cp; 451 1.28 christos RP = cgetstr(bp, "rp", &cp) == -1 ? DEFLP : cp; 452 1.28 christos SD = cgetstr(bp, "sd", &cp) == -1 ? _PATH_DEFSPOOL : cp; 453 1.28 christos LO = cgetstr(bp, "lo", &cp) == -1 ? DEFLOCK : cp; 454 1.28 christos ST = cgetstr(bp, "st", &cp) == -1 ? DEFSTAT : cp; 455 1.28 christos RM = cgetstr(bp, "rm", &cp) == -1 ? NULL : cp; 456 1.28 christos if ((dp = checkremote()) != NULL) 457 1.28 christos printf("Warning: %s\n", dp); 458 1.28 christos LF = cgetstr(bp, "lf", &cp) == -1 ? _PATH_CONSOLE : cp; 459 1.28 christos } 460 1.28 christos 461 1.28 christos /* 462 1.28 christos * Make sure there's some work to do before forking off a child 463 1.28 christos */ 464 1.28 christos int 465 1.28 christos ckqueue(char *cap) 466 1.28 christos { 467 1.28 christos struct dirent *d; 468 1.28 christos DIR *dirp; 469 1.28 christos const char *spooldir; 470 1.30 garbled char *sd = NULL; 471 1.28 christos int rv = 0; 472 1.28 christos 473 1.28 christos spooldir = cgetstr(cap, "sd", &sd) == -1 ? _PATH_DEFSPOOL : sd; 474 1.28 christos if ((dirp = opendir(spooldir)) == NULL) { 475 1.28 christos rv = -1; 476 1.28 christos goto out; 477 1.28 christos } 478 1.28 christos while ((d = readdir(dirp)) != NULL) { 479 1.28 christos if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 480 1.28 christos continue; /* daemon control files only */ 481 1.28 christos rv = 1; 482 1.28 christos break; 483 1.28 christos } 484 1.28 christos out: 485 1.28 christos if (dirp != NULL) 486 1.28 christos closedir(dirp); 487 1.28 christos if (spooldir != sd) 488 1.28 christos free(sd); 489 1.32 garbled return (rv); 490 1.28 christos } 491