1 1.57 mrg /* $NetBSD: printjob.c,v 1.57 2019/02/03 03:19:30 mrg Exp $ */ 2 1.14 mikel 3 1.1 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.5 cgd * 7 1.1 cgd * 8 1.1 cgd * Redistribution and use in source and binary forms, with or without 9 1.1 cgd * modification, are permitted provided that the following conditions 10 1.1 cgd * are met: 11 1.1 cgd * 1. Redistributions of source code must retain the above copyright 12 1.1 cgd * notice, this list of conditions and the following disclaimer. 13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer in the 15 1.1 cgd * documentation and/or other materials provided with the distribution. 16 1.39 agc * 3. Neither the name of the University nor the names of its contributors 17 1.1 cgd * may be used to endorse or promote products derived from this software 18 1.1 cgd * without specific prior written permission. 19 1.1 cgd * 20 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 cgd * SUCH DAMAGE. 31 1.1 cgd */ 32 1.1 cgd 33 1.14 mikel #include <sys/cdefs.h> 34 1.14 mikel 35 1.1 cgd #ifndef lint 36 1.54 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 37 1.54 lukem The Regents of the University of California. All rights reserved."); 38 1.5 cgd #endif /* not lint */ 39 1.5 cgd 40 1.5 cgd #ifndef lint 41 1.13 mikel #if 0 42 1.15 mrg static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 43 1.13 mikel #else 44 1.57 mrg __RCSID("$NetBSD: printjob.c,v 1.57 2019/02/03 03:19:30 mrg Exp $"); 45 1.13 mikel #endif 46 1.1 cgd #endif /* not lint */ 47 1.1 cgd 48 1.5 cgd 49 1.1 cgd /* 50 1.1 cgd * printjob -- print jobs in the queue. 51 1.1 cgd * 52 1.1 cgd * NOTE: the lock file is used to pass information to lpq and lprm. 53 1.1 cgd * it does not need to be removed because file locks are dynamic. 54 1.1 cgd */ 55 1.1 cgd 56 1.5 cgd #include <sys/param.h> 57 1.5 cgd #include <sys/wait.h> 58 1.5 cgd #include <sys/stat.h> 59 1.5 cgd #include <sys/types.h> 60 1.15 mrg #include <sys/file.h> 61 1.5 cgd 62 1.5 cgd #include <pwd.h> 63 1.5 cgd #include <unistd.h> 64 1.40 wiz #include <sys/uio.h> 65 1.5 cgd #include <signal.h> 66 1.7 hpeyerl #include <termios.h> 67 1.5 cgd #include <syslog.h> 68 1.5 cgd #include <fcntl.h> 69 1.5 cgd #include <dirent.h> 70 1.5 cgd #include <errno.h> 71 1.5 cgd #include <stdio.h> 72 1.5 cgd #include <string.h> 73 1.5 cgd #include <stdlib.h> 74 1.16 mrg #include <ctype.h> 75 1.1 cgd #include "lp.h" 76 1.5 cgd #include "lp.local.h" 77 1.1 cgd #include "pathnames.h" 78 1.5 cgd #include "extern.h" 79 1.1 cgd 80 1.1 cgd #define DORETURN 0 /* absorb fork error */ 81 1.1 cgd #define DOABORT 1 /* abort if dofork fails */ 82 1.1 cgd 83 1.1 cgd /* 84 1.1 cgd * Error tokens 85 1.1 cgd */ 86 1.1 cgd #define REPRINT -2 87 1.1 cgd #define ERROR -1 88 1.1 cgd #define OK 0 89 1.1 cgd #define FATALERR 1 90 1.1 cgd #define NOACCT 2 91 1.1 cgd #define FILTERERR 3 92 1.1 cgd #define ACCESS 4 93 1.1 cgd 94 1.21 mrg static dev_t fdev; /* device of file pointed to by symlink */ 95 1.21 mrg static ino_t fino; /* inode of file pointed to by symlink */ 96 1.5 cgd static FILE *cfp; /* control file */ 97 1.21 mrg static int child; /* id of any filters */ 98 1.21 mrg static int lfd; /* lock file descriptor */ 99 1.21 mrg static int ofd; /* output filter file descriptor */ 100 1.21 mrg static int ofilter; /* id of output filter, if any */ 101 1.33 hubertf static int pfd; /* printer file descriptor */ 102 1.21 mrg static int pid; /* pid of lpd process */ 103 1.21 mrg static int prchild; /* id of pr process */ 104 1.21 mrg static char title[80]; /* ``pr'' title */ 105 1.21 mrg static int tof; /* true if at top of form */ 106 1.5 cgd 107 1.5 cgd static char class[32]; /* classification field */ 108 1.5 cgd static char fromhost[32]; /* user's host machine */ 109 1.5 cgd /* indentation size in static characters */ 110 1.5 cgd static char indent[10] = "-i0"; 111 1.5 cgd static char jobname[100]; /* job or file name */ 112 1.5 cgd static char length[10] = "-l"; /* page length in lines */ 113 1.5 cgd static char logname[32]; /* user's login name */ 114 1.5 cgd static char pxlength[10] = "-y"; /* page length in pixels */ 115 1.5 cgd static char pxwidth[10] = "-x"; /* page width in pixels */ 116 1.5 cgd static char tempfile[] = "errsXXXXXX"; /* file name for filter output */ 117 1.35 abs static char tempremote[] = "remoteXXXXXX"; /* file name for remote filter */ 118 1.5 cgd static char width[10] = "-w"; /* page width in static characters */ 119 1.5 cgd 120 1.56 joerg __dead static void abortpr(int); 121 1.34 wiz static void banner(char *, char *); 122 1.34 wiz static int dofork(int); 123 1.34 wiz static int dropit(int); 124 1.34 wiz static void init(void); 125 1.35 abs static void setup_ofilter(int); 126 1.35 abs static void close_ofilter(void); 127 1.34 wiz static void openpr(void); 128 1.48 christos static void opennet(void); 129 1.34 wiz static void opentty(void); 130 1.34 wiz static void openrem(void); 131 1.34 wiz static int print(int, char *); 132 1.34 wiz static int printit(char *); 133 1.36 abs static void pstatus(const char *, ...) 134 1.36 abs __attribute__((__format__(__printf__, 1, 2))); 135 1.34 wiz static char response(void); 136 1.34 wiz static void scan_out(int, char *, int); 137 1.34 wiz static char *scnline(int, char *, int); 138 1.34 wiz static int sendfile(int, char *); 139 1.34 wiz static int sendit(char *); 140 1.34 wiz static void sendmail(char *, int); 141 1.34 wiz static void setty(void); 142 1.34 wiz static void alarmer(int); 143 1.1 cgd 144 1.5 cgd void 145 1.30 mjl printjob(void) 146 1.1 cgd { 147 1.1 cgd struct stat stb; 148 1.16 mrg struct queue *q, **qp; 149 1.1 cgd struct queue **queue; 150 1.37 thorpej int i, nitems, fd; 151 1.15 mrg off_t pidoff; 152 1.15 mrg int errcnt, count = 0; 153 1.1 cgd 154 1.1 cgd init(); /* set up capabilities */ 155 1.37 thorpej (void)write(STDOUT_FILENO, "", 1); /* ack that daemon is started */ 156 1.37 thorpej 157 1.37 thorpej /* set up log file */ 158 1.37 thorpej if ((fd = open(LF, O_WRONLY|O_APPEND, 0664)) < 0) { 159 1.1 cgd syslog(LOG_ERR, "%s: %m", LF); 160 1.37 thorpej fd = open(_PATH_DEVNULL, O_WRONLY); 161 1.1 cgd } 162 1.37 thorpej if (fd > 0) { 163 1.37 thorpej (void) dup2(fd, STDERR_FILENO); 164 1.37 thorpej (void) close(fd); 165 1.37 thorpej } else 166 1.37 thorpej (void)close(STDERR_FILENO); 167 1.37 thorpej 168 1.1 cgd setgid(getegid()); 169 1.1 cgd pid = getpid(); /* for use with lprm */ 170 1.1 cgd setpgrp(0, pid); 171 1.1 cgd signal(SIGHUP, abortpr); 172 1.1 cgd signal(SIGINT, abortpr); 173 1.1 cgd signal(SIGQUIT, abortpr); 174 1.1 cgd signal(SIGTERM, abortpr); 175 1.1 cgd 176 1.1 cgd /* 177 1.1 cgd * uses short form file names 178 1.1 cgd */ 179 1.1 cgd if (chdir(SD) < 0) { 180 1.1 cgd syslog(LOG_ERR, "%s: %m", SD); 181 1.1 cgd exit(1); 182 1.1 cgd } 183 1.22 mrg if (stat(LO, &stb) == 0 && (stb.st_mode & S_IXUSR)) 184 1.1 cgd exit(0); /* printing disabled */ 185 1.1 cgd lfd = open(LO, O_WRONLY|O_CREAT, 0644); 186 1.1 cgd if (lfd < 0) { 187 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, LO); 188 1.1 cgd exit(1); 189 1.1 cgd } 190 1.1 cgd if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 191 1.31 wiz if (errno == EWOULDBLOCK) /* active daemon present */ 192 1.1 cgd exit(0); 193 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, LO); 194 1.1 cgd exit(1); 195 1.1 cgd } 196 1.1 cgd ftruncate(lfd, 0); 197 1.1 cgd /* 198 1.1 cgd * write process id for others to know 199 1.1 cgd */ 200 1.11 mrg pidoff = i = snprintf(line, sizeof(line), "%u\n", pid); 201 1.1 cgd if (write(lfd, line, i) != i) { 202 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, LO); 203 1.1 cgd exit(1); 204 1.1 cgd } 205 1.52 lukem 206 1.52 lukem /* 207 1.52 lukem * create the temp filenames. 208 1.52 lukem * XXX arguably we should keep the fds open and fdopen(3) dup()s, 209 1.52 lukem * XXX but we're in a protected directory so it shouldn't matter. 210 1.52 lukem */ 211 1.52 lukem if ((fd = mkstemp(tempfile)) != -1) { 212 1.52 lukem (void)close(fd); 213 1.52 lukem (void)unlink(tempfile); 214 1.52 lukem } 215 1.52 lukem if ((fd = mkstemp(tempremote)) != -1) { 216 1.52 lukem (void)close(fd); 217 1.52 lukem (void)unlink(tempremote); 218 1.52 lukem } 219 1.52 lukem 220 1.1 cgd /* 221 1.1 cgd * search the spool directory for work and sort by queue order. 222 1.1 cgd */ 223 1.1 cgd if ((nitems = getq(&queue)) < 0) { 224 1.1 cgd syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 225 1.1 cgd exit(1); 226 1.1 cgd } 227 1.1 cgd if (nitems == 0) /* no work to do */ 228 1.1 cgd exit(0); 229 1.22 mrg if (stb.st_mode & S_IXOTH) { /* reset queue flag */ 230 1.32 itojun stb.st_mode &= ~S_IXOTH; 231 1.32 itojun if (fchmod(lfd, stb.st_mode & 0777) < 0) 232 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, LO); 233 1.1 cgd } 234 1.1 cgd openpr(); /* open printer or remote */ 235 1.1 cgd again: 236 1.1 cgd /* 237 1.1 cgd * we found something to do now do it -- 238 1.1 cgd * write the name of the current control file into the lock file 239 1.1 cgd * so the spool queue program can tell what we're working on 240 1.1 cgd */ 241 1.1 cgd for (qp = queue; nitems--; free((char *) q)) { 242 1.1 cgd q = *qp++; 243 1.1 cgd if (stat(q->q_name, &stb) < 0) 244 1.1 cgd continue; 245 1.15 mrg errcnt = 0; 246 1.1 cgd restart: 247 1.15 mrg (void)lseek(lfd, pidoff, 0); 248 1.11 mrg i = snprintf(line, sizeof(line), "%s\n", q->q_name); 249 1.1 cgd if (write(lfd, line, i) != i) 250 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, LO); 251 1.1 cgd if (!remote) 252 1.1 cgd i = printit(q->q_name); 253 1.1 cgd else 254 1.1 cgd i = sendit(q->q_name); 255 1.1 cgd /* 256 1.1 cgd * Check to see if we are supposed to stop printing or 257 1.1 cgd * if we are to rebuild the queue. 258 1.1 cgd */ 259 1.1 cgd if (fstat(lfd, &stb) == 0) { 260 1.1 cgd /* stop printing before starting next job? */ 261 1.22 mrg if (stb.st_mode & S_IXUSR) 262 1.1 cgd goto done; 263 1.1 cgd /* rebuild queue (after lpc topq) */ 264 1.22 mrg if (stb.st_mode & S_IXOTH) { 265 1.1 cgd for (free((char *) q); nitems--; free((char *) q)) 266 1.1 cgd q = *qp++; 267 1.32 itojun stb.st_mode &= ~S_IXOTH; 268 1.32 itojun if (fchmod(lfd, stb.st_mode & 0777) < 0) 269 1.1 cgd syslog(LOG_WARNING, "%s: %s: %m", 270 1.1 cgd printer, LO); 271 1.1 cgd break; 272 1.1 cgd } 273 1.1 cgd } 274 1.1 cgd if (i == OK) /* file ok and printed */ 275 1.1 cgd count++; 276 1.15 mrg else if (i == REPRINT && ++errcnt < 5) { 277 1.15 mrg /* try reprinting the job */ 278 1.1 cgd syslog(LOG_INFO, "restarting %s", printer); 279 1.35 abs if (ofilter > 0) 280 1.35 abs close_ofilter(); 281 1.11 mrg (void)close(pfd); /* close printer */ 282 1.1 cgd if (ftruncate(lfd, pidoff) < 0) 283 1.1 cgd syslog(LOG_WARNING, "%s: %s: %m", printer, LO); 284 1.1 cgd openpr(); /* try to reopen printer */ 285 1.1 cgd goto restart; 286 1.15 mrg } else { 287 1.15 mrg syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, 288 1.15 mrg remote ? "sent to remote host" : "printed", q->q_name); 289 1.15 mrg if (i == REPRINT) { 290 1.22 mrg /* ensure we don't attempt this job again */ 291 1.15 mrg (void) unlink(q->q_name); 292 1.15 mrg q->q_name[0] = 'd'; 293 1.15 mrg (void) unlink(q->q_name); 294 1.15 mrg if (logname[0]) 295 1.15 mrg sendmail(logname, FATALERR); 296 1.15 mrg } 297 1.1 cgd } 298 1.1 cgd } 299 1.49 christos free(queue); 300 1.49 christos queue = NULL; 301 1.1 cgd /* 302 1.1 cgd * search the spool directory for more work. 303 1.1 cgd */ 304 1.1 cgd if ((nitems = getq(&queue)) < 0) { 305 1.1 cgd syslog(LOG_ERR, "%s: can't scan %s", printer, SD); 306 1.1 cgd exit(1); 307 1.1 cgd } 308 1.1 cgd if (nitems == 0) { /* no more work to do */ 309 1.1 cgd done: 310 1.1 cgd if (count > 0) { /* Files actually printed */ 311 1.1 cgd if (!SF && !tof) 312 1.11 mrg (void)write(ofd, FF, strlen(FF)); 313 1.1 cgd if (TR != NULL) /* output trailer */ 314 1.11 mrg (void)write(ofd, TR, strlen(TR)); 315 1.1 cgd } 316 1.11 mrg (void)unlink(tempfile); 317 1.35 abs (void)unlink(tempremote); 318 1.1 cgd exit(0); 319 1.1 cgd } 320 1.1 cgd goto again; 321 1.1 cgd } 322 1.1 cgd 323 1.11 mrg #define FONTLEN 50 324 1.11 mrg char fonts[4][FONTLEN]; /* fonts for troff */ 325 1.1 cgd 326 1.1 cgd char ifonts[4][40] = { 327 1.1 cgd _PATH_VFONTR, 328 1.1 cgd _PATH_VFONTI, 329 1.1 cgd _PATH_VFONTB, 330 1.1 cgd _PATH_VFONTS, 331 1.1 cgd }; 332 1.1 cgd 333 1.1 cgd /* 334 1.1 cgd * The remaining part is the reading of the control file (cf) 335 1.1 cgd * and performing the various actions. 336 1.1 cgd */ 337 1.5 cgd static int 338 1.30 mjl printit(char *file) 339 1.1 cgd { 340 1.16 mrg int i; 341 1.1 cgd char *cp; 342 1.1 cgd int bombed = OK; 343 1.1 cgd 344 1.1 cgd /* 345 1.1 cgd * open control file; ignore if no longer there. 346 1.1 cgd */ 347 1.1 cgd if ((cfp = fopen(file, "r")) == NULL) { 348 1.1 cgd syslog(LOG_INFO, "%s: %s: %m", printer, file); 349 1.1 cgd return(OK); 350 1.1 cgd } 351 1.1 cgd /* 352 1.1 cgd * Reset troff fonts. 353 1.1 cgd */ 354 1.1 cgd for (i = 0; i < 4; i++) 355 1.38 itojun strlcpy(fonts[i], ifonts[i], sizeof(fonts[i])); 356 1.13 mikel (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW); 357 1.11 mrg indent[2] = '0'; 358 1.11 mrg indent[3] = '\0'; 359 1.1 cgd 360 1.1 cgd /* 361 1.1 cgd * read the control file for work to do 362 1.1 cgd * 363 1.1 cgd * file format -- first character in the line is a command 364 1.1 cgd * rest of the line is the argument. 365 1.1 cgd * valid commands are: 366 1.1 cgd * 367 1.1 cgd * S -- "stat info" for symbolic link protection 368 1.1 cgd * J -- "job name" on banner page 369 1.1 cgd * C -- "class name" on banner page 370 1.1 cgd * L -- "literal" user's name to print on banner 371 1.1 cgd * T -- "title" for pr 372 1.1 cgd * H -- "host name" of machine where lpr was done 373 1.1 cgd * P -- "person" user's login name 374 1.1 cgd * I -- "indent" amount to indent output 375 1.15 mrg * R -- laser dpi "resolution" 376 1.1 cgd * f -- "file name" name of text file to print 377 1.1 cgd * l -- "file name" text file with control chars 378 1.1 cgd * p -- "file name" text file to print with pr(1) 379 1.1 cgd * t -- "file name" troff(1) file to print 380 1.1 cgd * n -- "file name" ditroff(1) file to print 381 1.1 cgd * d -- "file name" dvi file to print 382 1.1 cgd * g -- "file name" plot(1G) file to print 383 1.1 cgd * v -- "file name" plain raster file to print 384 1.1 cgd * c -- "file name" cifplot file to print 385 1.46 garbled * o -- "file name" postscript file to print 386 1.1 cgd * 1 -- "R font file" for troff 387 1.1 cgd * 2 -- "I font file" for troff 388 1.1 cgd * 3 -- "B font file" for troff 389 1.1 cgd * 4 -- "S font file" for troff 390 1.1 cgd * N -- "name" of file (used by lpq) 391 1.1 cgd * U -- "unlink" name of file to remove 392 1.1 cgd * (after we print it. (Pass 2 only)). 393 1.1 cgd * M -- "mail" to user when done printing 394 1.1 cgd * 395 1.55 roy * get_line reads a line and expands tabs to blanks 396 1.1 cgd */ 397 1.1 cgd 398 1.1 cgd /* pass 1 */ 399 1.1 cgd 400 1.55 roy while (get_line(cfp)) 401 1.1 cgd switch (line[0]) { 402 1.1 cgd case 'H': 403 1.38 itojun strlcpy(fromhost, line+1, sizeof(fromhost)); 404 1.1 cgd if (class[0] == '\0') 405 1.38 itojun strlcpy(class, line+1, sizeof(class)); 406 1.1 cgd continue; 407 1.1 cgd 408 1.1 cgd case 'P': 409 1.38 itojun strlcpy(logname, line+1, sizeof(logname)); 410 1.1 cgd if (RS) { /* restricted */ 411 1.5 cgd if (getpwnam(logname) == NULL) { 412 1.1 cgd bombed = NOACCT; 413 1.1 cgd sendmail(line+1, bombed); 414 1.1 cgd goto pass2; 415 1.1 cgd } 416 1.1 cgd } 417 1.1 cgd continue; 418 1.1 cgd 419 1.1 cgd case 'S': 420 1.1 cgd cp = line+1; 421 1.1 cgd i = 0; 422 1.1 cgd while (*cp >= '0' && *cp <= '9') 423 1.1 cgd i = i * 10 + (*cp++ - '0'); 424 1.1 cgd fdev = i; 425 1.1 cgd cp++; 426 1.1 cgd i = 0; 427 1.1 cgd while (*cp >= '0' && *cp <= '9') 428 1.1 cgd i = i * 10 + (*cp++ - '0'); 429 1.1 cgd fino = i; 430 1.1 cgd continue; 431 1.1 cgd 432 1.1 cgd case 'J': 433 1.38 itojun if (line[1] != '\0') 434 1.38 itojun strlcpy(jobname, line+1, sizeof(jobname)); 435 1.38 itojun else { 436 1.11 mrg jobname[0] = ' '; 437 1.11 mrg jobname[1] = '\0'; 438 1.11 mrg } 439 1.1 cgd continue; 440 1.1 cgd 441 1.1 cgd case 'C': 442 1.38 itojun if (line[1] != '\0') 443 1.38 itojun strlcpy(class, line+1, sizeof(class)); 444 1.38 itojun else if (class[0] == '\0') { 445 1.1 cgd gethostname(class, sizeof(class)); 446 1.19 mrg class[sizeof(class) - 1] = '\0'; 447 1.19 mrg } 448 1.1 cgd continue; 449 1.1 cgd 450 1.1 cgd case 'T': /* header title for pr */ 451 1.38 itojun strlcpy(title, line+1, sizeof(title)); 452 1.1 cgd continue; 453 1.1 cgd 454 1.1 cgd case 'L': /* identification line */ 455 1.1 cgd if (!SH && !HL) 456 1.1 cgd banner(line+1, jobname); 457 1.1 cgd continue; 458 1.1 cgd 459 1.1 cgd case '1': /* troff fonts */ 460 1.1 cgd case '2': 461 1.1 cgd case '3': 462 1.1 cgd case '4': 463 1.16 mrg if (line[1] != '\0') { 464 1.38 itojun strlcpy(fonts[line[0]-'1'], line+1, 465 1.38 itojun sizeof(fonts[line[0]-'1'])); 466 1.16 mrg } 467 1.1 cgd continue; 468 1.1 cgd 469 1.1 cgd case 'W': /* page width */ 470 1.38 itojun strlcpy(width+2, line+1, sizeof(width) - 2); 471 1.1 cgd continue; 472 1.1 cgd 473 1.1 cgd case 'I': /* indent amount */ 474 1.38 itojun strlcpy(indent+2, line+1, sizeof(indent) - 2); 475 1.1 cgd continue; 476 1.1 cgd 477 1.1 cgd default: /* some file to print */ 478 1.1 cgd switch (i = print(line[0], line+1)) { 479 1.1 cgd case ERROR: 480 1.1 cgd if (bombed == OK) 481 1.1 cgd bombed = FATALERR; 482 1.1 cgd break; 483 1.1 cgd case REPRINT: 484 1.11 mrg (void)fclose(cfp); 485 1.1 cgd return(REPRINT); 486 1.1 cgd case FILTERERR: 487 1.1 cgd case ACCESS: 488 1.1 cgd bombed = i; 489 1.1 cgd sendmail(logname, bombed); 490 1.1 cgd } 491 1.1 cgd title[0] = '\0'; 492 1.1 cgd continue; 493 1.1 cgd 494 1.1 cgd case 'N': 495 1.1 cgd case 'U': 496 1.1 cgd case 'M': 497 1.15 mrg case 'R': 498 1.1 cgd continue; 499 1.1 cgd } 500 1.1 cgd 501 1.1 cgd /* pass 2 */ 502 1.1 cgd 503 1.1 cgd pass2: 504 1.1 cgd fseek(cfp, 0L, 0); 505 1.55 roy while (get_line(cfp)) 506 1.1 cgd switch (line[0]) { 507 1.1 cgd case 'L': /* identification line */ 508 1.1 cgd if (!SH && HL) 509 1.1 cgd banner(line+1, jobname); 510 1.1 cgd continue; 511 1.1 cgd 512 1.1 cgd case 'M': 513 1.1 cgd if (bombed < NOACCT) /* already sent if >= NOACCT */ 514 1.1 cgd sendmail(line+1, bombed); 515 1.1 cgd continue; 516 1.1 cgd 517 1.1 cgd case 'U': 518 1.16 mrg if (strchr(line+1, '/')) 519 1.16 mrg continue; 520 1.11 mrg (void)unlink(line+1); 521 1.1 cgd } 522 1.1 cgd /* 523 1.1 cgd * clean-up in case another control file exists 524 1.1 cgd */ 525 1.11 mrg (void)fclose(cfp); 526 1.11 mrg (void)unlink(file); 527 1.1 cgd return(bombed == OK ? OK : ERROR); 528 1.1 cgd } 529 1.1 cgd 530 1.1 cgd /* 531 1.1 cgd * Print a file. 532 1.1 cgd * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}. 533 1.28 wiz * Return -1 if a non-recoverable error occurred, 534 1.1 cgd * 2 if the filter detected some errors (but printed the job anyway), 535 1.1 cgd * 1 if we should try to reprint this job and 536 1.1 cgd * 0 if all is well. 537 1.1 cgd * Note: all filters take stdin as the file, stdout as the printer, 538 1.1 cgd * stderr as the log file, and must not ignore SIGINT. 539 1.1 cgd */ 540 1.5 cgd static int 541 1.30 mjl print(int format, char *file) 542 1.1 cgd { 543 1.1 cgd FILE *fp; 544 1.16 mrg int status; 545 1.1 cgd struct stat stb; 546 1.53 christos const char *prog, *av[17]; 547 1.43 christos char buf[BUFSIZ]; 548 1.43 christos int n, fi, fo, child_pid, p[2], stopped = 0, nofile; 549 1.1 cgd 550 1.1 cgd if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) 551 1.1 cgd return(ERROR); 552 1.1 cgd /* 553 1.1 cgd * Check to see if data file is a symbolic link. If so, it should 554 1.1 cgd * still point to the same file or someone is trying to print 555 1.1 cgd * something he shouldn't. 556 1.1 cgd */ 557 1.18 mycroft if (S_ISLNK(stb.st_mode) && fstat(fi, &stb) == 0 && 558 1.1 cgd (stb.st_dev != fdev || stb.st_ino != fino)) 559 1.1 cgd return(ACCESS); 560 1.1 cgd if (!SF && !tof) { /* start on a fresh page */ 561 1.11 mrg (void)write(ofd, FF, strlen(FF)); 562 1.1 cgd tof = 1; 563 1.1 cgd } 564 1.1 cgd if (IF == NULL && (format == 'f' || format == 'l')) { 565 1.1 cgd tof = 0; 566 1.1 cgd while ((n = read(fi, buf, BUFSIZ)) > 0) 567 1.1 cgd if (write(ofd, buf, n) != n) { 568 1.11 mrg (void)close(fi); 569 1.1 cgd return(REPRINT); 570 1.1 cgd } 571 1.11 mrg (void)close(fi); 572 1.1 cgd return(OK); 573 1.1 cgd } 574 1.1 cgd switch (format) { 575 1.1 cgd case 'p': /* print file using 'pr' */ 576 1.1 cgd if (IF == NULL) { /* use output filter */ 577 1.1 cgd prog = _PATH_PR; 578 1.1 cgd av[0] = "pr"; 579 1.1 cgd av[1] = width; 580 1.1 cgd av[2] = length; 581 1.1 cgd av[3] = "-h"; 582 1.1 cgd av[4] = *title ? title : " "; 583 1.1 cgd av[5] = 0; 584 1.1 cgd fo = ofd; 585 1.1 cgd goto start; 586 1.1 cgd } 587 1.1 cgd pipe(p); 588 1.1 cgd if ((prchild = dofork(DORETURN)) == 0) { /* child */ 589 1.1 cgd dup2(fi, 0); /* file is stdin */ 590 1.1 cgd dup2(p[1], 1); /* pipe is stdout */ 591 1.15 mrg closelog(); 592 1.16 mrg nofile = sysconf(_SC_OPEN_MAX); 593 1.16 mrg for (n = 3; n < nofile; n++) 594 1.11 mrg (void)close(n); 595 1.1 cgd execl(_PATH_PR, "pr", width, length, 596 1.50 mrg "-h", *title ? title : " ", NULL); 597 1.1 cgd syslog(LOG_ERR, "cannot execl %s", _PATH_PR); 598 1.1 cgd exit(2); 599 1.1 cgd } 600 1.11 mrg (void)close(p[1]); /* close output side */ 601 1.11 mrg (void)close(fi); 602 1.1 cgd if (prchild < 0) { 603 1.1 cgd prchild = 0; 604 1.11 mrg (void)close(p[0]); 605 1.1 cgd return(ERROR); 606 1.1 cgd } 607 1.1 cgd fi = p[0]; /* use pipe for input */ 608 1.57 mrg /* FALLTHROUGH */ 609 1.1 cgd case 'f': /* print plain text file */ 610 1.1 cgd prog = IF; 611 1.1 cgd av[1] = width; 612 1.1 cgd av[2] = length; 613 1.1 cgd av[3] = indent; 614 1.1 cgd n = 4; 615 1.1 cgd break; 616 1.45 garbled case 'o': /* print a postscript file */ 617 1.45 garbled if (PF == NULL) { 618 1.45 garbled /* if PF is not set, handle it like an 'l' */ 619 1.45 garbled prog = IF; 620 1.45 garbled av[1] = "-c"; 621 1.45 garbled av[2] = width; 622 1.45 garbled av[3] = length; 623 1.45 garbled av[4] = indent; 624 1.45 garbled n = 5; 625 1.45 garbled break; 626 1.45 garbled } else { 627 1.45 garbled prog = PF; 628 1.45 garbled av[1] = pxwidth; 629 1.45 garbled av[2] = pxlength; 630 1.45 garbled n = 3; 631 1.45 garbled break; 632 1.45 garbled } 633 1.1 cgd case 'l': /* like 'f' but pass control characters */ 634 1.1 cgd prog = IF; 635 1.1 cgd av[1] = "-c"; 636 1.1 cgd av[2] = width; 637 1.1 cgd av[3] = length; 638 1.1 cgd av[4] = indent; 639 1.1 cgd n = 5; 640 1.1 cgd break; 641 1.1 cgd case 'r': /* print a fortran text file */ 642 1.1 cgd prog = RF; 643 1.1 cgd av[1] = width; 644 1.1 cgd av[2] = length; 645 1.1 cgd n = 3; 646 1.1 cgd break; 647 1.1 cgd case 't': /* print troff output */ 648 1.1 cgd case 'n': /* print ditroff output */ 649 1.1 cgd case 'd': /* print tex output */ 650 1.11 mrg (void)unlink(".railmag"); 651 1.1 cgd if ((fo = creat(".railmag", FILMOD)) < 0) { 652 1.1 cgd syslog(LOG_ERR, "%s: cannot create .railmag", printer); 653 1.11 mrg (void)unlink(".railmag"); 654 1.1 cgd } else { 655 1.1 cgd for (n = 0; n < 4; n++) { 656 1.1 cgd if (fonts[n][0] != '/') 657 1.11 mrg (void)write(fo, _PATH_VFONT, 658 1.5 cgd sizeof(_PATH_VFONT) - 1); 659 1.11 mrg (void)write(fo, fonts[n], strlen(fonts[n])); 660 1.11 mrg (void)write(fo, "\n", 1); 661 1.1 cgd } 662 1.11 mrg (void)close(fo); 663 1.1 cgd } 664 1.1 cgd prog = (format == 't') ? TF : (format == 'n') ? NF : DF; 665 1.1 cgd av[1] = pxwidth; 666 1.1 cgd av[2] = pxlength; 667 1.1 cgd n = 3; 668 1.1 cgd break; 669 1.1 cgd case 'c': /* print cifplot output */ 670 1.1 cgd prog = CF; 671 1.1 cgd av[1] = pxwidth; 672 1.1 cgd av[2] = pxlength; 673 1.1 cgd n = 3; 674 1.1 cgd break; 675 1.1 cgd case 'g': /* print plot(1G) output */ 676 1.1 cgd prog = GF; 677 1.1 cgd av[1] = pxwidth; 678 1.1 cgd av[2] = pxlength; 679 1.1 cgd n = 3; 680 1.1 cgd break; 681 1.1 cgd case 'v': /* print raster output */ 682 1.1 cgd prog = VF; 683 1.1 cgd av[1] = pxwidth; 684 1.1 cgd av[2] = pxlength; 685 1.1 cgd n = 3; 686 1.1 cgd break; 687 1.1 cgd default: 688 1.11 mrg (void)close(fi); 689 1.1 cgd syslog(LOG_ERR, "%s: illegal format character '%c'", 690 1.1 cgd printer, format); 691 1.1 cgd return(ERROR); 692 1.1 cgd } 693 1.15 mrg if (prog == NULL) { 694 1.16 mrg (void)close(fi); 695 1.15 mrg syslog(LOG_ERR, 696 1.16 mrg "%s: no filter found in printcap for format character '%c'", 697 1.16 mrg printer, format); 698 1.16 mrg return (ERROR); 699 1.15 mrg } 700 1.16 mrg if ((av[0] = strrchr(prog, '/')) != NULL) 701 1.1 cgd av[0]++; 702 1.1 cgd else 703 1.1 cgd av[0] = prog; 704 1.1 cgd av[n++] = "-n"; 705 1.1 cgd av[n++] = logname; 706 1.53 christos if (*jobname != '\0' && strcmp(jobname, " ") != 0) { 707 1.53 christos av[n++] = "-j"; 708 1.53 christos av[n++] = jobname; 709 1.53 christos } 710 1.1 cgd av[n++] = "-h"; 711 1.1 cgd av[n++] = fromhost; 712 1.1 cgd av[n++] = AF; 713 1.1 cgd av[n] = 0; 714 1.1 cgd fo = pfd; 715 1.1 cgd if (ofilter > 0) { /* stop output filter */ 716 1.1 cgd write(ofd, "\031\1", 2); 717 1.43 christos while ((child_pid = 718 1.43 christos wait3(&status, WUNTRACED, 0)) > 0 && child_pid != ofilter) 719 1.1 cgd ; 720 1.16 mrg if (WIFSTOPPED(status) == 0) { 721 1.11 mrg (void)close(fi); 722 1.15 mrg syslog(LOG_WARNING, 723 1.16 mrg "%s: output filter died (retcode=%d termsig=%d)", 724 1.16 mrg printer, WEXITSTATUS(status), WTERMSIG(status)); 725 1.1 cgd return(REPRINT); 726 1.1 cgd } 727 1.1 cgd stopped++; 728 1.1 cgd } 729 1.1 cgd start: 730 1.1 cgd if ((child = dofork(DORETURN)) == 0) { /* child */ 731 1.1 cgd dup2(fi, 0); 732 1.1 cgd dup2(fo, 1); 733 1.12 lukem unlink(tempfile); 734 1.12 lukem n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664); 735 1.1 cgd if (n >= 0) 736 1.1 cgd dup2(n, 2); 737 1.15 mrg closelog(); 738 1.16 mrg nofile = sysconf(_SC_OPEN_MAX); 739 1.16 mrg for (n = 3; n < nofile; n++) 740 1.11 mrg (void)close(n); 741 1.43 christos execv(prog, __UNCONST(av)); 742 1.1 cgd syslog(LOG_ERR, "cannot execv %s", prog); 743 1.1 cgd exit(2); 744 1.1 cgd } 745 1.16 mrg if (child < 0) { 746 1.16 mrg child = 0; 747 1.16 mrg prchild = 0; 748 1.16 mrg tof = 0; 749 1.16 mrg syslog(LOG_ERR, "cannot start child process: %m"); 750 1.16 mrg return (ERROR); 751 1.16 mrg } 752 1.11 mrg (void)close(fi); 753 1.43 christos while ((child_pid = wait(&status)) > 0 && child_pid != child) 754 1.16 mrg ; 755 1.1 cgd child = 0; 756 1.1 cgd prchild = 0; 757 1.1 cgd if (stopped) { /* restart output filter */ 758 1.1 cgd if (kill(ofilter, SIGCONT) < 0) { 759 1.1 cgd syslog(LOG_ERR, "cannot restart output filter"); 760 1.1 cgd exit(1); 761 1.1 cgd } 762 1.1 cgd } 763 1.1 cgd tof = 0; 764 1.1 cgd 765 1.1 cgd /* Copy filter output to "lf" logfile */ 766 1.13 mikel if ((fp = fopen(tempfile, "r")) != NULL) { 767 1.1 cgd while (fgets(buf, sizeof(buf), fp)) 768 1.1 cgd fputs(buf, stderr); 769 1.5 cgd fclose(fp); 770 1.1 cgd } 771 1.1 cgd 772 1.1 cgd if (!WIFEXITED(status)) { 773 1.16 mrg syslog(LOG_WARNING, 774 1.35 abs "%s: Daemon filter '%c' terminated (pid=%d) (termsig=%d)", 775 1.43 christos printer, format, (int)child_pid, WTERMSIG(status)); 776 1.1 cgd return(ERROR); 777 1.1 cgd } 778 1.16 mrg switch (WEXITSTATUS(status)) { 779 1.1 cgd case 0: 780 1.1 cgd tof = 1; 781 1.1 cgd return(OK); 782 1.1 cgd case 1: 783 1.1 cgd return(REPRINT); 784 1.15 mrg case 2: 785 1.15 mrg return(ERROR); 786 1.1 cgd default: 787 1.15 mrg syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", 788 1.16 mrg printer, format, WEXITSTATUS(status)); 789 1.15 mrg return(FILTERERR); 790 1.1 cgd } 791 1.1 cgd } 792 1.1 cgd 793 1.1 cgd /* 794 1.1 cgd * Send the daemon control file (cf) and any data files. 795 1.28 wiz * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and 796 1.1 cgd * 0 if all is well. 797 1.1 cgd */ 798 1.5 cgd static int 799 1.30 mjl sendit(char *file) 800 1.1 cgd { 801 1.16 mrg int i, err = OK; 802 1.1 cgd char *cp, last[BUFSIZ]; 803 1.1 cgd 804 1.1 cgd /* 805 1.1 cgd * open control file 806 1.1 cgd */ 807 1.1 cgd if ((cfp = fopen(file, "r")) == NULL) 808 1.1 cgd return(OK); 809 1.1 cgd /* 810 1.1 cgd * read the control file for work to do 811 1.1 cgd * 812 1.1 cgd * file format -- first character in the line is a command 813 1.1 cgd * rest of the line is the argument. 814 1.1 cgd * commands of interest are: 815 1.1 cgd * 816 1.1 cgd * a-z -- "file name" name of file to print 817 1.1 cgd * U -- "unlink" name of file to remove 818 1.1 cgd * (after we print it. (Pass 2 only)). 819 1.1 cgd */ 820 1.1 cgd 821 1.1 cgd /* 822 1.1 cgd * pass 1 823 1.1 cgd */ 824 1.55 roy while (get_line(cfp)) { 825 1.1 cgd again: 826 1.1 cgd if (line[0] == 'S') { 827 1.1 cgd cp = line+1; 828 1.1 cgd i = 0; 829 1.1 cgd while (*cp >= '0' && *cp <= '9') 830 1.1 cgd i = i * 10 + (*cp++ - '0'); 831 1.1 cgd fdev = i; 832 1.1 cgd cp++; 833 1.1 cgd i = 0; 834 1.1 cgd while (*cp >= '0' && *cp <= '9') 835 1.1 cgd i = i * 10 + (*cp++ - '0'); 836 1.1 cgd fino = i; 837 1.1 cgd continue; 838 1.1 cgd } 839 1.1 cgd if (line[0] >= 'a' && line[0] <= 'z') { 840 1.38 itojun strlcpy(last, line, sizeof(last)); 841 1.55 roy while ((i = get_line(cfp)) != 0) 842 1.1 cgd if (strcmp(last, line)) 843 1.1 cgd break; 844 1.1 cgd switch (sendfile('\3', last+1)) { 845 1.1 cgd case OK: 846 1.1 cgd if (i) 847 1.1 cgd goto again; 848 1.1 cgd break; 849 1.1 cgd case REPRINT: 850 1.11 mrg (void)fclose(cfp); 851 1.1 cgd return(REPRINT); 852 1.1 cgd case ACCESS: 853 1.1 cgd sendmail(logname, ACCESS); 854 1.57 mrg /* FALLTHROUGH */ 855 1.1 cgd case ERROR: 856 1.1 cgd err = ERROR; 857 1.1 cgd } 858 1.1 cgd break; 859 1.1 cgd } 860 1.1 cgd } 861 1.1 cgd if (err == OK && sendfile('\2', file) > 0) { 862 1.11 mrg (void)fclose(cfp); 863 1.1 cgd return(REPRINT); 864 1.1 cgd } 865 1.1 cgd /* 866 1.1 cgd * pass 2 867 1.1 cgd */ 868 1.1 cgd fseek(cfp, 0L, 0); 869 1.55 roy while (get_line(cfp)) 870 1.16 mrg if (line[0] == 'U' && strchr(line+1, '/') == 0) 871 1.11 mrg (void)unlink(line+1); 872 1.1 cgd /* 873 1.1 cgd * clean-up in case another control file exists 874 1.1 cgd */ 875 1.11 mrg (void)fclose(cfp); 876 1.11 mrg (void)unlink(file); 877 1.1 cgd return(err); 878 1.1 cgd } 879 1.1 cgd 880 1.1 cgd /* 881 1.1 cgd * Send a data file to the remote machine and spool it. 882 1.1 cgd * Return positive if we should try resending. 883 1.1 cgd */ 884 1.5 cgd static int 885 1.30 mjl sendfile(int type, char *file) 886 1.1 cgd { 887 1.16 mrg int f, i, amt; 888 1.1 cgd struct stat stb; 889 1.1 cgd char buf[BUFSIZ]; 890 1.1 cgd int sizerr, resp; 891 1.35 abs extern int rflag; 892 1.47 garbled char *save_file; 893 1.35 abs 894 1.47 garbled save_file = file; 895 1.35 abs if (type == '\3' && rflag && (OF || IF)) { 896 1.35 abs int save_pfd = pfd; 897 1.35 abs 898 1.35 abs (void)unlink(tempremote); 899 1.35 abs pfd = open(tempremote, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664); 900 1.35 abs if (pfd == -1) { 901 1.35 abs pfd = save_pfd; 902 1.35 abs return ERROR; 903 1.35 abs } 904 1.35 abs setup_ofilter(1); 905 1.35 abs switch (i = print('f', file)) { 906 1.35 abs case ERROR: 907 1.35 abs case REPRINT: 908 1.35 abs case FILTERERR: 909 1.35 abs case ACCESS: 910 1.35 abs return(i); 911 1.35 abs } 912 1.35 abs close_ofilter(); 913 1.35 abs pfd = save_pfd; 914 1.35 abs file = tempremote; 915 1.35 abs } 916 1.1 cgd 917 1.1 cgd if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) 918 1.1 cgd return(ERROR); 919 1.1 cgd /* 920 1.1 cgd * Check to see if data file is a symbolic link. If so, it should 921 1.1 cgd * still point to the same file or someone is trying to print something 922 1.1 cgd * he shouldn't. 923 1.1 cgd */ 924 1.18 mycroft if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 && 925 1.1 cgd (stb.st_dev != fdev || stb.st_ino != fino)) 926 1.1 cgd return(ACCESS); 927 1.35 abs 928 1.26 lukem amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type, 929 1.47 garbled (long long)stb.st_size, save_file); 930 1.21 mrg for (i = 0; ; i++) { 931 1.1 cgd if (write(pfd, buf, amt) != amt || 932 1.1 cgd (resp = response()) < 0 || resp == '\1') { 933 1.11 mrg (void)close(f); 934 1.1 cgd return(REPRINT); 935 1.1 cgd } else if (resp == '\0') 936 1.1 cgd break; 937 1.1 cgd if (i == 0) 938 1.5 cgd pstatus("no space on remote; waiting for queue to drain"); 939 1.1 cgd if (i == 10) 940 1.1 cgd syslog(LOG_ALERT, "%s: can't send to %s; queue full", 941 1.1 cgd printer, RM); 942 1.1 cgd sleep(5 * 60); 943 1.1 cgd } 944 1.1 cgd if (i) 945 1.5 cgd pstatus("sending to %s", RM); 946 1.1 cgd sizerr = 0; 947 1.1 cgd for (i = 0; i < stb.st_size; i += BUFSIZ) { 948 1.21 mrg struct sigaction osa, nsa; 949 1.21 mrg 950 1.1 cgd amt = BUFSIZ; 951 1.1 cgd if (i + amt > stb.st_size) 952 1.1 cgd amt = stb.st_size - i; 953 1.1 cgd if (sizerr == 0 && read(f, buf, amt) != amt) 954 1.1 cgd sizerr = 1; 955 1.21 mrg nsa.sa_handler = alarmer; 956 1.21 mrg sigemptyset(&nsa.sa_mask); 957 1.21 mrg sigaddset(&nsa.sa_mask, SIGALRM); 958 1.21 mrg nsa.sa_flags = 0; 959 1.21 mrg (void)sigaction(SIGALRM, &nsa, &osa); 960 1.21 mrg alarm(wait_time); 961 1.1 cgd if (write(pfd, buf, amt) != amt) { 962 1.21 mrg alarm(0); 963 1.21 mrg (void)sigaction(SIGALRM, &osa, NULL); 964 1.11 mrg (void)close(f); 965 1.1 cgd return(REPRINT); 966 1.1 cgd } 967 1.21 mrg alarm(0); 968 1.21 mrg (void)sigaction(SIGALRM, &osa, NULL); 969 1.1 cgd } 970 1.5 cgd 971 1.11 mrg (void)close(f); 972 1.1 cgd if (sizerr) { 973 1.1 cgd syslog(LOG_INFO, "%s: %s: changed size", printer, file); 974 1.1 cgd /* tell recvjob to ignore this file */ 975 1.11 mrg (void)write(pfd, "\1", 1); 976 1.1 cgd return(ERROR); 977 1.1 cgd } 978 1.1 cgd if (write(pfd, "", 1) != 1 || response()) 979 1.1 cgd return(REPRINT); 980 1.1 cgd return(OK); 981 1.1 cgd } 982 1.1 cgd 983 1.1 cgd /* 984 1.1 cgd * Check to make sure there have been no errors and that both programs 985 1.1 cgd * are in sync with eachother. 986 1.1 cgd * Return non-zero if the connection was lost. 987 1.1 cgd */ 988 1.5 cgd static char 989 1.30 mjl response(void) 990 1.1 cgd { 991 1.21 mrg struct sigaction osa, nsa; 992 1.1 cgd char resp; 993 1.1 cgd 994 1.21 mrg nsa.sa_handler = alarmer; 995 1.21 mrg sigemptyset(&nsa.sa_mask); 996 1.21 mrg sigaddset(&nsa.sa_mask, SIGALRM); 997 1.21 mrg nsa.sa_flags = 0; 998 1.21 mrg (void)sigaction(SIGALRM, &nsa, &osa); 999 1.21 mrg alarm(wait_time); 1000 1.1 cgd if (read(pfd, &resp, 1) != 1) { 1001 1.1 cgd syslog(LOG_INFO, "%s: lost connection", printer); 1002 1.21 mrg resp = -1; 1003 1.1 cgd } 1004 1.21 mrg alarm(0); 1005 1.21 mrg (void)sigaction(SIGALRM, &osa, NULL); 1006 1.21 mrg return (resp); 1007 1.1 cgd } 1008 1.1 cgd 1009 1.1 cgd /* 1010 1.1 cgd * Banner printing stuff 1011 1.1 cgd */ 1012 1.5 cgd static void 1013 1.30 mjl banner(char *name1, char *name2) 1014 1.1 cgd { 1015 1.1 cgd time_t tvec; 1016 1.1 cgd 1017 1.1 cgd time(&tvec); 1018 1.1 cgd if (!SF && !tof) 1019 1.11 mrg (void)write(ofd, FF, strlen(FF)); 1020 1.1 cgd if (SB) { /* short banner only */ 1021 1.1 cgd if (class[0]) { 1022 1.11 mrg (void)write(ofd, class, strlen(class)); 1023 1.11 mrg (void)write(ofd, ":", 1); 1024 1.1 cgd } 1025 1.11 mrg (void)write(ofd, name1, strlen(name1)); 1026 1.11 mrg (void)write(ofd, " Job: ", 7); 1027 1.11 mrg (void)write(ofd, name2, strlen(name2)); 1028 1.11 mrg (void)write(ofd, " Date: ", 8); 1029 1.11 mrg (void)write(ofd, ctime(&tvec), 24); 1030 1.11 mrg (void)write(ofd, "\n", 1); 1031 1.1 cgd } else { /* normal banner */ 1032 1.11 mrg (void)write(ofd, "\n\n\n", 3); 1033 1.1 cgd scan_out(ofd, name1, '\0'); 1034 1.11 mrg (void)write(ofd, "\n\n", 2); 1035 1.1 cgd scan_out(ofd, name2, '\0'); 1036 1.1 cgd if (class[0]) { 1037 1.11 mrg (void)write(ofd,"\n\n\n",3); 1038 1.1 cgd scan_out(ofd, class, '\0'); 1039 1.1 cgd } 1040 1.11 mrg (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15); 1041 1.11 mrg (void)write(ofd, name2, strlen(name2)); 1042 1.11 mrg (void)write(ofd, "\n\t\t\t\t\tDate: ", 12); 1043 1.11 mrg (void)write(ofd, ctime(&tvec), 24); 1044 1.11 mrg (void)write(ofd, "\n", 1); 1045 1.1 cgd } 1046 1.1 cgd if (!SF) 1047 1.11 mrg (void)write(ofd, FF, strlen(FF)); 1048 1.1 cgd tof = 1; 1049 1.1 cgd } 1050 1.1 cgd 1051 1.5 cgd static char * 1052 1.34 wiz scnline(int key, char *p, int c) 1053 1.1 cgd { 1054 1.16 mrg int scnwidth; 1055 1.1 cgd 1056 1.1 cgd for (scnwidth = WIDTH; --scnwidth;) { 1057 1.1 cgd key <<= 1; 1058 1.1 cgd *p++ = key & 0200 ? c : BACKGND; 1059 1.1 cgd } 1060 1.1 cgd return (p); 1061 1.1 cgd } 1062 1.1 cgd 1063 1.1 cgd #define TRC(q) (((q)-' ')&0177) 1064 1.1 cgd 1065 1.5 cgd static void 1066 1.30 mjl scan_out(int scfd, char *scsp, int dlm) 1067 1.1 cgd { 1068 1.16 mrg char *strp; 1069 1.16 mrg int nchrs, j; 1070 1.1 cgd char outbuf[LINELEN+1], *sp, c, cc; 1071 1.1 cgd int d, scnhgt; 1072 1.51 matt extern const char scnkey[][HEIGHT]; /* in lpdchar.c */ 1073 1.1 cgd 1074 1.1 cgd for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) { 1075 1.1 cgd strp = &outbuf[0]; 1076 1.1 cgd sp = scsp; 1077 1.1 cgd for (nchrs = 0; ; ) { 1078 1.1 cgd d = dropit(c = TRC(cc = *sp++)); 1079 1.1 cgd if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d)) 1080 1.1 cgd for (j = WIDTH; --j;) 1081 1.1 cgd *strp++ = BACKGND; 1082 1.1 cgd else 1083 1.13 mikel strp = scnline(scnkey[(int)c][scnhgt-1-d], 1084 1.13 mikel strp, cc); 1085 1.13 mikel if (*sp == dlm || *sp == '\0' || 1086 1.13 mikel nchrs++ >= PW/(WIDTH+1)-1) 1087 1.1 cgd break; 1088 1.1 cgd *strp++ = BACKGND; 1089 1.1 cgd *strp++ = BACKGND; 1090 1.1 cgd } 1091 1.1 cgd while (*--strp == BACKGND && strp >= outbuf) 1092 1.1 cgd ; 1093 1.1 cgd strp++; 1094 1.1 cgd *strp++ = '\n'; 1095 1.11 mrg (void)write(scfd, outbuf, strp-outbuf); 1096 1.1 cgd } 1097 1.1 cgd } 1098 1.1 cgd 1099 1.5 cgd static int 1100 1.33 hubertf dropit(int c) 1101 1.1 cgd { 1102 1.1 cgd switch(c) { 1103 1.1 cgd 1104 1.1 cgd case TRC('_'): 1105 1.1 cgd case TRC(';'): 1106 1.1 cgd case TRC(','): 1107 1.1 cgd case TRC('g'): 1108 1.1 cgd case TRC('j'): 1109 1.1 cgd case TRC('p'): 1110 1.1 cgd case TRC('q'): 1111 1.1 cgd case TRC('y'): 1112 1.1 cgd return (DROP); 1113 1.1 cgd 1114 1.1 cgd default: 1115 1.1 cgd return (0); 1116 1.1 cgd } 1117 1.1 cgd } 1118 1.1 cgd 1119 1.1 cgd /* 1120 1.1 cgd * sendmail --- 1121 1.1 cgd * tell people about job completion 1122 1.1 cgd */ 1123 1.5 cgd static void 1124 1.30 mjl sendmail(char *user, int bombed) 1125 1.1 cgd { 1126 1.16 mrg int i, p[2], s, nofile; 1127 1.43 christos const char *cp = NULL; /* XXX gcc */ 1128 1.1 cgd struct stat stb; 1129 1.1 cgd FILE *fp; 1130 1.1 cgd 1131 1.41 dsl if (user[0] == '-' || user[0] == '/' || !isprint((unsigned char)user[0])) 1132 1.16 mrg return; 1133 1.1 cgd pipe(p); 1134 1.1 cgd if ((s = dofork(DORETURN)) == 0) { /* child */ 1135 1.1 cgd dup2(p[0], 0); 1136 1.15 mrg closelog(); 1137 1.16 mrg nofile = sysconf(_SC_OPEN_MAX); 1138 1.16 mrg for (i = 3; i < nofile; i++) 1139 1.11 mrg (void)close(i); 1140 1.16 mrg if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL) 1141 1.1 cgd cp++; 1142 1.16 mrg else 1143 1.1 cgd cp = _PATH_SENDMAIL; 1144 1.50 mrg execl(_PATH_SENDMAIL, cp, "-t", NULL); 1145 1.22 mrg _exit(0); 1146 1.1 cgd } else if (s > 0) { /* parent */ 1147 1.1 cgd dup2(p[1], 1); 1148 1.1 cgd printf("To: %s@%s\n", user, fromhost); 1149 1.15 mrg printf("Subject: %s printer job \"%s\"\n", printer, 1150 1.15 mrg *jobname ? jobname : "<unknown>"); 1151 1.15 mrg printf("Reply-To: root@%s\n\n", host); 1152 1.1 cgd printf("Your printer job "); 1153 1.1 cgd if (*jobname) 1154 1.1 cgd printf("(%s) ", jobname); 1155 1.1 cgd switch (bombed) { 1156 1.1 cgd case OK: 1157 1.1 cgd printf("\ncompleted successfully\n"); 1158 1.15 mrg cp = "OK"; 1159 1.1 cgd break; 1160 1.1 cgd default: 1161 1.1 cgd case FATALERR: 1162 1.1 cgd printf("\ncould not be printed\n"); 1163 1.15 mrg cp = "FATALERR"; 1164 1.1 cgd break; 1165 1.1 cgd case NOACCT: 1166 1.1 cgd printf("\ncould not be printed without an account on %s\n", host); 1167 1.15 mrg cp = "NOACCT"; 1168 1.1 cgd break; 1169 1.1 cgd case FILTERERR: 1170 1.23 itohy cp = "FILTERERR"; 1171 1.1 cgd if (stat(tempfile, &stb) < 0 || stb.st_size == 0 || 1172 1.1 cgd (fp = fopen(tempfile, "r")) == NULL) { 1173 1.15 mrg printf("\nhad some errors and may not have printed\n"); 1174 1.1 cgd break; 1175 1.1 cgd } 1176 1.15 mrg printf("\nhad the following errors and may not have printed:\n"); 1177 1.1 cgd while ((i = getc(fp)) != EOF) 1178 1.1 cgd putchar(i); 1179 1.11 mrg (void)fclose(fp); 1180 1.1 cgd break; 1181 1.1 cgd case ACCESS: 1182 1.1 cgd printf("\nwas not printed because it was not linked to the original file\n"); 1183 1.15 mrg cp = "ACCESS"; 1184 1.1 cgd } 1185 1.1 cgd fflush(stdout); 1186 1.11 mrg (void)close(1); 1187 1.16 mrg } else { 1188 1.16 mrg syslog(LOG_ERR, "fork for sendmail failed: %m"); 1189 1.1 cgd } 1190 1.11 mrg (void)close(p[0]); 1191 1.11 mrg (void)close(p[1]); 1192 1.16 mrg if (s > 0) { 1193 1.16 mrg wait(NULL); 1194 1.16 mrg syslog(LOG_INFO, "mail sent to user %s about job %s on " 1195 1.16 mrg "printer %s (%s)", user, *jobname ? jobname : "<unknown>", 1196 1.16 mrg printer, cp); 1197 1.16 mrg } 1198 1.1 cgd } 1199 1.1 cgd 1200 1.1 cgd /* 1201 1.1 cgd * dofork - fork with retries on failure 1202 1.1 cgd */ 1203 1.5 cgd static int 1204 1.30 mjl dofork(int action) 1205 1.1 cgd { 1206 1.43 christos int i, child_pid; 1207 1.6 mycroft struct passwd *pw; 1208 1.1 cgd 1209 1.1 cgd for (i = 0; i < 20; i++) { 1210 1.43 christos if ((child_pid = fork()) < 0) { 1211 1.1 cgd sleep((unsigned)(i*i)); 1212 1.1 cgd continue; 1213 1.1 cgd } 1214 1.1 cgd /* 1215 1.1 cgd * Child should run as daemon instead of root 1216 1.1 cgd */ 1217 1.43 christos if (child_pid == 0) { 1218 1.6 mycroft pw = getpwuid(DU); 1219 1.6 mycroft if (pw == 0) { 1220 1.13 mikel syslog(LOG_ERR, "uid %ld not in password file", 1221 1.6 mycroft DU); 1222 1.6 mycroft break; 1223 1.6 mycroft } 1224 1.6 mycroft initgroups(pw->pw_name, pw->pw_gid); 1225 1.6 mycroft setgid(pw->pw_gid); 1226 1.1 cgd setuid(DU); 1227 1.35 abs signal(SIGCHLD, SIG_DFL); 1228 1.6 mycroft } 1229 1.43 christos return (child_pid); 1230 1.1 cgd } 1231 1.1 cgd syslog(LOG_ERR, "can't fork"); 1232 1.1 cgd 1233 1.1 cgd switch (action) { 1234 1.1 cgd case DORETURN: 1235 1.1 cgd return (-1); 1236 1.1 cgd default: 1237 1.1 cgd syslog(LOG_ERR, "bad action (%d) to dofork", action); 1238 1.1 cgd /*FALL THRU*/ 1239 1.1 cgd case DOABORT: 1240 1.1 cgd exit(1); 1241 1.1 cgd } 1242 1.1 cgd /*NOTREACHED*/ 1243 1.1 cgd } 1244 1.1 cgd 1245 1.1 cgd /* 1246 1.1 cgd * Kill child processes to abort current job. 1247 1.1 cgd */ 1248 1.5 cgd static void 1249 1.33 hubertf abortpr(int signo) 1250 1.1 cgd { 1251 1.11 mrg (void)unlink(tempfile); 1252 1.35 abs (void)unlink(tempremote); 1253 1.1 cgd kill(0, SIGINT); 1254 1.1 cgd if (ofilter > 0) 1255 1.1 cgd kill(ofilter, SIGCONT); 1256 1.1 cgd while (wait(NULL) > 0) 1257 1.1 cgd ; 1258 1.1 cgd exit(0); 1259 1.1 cgd } 1260 1.1 cgd 1261 1.5 cgd static void 1262 1.30 mjl init(void) 1263 1.1 cgd { 1264 1.1 cgd char *s; 1265 1.1 cgd 1266 1.43 christos getprintcap(printer); 1267 1.43 christos 1268 1.43 christos FF = cgetstr(bp, "ff", &s) == -1 ? DEFFF : s; 1269 1.5 cgd 1270 1.5 cgd if (cgetnum(bp, "du", &DU) < 0) 1271 1.1 cgd DU = DEFUID; 1272 1.5 cgd if (cgetnum(bp, "pw", &PW) < 0) 1273 1.1 cgd PW = DEFWIDTH; 1274 1.13 mikel (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW); 1275 1.5 cgd if (cgetnum(bp, "pl", &PL) < 0) 1276 1.1 cgd PL = DEFLENGTH; 1277 1.13 mikel (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL); 1278 1.5 cgd if (cgetnum(bp,"px", &PX) < 0) 1279 1.1 cgd PX = 0; 1280 1.13 mikel (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX); 1281 1.5 cgd if (cgetnum(bp, "py", &PY) < 0) 1282 1.1 cgd PY = 0; 1283 1.13 mikel (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY); 1284 1.43 christos 1285 1.43 christos AF = cgetstr(bp, "af", &s) == -1 ? NULL : s; 1286 1.43 christos OF = cgetstr(bp, "of", &s) == -1 ? NULL : s; 1287 1.43 christos IF = cgetstr(bp, "if", &s) == -1 ? NULL : s; 1288 1.43 christos RF = cgetstr(bp, "rf", &s) == -1 ? NULL : s; 1289 1.43 christos TF = cgetstr(bp, "tf", &s) == -1 ? NULL : s; 1290 1.43 christos NF = cgetstr(bp, "nf", &s) == -1 ? NULL : s; 1291 1.43 christos DF = cgetstr(bp, "df", &s) == -1 ? NULL : s; 1292 1.43 christos GF = cgetstr(bp, "gf", &s) == -1 ? NULL : s; 1293 1.43 christos VF = cgetstr(bp, "vf", &s) == -1 ? NULL : s; 1294 1.43 christos CF = cgetstr(bp, "cf", &s) == -1 ? NULL : s; 1295 1.45 garbled PF = cgetstr(bp, "pf", &s) == -1 ? NULL : s; 1296 1.43 christos TR = cgetstr(bp, "tr", &s) == -1 ? NULL : s; 1297 1.5 cgd 1298 1.5 cgd RS = (cgetcap(bp, "rs", ':') != NULL); 1299 1.5 cgd SF = (cgetcap(bp, "sf", ':') != NULL); 1300 1.5 cgd SH = (cgetcap(bp, "sh", ':') != NULL); 1301 1.5 cgd SB = (cgetcap(bp, "sb", ':') != NULL); 1302 1.5 cgd HL = (cgetcap(bp, "hl", ':') != NULL); 1303 1.5 cgd RW = (cgetcap(bp, "rw", ':') != NULL); 1304 1.5 cgd 1305 1.5 cgd cgetnum(bp, "br", &BR); 1306 1.5 cgd if (cgetnum(bp, "fc", &FC) < 0) 1307 1.1 cgd FC = 0; 1308 1.5 cgd if (cgetnum(bp, "fs", &FS) < 0) 1309 1.1 cgd FS = 0; 1310 1.5 cgd if (cgetnum(bp, "xc", &XC) < 0) 1311 1.1 cgd XC = 0; 1312 1.5 cgd if (cgetnum(bp, "xs", &XS) < 0) 1313 1.1 cgd XS = 0; 1314 1.43 christos MS = cgetstr(bp, "ms", &s) == -1 ? NULL : s; 1315 1.5 cgd 1316 1.5 cgd tof = (cgetcap(bp, "fo", ':') == NULL); 1317 1.1 cgd } 1318 1.1 cgd 1319 1.35 abs /* 1320 1.35 abs * Setup output filter - called once for local printer, or (if -r given to lpd) 1321 1.35 abs * once per file for remote printers 1322 1.35 abs */ 1323 1.5 cgd static void 1324 1.35 abs setup_ofilter(int check_rflag) 1325 1.1 cgd { 1326 1.21 mrg extern int rflag; 1327 1.1 cgd 1328 1.35 abs if (OF && (!remote || (check_rflag && rflag))) { 1329 1.1 cgd int p[2]; 1330 1.35 abs int i, nofile; 1331 1.43 christos const char *cp; 1332 1.1 cgd 1333 1.1 cgd pipe(p); 1334 1.1 cgd if ((ofilter = dofork(DOABORT)) == 0) { /* child */ 1335 1.1 cgd dup2(p[0], 0); /* pipe is std in */ 1336 1.1 cgd dup2(pfd, 1); /* printer is std out */ 1337 1.15 mrg closelog(); 1338 1.16 mrg nofile = sysconf(_SC_OPEN_MAX); 1339 1.16 mrg for (i = 3; i < nofile; i++) 1340 1.11 mrg (void)close(i); 1341 1.16 mrg if ((cp = strrchr(OF, '/')) == NULL) 1342 1.1 cgd cp = OF; 1343 1.1 cgd else 1344 1.1 cgd cp++; 1345 1.50 mrg execl(OF, cp, width, length, NULL); 1346 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, OF); 1347 1.1 cgd exit(1); 1348 1.1 cgd } 1349 1.11 mrg (void)close(p[0]); /* close input side */ 1350 1.1 cgd ofd = p[1]; /* use pipe for output */ 1351 1.1 cgd } else { 1352 1.1 cgd ofd = pfd; 1353 1.1 cgd ofilter = 0; 1354 1.1 cgd } 1355 1.35 abs } 1356 1.35 abs 1357 1.35 abs /* 1358 1.35 abs * Close the output filter and reset ofd back to the main pfd descriptor 1359 1.35 abs */ 1360 1.35 abs static void 1361 1.35 abs close_ofilter(void) 1362 1.35 abs { 1363 1.35 abs int i; 1364 1.35 abs 1365 1.35 abs if (ofilter) { 1366 1.35 abs kill(ofilter, SIGCONT); /* to be sure */ 1367 1.35 abs (void)close(ofd); 1368 1.35 abs ofd = pfd; 1369 1.35 abs while ((i = wait(NULL)) > 0 && i != ofilter) 1370 1.35 abs ; 1371 1.35 abs ofilter = 0; 1372 1.35 abs } 1373 1.35 abs } 1374 1.35 abs 1375 1.35 abs /* 1376 1.35 abs * Acquire line printer or remote connection. 1377 1.35 abs */ 1378 1.35 abs static void 1379 1.35 abs openpr(void) 1380 1.35 abs { 1381 1.35 abs if (!remote && *LP) { 1382 1.48 christos if (strchr(LP, '@') != NULL) 1383 1.48 christos opennet(); 1384 1.35 abs else 1385 1.35 abs opentty(); 1386 1.35 abs } else if (remote) { 1387 1.35 abs openrem(); 1388 1.35 abs } else { 1389 1.35 abs syslog(LOG_ERR, "%s: no line printer device or host name", 1390 1.35 abs printer); 1391 1.35 abs exit(1); 1392 1.35 abs } 1393 1.35 abs 1394 1.35 abs /* 1395 1.35 abs * Start up an output filter, if needed. 1396 1.35 abs */ 1397 1.35 abs setup_ofilter(0); 1398 1.1 cgd } 1399 1.1 cgd 1400 1.15 mrg /* 1401 1.15 mrg * Printer connected directly to the network 1402 1.15 mrg * or to a terminal server on the net 1403 1.15 mrg */ 1404 1.15 mrg static void 1405 1.48 christos opennet(void) 1406 1.15 mrg { 1407 1.16 mrg int i; 1408 1.48 christos int resp; 1409 1.15 mrg 1410 1.15 mrg for (i = 1; ; i = i < 256 ? i << 1 : i) { 1411 1.15 mrg resp = -1; 1412 1.48 christos pfd = getport(LP); 1413 1.15 mrg if (pfd < 0 && errno == ECONNREFUSED) 1414 1.15 mrg resp = 1; 1415 1.15 mrg else if (pfd >= 0) { 1416 1.15 mrg /* 1417 1.15 mrg * need to delay a bit for rs232 lines 1418 1.15 mrg * to stabilize in case printer is 1419 1.15 mrg * connected via a terminal server 1420 1.15 mrg */ 1421 1.15 mrg delay(500); 1422 1.15 mrg break; 1423 1.15 mrg } 1424 1.15 mrg if (i == 1) { 1425 1.15 mrg if (resp < 0) 1426 1.15 mrg pstatus("waiting for %s to come up", LP); 1427 1.15 mrg else 1428 1.15 mrg pstatus("waiting for access to printer on %s", LP); 1429 1.15 mrg } 1430 1.15 mrg sleep(i); 1431 1.15 mrg } 1432 1.48 christos pstatus("sending to %s", LP); 1433 1.15 mrg } 1434 1.15 mrg 1435 1.15 mrg /* 1436 1.15 mrg * Printer is connected to an RS232 port on this host 1437 1.15 mrg */ 1438 1.15 mrg static void 1439 1.30 mjl opentty(void) 1440 1.15 mrg { 1441 1.16 mrg int i; 1442 1.15 mrg 1443 1.15 mrg for (i = 1; ; i = i < 32 ? i << 1 : i) { 1444 1.15 mrg pfd = open(LP, RW ? O_RDWR : O_WRONLY); 1445 1.15 mrg if (pfd >= 0) { 1446 1.15 mrg delay(500); 1447 1.15 mrg break; 1448 1.15 mrg } 1449 1.15 mrg if (errno == ENOENT) { 1450 1.15 mrg syslog(LOG_ERR, "%s: %m", LP); 1451 1.15 mrg exit(1); 1452 1.15 mrg } 1453 1.15 mrg if (i == 1) 1454 1.15 mrg pstatus("waiting for %s to become ready (offline ?)", 1455 1.15 mrg printer); 1456 1.15 mrg sleep(i); 1457 1.15 mrg } 1458 1.15 mrg if (isatty(pfd)) 1459 1.15 mrg setty(); 1460 1.15 mrg pstatus("%s is ready and printing", printer); 1461 1.15 mrg } 1462 1.15 mrg 1463 1.15 mrg /* 1464 1.15 mrg * Printer is on a remote host 1465 1.15 mrg */ 1466 1.15 mrg static void 1467 1.30 mjl openrem(void) 1468 1.15 mrg { 1469 1.16 mrg int i, n; 1470 1.16 mrg int resp; 1471 1.15 mrg 1472 1.15 mrg for (i = 1; ; i = i < 256 ? i << 1 : i) { 1473 1.15 mrg resp = -1; 1474 1.48 christos pfd = getport(RM); 1475 1.15 mrg if (pfd >= 0) { 1476 1.15 mrg n = snprintf(line, sizeof(line), "\2%s\n", RP); 1477 1.15 mrg if (write(pfd, line, n) == n && 1478 1.15 mrg (resp = response()) == '\0') 1479 1.15 mrg break; 1480 1.15 mrg (void) close(pfd); 1481 1.15 mrg } 1482 1.15 mrg if (i == 1) { 1483 1.15 mrg if (resp < 0) 1484 1.15 mrg pstatus("waiting for %s to come up", RM); 1485 1.15 mrg else { 1486 1.15 mrg pstatus("waiting for queue to be enabled on %s", 1487 1.15 mrg RM); 1488 1.15 mrg i = 256; 1489 1.15 mrg } 1490 1.15 mrg } 1491 1.15 mrg sleep(i); 1492 1.15 mrg } 1493 1.15 mrg pstatus("sending to %s", RM); 1494 1.21 mrg } 1495 1.21 mrg 1496 1.21 mrg static void 1497 1.30 mjl alarmer(int s) 1498 1.21 mrg { 1499 1.21 mrg /* nothing */ 1500 1.15 mrg } 1501 1.15 mrg 1502 1.10 jtc #if !defined(__NetBSD__) 1503 1.1 cgd struct bauds { 1504 1.1 cgd int baud; 1505 1.1 cgd int speed; 1506 1.1 cgd } bauds[] = { 1507 1.1 cgd 50, B50, 1508 1.1 cgd 75, B75, 1509 1.1 cgd 110, B110, 1510 1.1 cgd 134, B134, 1511 1.1 cgd 150, B150, 1512 1.1 cgd 200, B200, 1513 1.1 cgd 300, B300, 1514 1.1 cgd 600, B600, 1515 1.1 cgd 1200, B1200, 1516 1.1 cgd 1800, B1800, 1517 1.1 cgd 2400, B2400, 1518 1.1 cgd 4800, B4800, 1519 1.1 cgd 9600, B9600, 1520 1.7 hpeyerl 19200, B19200, 1521 1.7 hpeyerl 38400, B38400, 1522 1.16 mrg 57600, B57600, 1523 1.16 mrg 115200, B115200, 1524 1.1 cgd 0, 0 1525 1.1 cgd }; 1526 1.10 jtc #endif 1527 1.1 cgd 1528 1.1 cgd /* 1529 1.1 cgd * setup tty lines. 1530 1.1 cgd */ 1531 1.5 cgd static void 1532 1.30 mjl setty(void) 1533 1.1 cgd { 1534 1.7 hpeyerl struct info i; 1535 1.7 hpeyerl char **argv, **ap, *p, *val; 1536 1.1 cgd 1537 1.7 hpeyerl i.fd = pfd; 1538 1.7 hpeyerl i.set = i.wset = 0; 1539 1.7 hpeyerl if (ioctl(i.fd, TIOCEXCL, (char *)0) < 0) { 1540 1.1 cgd syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer); 1541 1.1 cgd exit(1); 1542 1.1 cgd } 1543 1.7 hpeyerl if (tcgetattr(i.fd, &i.t) < 0) { 1544 1.7 hpeyerl syslog(LOG_ERR, "%s: tcgetattr: %m", printer); 1545 1.1 cgd exit(1); 1546 1.1 cgd } 1547 1.1 cgd if (BR > 0) { 1548 1.10 jtc #if !defined(__NetBSD__) 1549 1.16 mrg struct bauds *bp; 1550 1.1 cgd for (bp = bauds; bp->baud; bp++) 1551 1.1 cgd if (BR == bp->baud) 1552 1.1 cgd break; 1553 1.1 cgd if (!bp->baud) { 1554 1.1 cgd syslog(LOG_ERR, "%s: illegal baud rate %d", printer, BR); 1555 1.1 cgd exit(1); 1556 1.1 cgd } 1557 1.7 hpeyerl cfsetspeed(&i.t, bp->speed); 1558 1.10 jtc #else 1559 1.10 jtc cfsetspeed(&i.t, BR); 1560 1.10 jtc #endif 1561 1.7 hpeyerl i.set = 1; 1562 1.1 cgd } 1563 1.7 hpeyerl if (MS) { 1564 1.7 hpeyerl if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) { 1565 1.7 hpeyerl syslog(LOG_ERR, "%s: ioctl(TIOCGETD): %m", printer); 1566 1.1 cgd exit(1); 1567 1.1 cgd } 1568 1.7 hpeyerl if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0) 1569 1.7 hpeyerl syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m", 1570 1.7 hpeyerl printer); 1571 1.7 hpeyerl 1572 1.7 hpeyerl argv = (char **)calloc(256, sizeof(char *)); 1573 1.7 hpeyerl if (argv == NULL) { 1574 1.7 hpeyerl syslog(LOG_ERR, "%s: calloc: %m", printer); 1575 1.1 cgd exit(1); 1576 1.1 cgd } 1577 1.7 hpeyerl p = strdup(MS); 1578 1.7 hpeyerl ap = argv; 1579 1.7 hpeyerl while ((val = strsep(&p, " \t,")) != NULL) { 1580 1.7 hpeyerl *ap++ = strdup(val); 1581 1.7 hpeyerl } 1582 1.7 hpeyerl 1583 1.7 hpeyerl for (; *argv; ++argv) { 1584 1.7 hpeyerl if (ksearch(&argv, &i)) 1585 1.7 hpeyerl continue; 1586 1.7 hpeyerl if (msearch(&argv, &i)) 1587 1.7 hpeyerl continue; 1588 1.7 hpeyerl syslog(LOG_INFO, "%s: unknown stty flag: %s", 1589 1.7 hpeyerl printer, *argv); 1590 1.7 hpeyerl } 1591 1.7 hpeyerl } else { 1592 1.7 hpeyerl if (FC) { 1593 1.7 hpeyerl sttyclearflags(&i.t, FC); 1594 1.7 hpeyerl i.set = 1; 1595 1.7 hpeyerl } 1596 1.7 hpeyerl if (FS) { 1597 1.7 hpeyerl sttysetflags(&i.t, FS); 1598 1.7 hpeyerl i.set = 1; 1599 1.7 hpeyerl } 1600 1.7 hpeyerl if (XC) { 1601 1.7 hpeyerl sttyclearlflags(&i.t, XC); 1602 1.7 hpeyerl i.set = 1; 1603 1.7 hpeyerl } 1604 1.7 hpeyerl if (XS) { 1605 1.9 jtc sttysetlflags(&i.t, XS); 1606 1.7 hpeyerl i.set = 1; 1607 1.7 hpeyerl } 1608 1.7 hpeyerl } 1609 1.7 hpeyerl 1610 1.7 hpeyerl if (i.set && tcsetattr(i.fd, TCSANOW, &i.t) < 0) { 1611 1.7 hpeyerl syslog(LOG_ERR, "%s: tcsetattr: %m", printer); 1612 1.7 hpeyerl exit(1); 1613 1.1 cgd } 1614 1.7 hpeyerl if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0) 1615 1.7 hpeyerl syslog(LOG_INFO, "%s: ioctl(TIOCSWINSZ): %m", printer); 1616 1.7 hpeyerl return; 1617 1.1 cgd } 1618 1.1 cgd 1619 1.5 cgd #include <stdarg.h> 1620 1.5 cgd 1621 1.15 mrg static void 1622 1.5 cgd pstatus(const char *msg, ...) 1623 1.1 cgd { 1624 1.16 mrg int fd; 1625 1.22 mrg char *buf; 1626 1.5 cgd va_list ap; 1627 1.40 wiz struct iovec iov[2]; 1628 1.1 cgd 1629 1.1 cgd umask(0); 1630 1.1 cgd fd = open(ST, O_WRONLY|O_CREAT, 0664); 1631 1.1 cgd if (fd < 0 || flock(fd, LOCK_EX) < 0) { 1632 1.1 cgd syslog(LOG_ERR, "%s: %s: %m", printer, ST); 1633 1.1 cgd exit(1); 1634 1.1 cgd } 1635 1.1 cgd ftruncate(fd, 0); 1636 1.29 wiz va_start(ap, msg); 1637 1.22 mrg (void)vasprintf(&buf, msg, ap); 1638 1.5 cgd va_end(ap); 1639 1.40 wiz 1640 1.40 wiz iov[0].iov_base = buf; 1641 1.40 wiz iov[0].iov_len = strlen(buf); 1642 1.43 christos iov[1].iov_base = __UNCONST("\n"); 1643 1.40 wiz iov[1].iov_len = 1; 1644 1.40 wiz (void)writev(fd, iov, 2); 1645 1.11 mrg (void)close(fd); 1646 1.22 mrg free(buf); 1647 1.1 cgd } 1648