8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / lp / model / lp.cat.c
blob29f14ad3184b084e64ebd86d5d7a112ea8c2cf4d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <termio.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <signal.h>
36 #include <sys/times.h>
37 #include <string.h>
38 #include <limits.h>
39 #include <sys/prnio.h>
41 #include "lp.h"
43 #include <locale.h>
46 * Begin Sun Additions for Parallel ports
49 #include <string.h>
50 #include <stdarg.h>
51 #include <signal.h>
52 #include <unistd.h>
53 #include <sys/types.h>
54 #include <sys/ioccom.h>
55 #include <sys/ioctl.h>
57 #include <sys/bpp_io.h>
58 #include <sys/ecppsys.h>
59 #include <stropts.h>
62 * the parameter structure for the parallel port
64 struct ppc_params_t {
65 int flags; /* same as above */
66 int state; /* status of the printer interface */
67 int strobe_w; /* strobe width, in uS */
68 int data_setup; /* data setup time, in uS */
69 int ack_timeout; /* ACK timeout, in secs */
70 int error_timeout; /* PAPER OUT, etc... timeout, in secs */
71 int busy_timeout; /* BUSY timeout, in seconds */
76 static void printer_info(char *fmt, ...);
78 /* These are the routines avaliable to others for use */
79 int is_a_parallel_bpp(int);
80 int bpp_state(int);
81 int parallel_comm(int, int());
82 int get_ecpp_status(int fd);
83 int is_a_prnio(int);
84 int prnio_state(int);
86 #define PRINTER_ERROR_PAPER_OUT 1
87 #define PRINTER_ERROR_OFFLINE 2
88 #define PRINTER_ERROR_BUSY 3
89 #define PRINTER_ERROR_ERROR 4
90 #define PRINTER_ERROR_CABLE_POWER 5
91 #define PRINTER_ERROR_UNKNOWN 6
92 #define PRINTER_ERROR_TIMEOUT 7
93 #define PRINTER_IO_ERROR 129
97 * for BPP PARALLEL interfaces
101 is_a_parallel_bpp(int fd)
103 if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
104 return (1);
105 return (0);
109 #if defined(DEBUG) && defined(NOTDEF)
110 char *
111 BppState(int state)
113 static char buf[BUFSIZ];
115 memset(buf, 0, sizeof (buf));
116 sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
117 ((state & BPP_SLCT_ERR) ? "offline " : ""),
118 ((state & BPP_BUSY_ERR) ? "busy " : ""),
119 ((state & BPP_PE_ERR) ? "paper " : ""),
120 ((state & BPP_ERR_ERR) ? "error " : ""));
122 return (buf);
124 #endif
127 bpp_state(int fd)
129 if (ioctl(fd, BPPIOC_TESTIO)) {
130 struct bpp_error_status bpp_stat;
131 int state;
133 if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
134 exit(PRINTER_IO_ERROR);
135 state = bpp_stat.pin_status;
137 #if defined(DEBUG) && defined(NOTDEF)
138 logit("%s", BppState(state));
139 #endif
141 if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
142 /* paper is out */
143 return (PRINTER_ERROR_PAPER_OUT);
144 } else if (state & BPP_BUSY_ERR) {
145 /* printer is busy */
146 return (PRINTER_ERROR_BUSY);
147 } else if (state & BPP_SLCT_ERR) {
148 /* printer is offline */
149 return (PRINTER_ERROR_OFFLINE);
150 } else if (state & BPP_ERR_ERR) {
151 /* printer is errored */
152 return (PRINTER_ERROR_ERROR);
153 } else if (state == BPP_PE_ERR) {
154 /* printer is off/unplugged */
155 return (PRINTER_ERROR_CABLE_POWER);
156 } else if (state) {
157 return (PRINTER_ERROR_UNKNOWN);
158 } else
159 return (0);
161 return (0);
165 * For ecpp parallel port
169 get_ecpp_status(int fd)
171 int state;
172 struct ecpp_transfer_parms transfer_parms;
175 if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
176 return (-1);
179 state = transfer_parms.mode;
181 * We don't know what all printers will return in
182 * nibble mode, therefore if we support nibble mode we will
183 * force the printer to be in CENTRONICS mode.
185 if (state != ECPP_CENTRONICS) {
186 transfer_parms.mode = ECPP_CENTRONICS;
187 if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
188 return (-1);
189 } else {
190 state = ECPP_CENTRONICS;
195 return (state);
199 * For prnio(7I) - generic printer interface
202 is_a_prnio(int fd)
204 uint_t cap;
206 /* check if device supports prnio */
207 if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
208 return (0);
210 /* we will use 1284 status if available */
211 if ((cap & PRN_1284_STATUS) == 0) {
212 /* some devices may only support 1284 status in unidir. mode */
213 if (cap & PRN_BIDI) {
214 cap &= ~PRN_BIDI;
215 (void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
218 return (1);
222 prnio_state(int fd)
224 uint_t status;
225 uchar_t pins;
227 if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
228 (status & PRN_READY)) {
229 return (0);
232 if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
233 return (PRINTER_ERROR_UNKNOWN);
236 if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
237 /* paper is out */
238 return (PRINTER_ERROR_PAPER_OUT);
239 } else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
240 PRN_1284_NOFAULT | PRN_1284_BUSY)) {
241 /* printer is off/unplugged */
242 return (PRINTER_ERROR_CABLE_POWER);
243 } else if ((pins & PRN_1284_SELECT) == 0) {
244 /* printer is offline */
245 return (PRINTER_ERROR_OFFLINE);
246 } else if ((pins & PRN_1284_NOFAULT) == 0) {
247 /* printer is errored */
248 return (PRINTER_ERROR_ERROR);
249 } else if (pins & PRN_1284_PE) {
250 /* paper is out */
251 return (PRINTER_ERROR_PAPER_OUT);
252 } else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
253 return (PRINTER_ERROR_UNKNOWN);
256 return (0);
260 * Common routines
263 /*ARGSUSED0*/
264 static void
265 ByeByeParallel(int sig)
267 /* try to shove out the EOT */
268 (void) write(1, "\004", 1);
269 exit(0);
273 /*ARGSUSED0*/
274 static void
275 printer_info(char *fmt, ...)
277 char mesg[BUFSIZ];
278 va_list ap;
280 va_start(ap, fmt);
281 vsprintf(mesg, fmt, ap);
282 va_end(ap);
284 * fprintf(stderr,
285 * "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
286 * mesg);
288 fprintf(stderr, "%s\n", mesg);
289 fflush(stderr);
290 fsync(2);
294 static void
295 printer_error(int error)
297 switch (error) {
298 case -1:
299 printer_info("ioctl(): %s", strerror(errno));
300 break;
301 case PRINTER_ERROR_PAPER_OUT:
302 printer_info("out of paper");
303 break;
304 case PRINTER_ERROR_OFFLINE:
305 printer_info("offline");
306 break;
307 case PRINTER_ERROR_BUSY:
308 printer_info("busy");
309 break;
310 case PRINTER_ERROR_ERROR:
311 printer_info("printer error");
312 break;
313 case PRINTER_ERROR_CABLE_POWER:
314 printer_info("printer powered off or disconnected");
315 break;
316 case PRINTER_ERROR_UNKNOWN:
317 printer_info("unknown error");
318 break;
319 case PRINTER_ERROR_TIMEOUT:
320 printer_info("communications timeout");
321 break;
322 default:
323 printer_info("get_status() failed");
328 static void
329 wait_state(int fd, int get_state())
331 int state;
332 int was_faulted = 0;
334 while (state = get_state(fd)) {
335 was_faulted = 1;
336 printer_error(state);
337 sleep(15);
340 if (was_faulted) {
341 fprintf(stderr, "printer ok\n");
342 fflush(stderr);
343 fsync(2);
348 * end of Sun Additions for parallel port
350 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
351 #define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK)
352 #define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR)
354 #define E_SUCCESS 0
355 #define E_BAD_INPUT 1
356 #define E_BAD_OUTPUT 2
357 #define E_BAD_TERM 3
358 #define E_IDENTICAL 4
359 #define E_WRITE_FAILED 5
360 #define E_TIMEOUT 6
361 #define E_HANGUP 7
362 #define E_INTERRUPT 8
364 #define SAFETY_FACTOR 2.0
365 #define R(F) (int)((F) + .5)
366 #define DELAY(N, D) R(SAFETY_FACTOR * ((N) / (double)(D)))
368 char buffer[BUFSIZ];
370 void sighup(),
371 sigint(),
372 sigquit(),
373 sigpipe(),
374 sigalrm(),
375 sigterm();
377 #if defined(baudrate)
378 #undef baudrate
379 #endif
381 int baudrate();
385 nop(int fd)
387 return (0);
390 int bpp_state(int);
394 * main()
398 main(int argc, char *argv[])
400 int nin, nout, effective_rate, max_delay = 0, n;
401 int report_rate;
402 short print_rate;
403 struct stat in, out;
404 struct tms tms;
405 long epoch_start, epoch_end;
406 char *TERM;
407 int (*func)(int fd);
410 * The Spooler can hit us with SIGTERM for three reasons:
412 * - the user's job has been canceled
413 * - the printer has been disabled while we were printing
414 * - the Spooler heard that the printer has a fault,
415 * and the fault recovery is wait or beginning
417 * We should exit cleanly for the first two cases,
418 * but we have to be careful with the last. If it was THIS
419 * PROGRAM that told the Spooler about the fault, we must
420 * exit consistently.
422 * The method of avoiding any problem is to turn off the
423 * trapping of SIGTERM before telling the Spooler about
424 * the fault.
426 * Faults that we can detect:
427 * - hangup (drop of carrier)
428 * - interrupt (printer sent a break or quit character)
429 * - SIGPIPE (output port is a FIFO, and was closed early)
430 * - failed or incomplete write()
431 * - excess delay in write() (handled with SIGALRM later)
433 * Pseudo-faults (errors in use):
434 * - No input/output, or strange input/output
435 * - Input/output identical
436 * - No TERM defined or trouble reading Terminfo database
438 signal(SIGTERM, sigterm);
439 signal(SIGHUP, sighup);
440 signal(SIGINT, sigint);
441 signal(SIGQUIT, sigint);
442 signal(SIGPIPE, sigpipe);
445 if (argc > 1 && STREQU(argv[1], "-r")) {
446 report_rate = 1;
447 argc--;
448 argv++;
449 } else
450 report_rate = 0;
452 (void) setlocale(LC_ALL, "");
453 #if !defined(TEXT_DOMAIN)
454 #define TEXT_DOMAIN "SYS_TEST"
455 #endif
456 (void) textdomain(TEXT_DOMAIN);
459 * Stat the standard output to be sure it is defined.
461 if (fstat(1, &out) < 0) {
462 signal(SIGTERM, SIG_IGN);
463 fprintf(stderr, gettext("Can't stat output "
464 "(%s);\nincorrect use of lp.cat!\n"), PERROR);
465 exit(E_BAD_OUTPUT);
469 * Stat the standard input to be sure it is defined.
471 if (fstat(0, &in) < 0) {
472 signal(SIGTERM, SIG_IGN);
473 fprintf(stderr, gettext("Can't stat input "
474 "(%s);\nincorrect use of lp.cat!\n"), PERROR);
475 exit(E_BAD_INPUT);
479 * If the standard output is not a character special file or a
480 * block special file, make sure it is not identical to the
481 * standard input.
483 * If we are an ecpp parallel port in centronics mode treat
484 * ourselves as a bpp compatible device.
487 if (is_a_prnio(1)) {
488 func = prnio_state;
489 } else if (is_a_parallel_bpp(1) ||
490 (get_ecpp_status(1) == ECPP_CENTRONICS)) {
491 func = bpp_state;
492 } else if (isatty(1)) {
493 /* serial connection (probably) - continue as usual */
494 func = nop;
495 } else {
496 func = nop;
499 if (!ISCHR(out) && !ISBLK(out) && IDENTICAL(out, in)) {
500 signal(SIGTERM, SIG_IGN);
501 fprintf(stderr, gettext("Input and output are identical; "
502 "incorrect use of lp.cat!\n"));
503 exit(E_IDENTICAL);
507 * The effective data transfer rate is the lesser
508 * of the transmission rate and print rate. If an
509 * argument was passed to us, it should be a data
510 * rate and it may be lower still.
511 * Based on the effective data transfer rate,
512 * we can predict the maximum delay we should experience.
513 * But there are other factors that could introduce
514 * delay, so let's be generous; after all, we'd rather
515 * err in favor of waiting too long to detect a fault
516 * than err too often on false alarms.
519 if (!(TERM = getenv("TERM")) || !*TERM) {
520 signal(SIGTERM, SIG_IGN);
521 fprintf(stderr, gettext("No TERM variable defined! "
522 "Trouble with the Spooler!\n"));
523 exit(E_BAD_TERM);
525 if (!STREQU(TERM, NAME_UNKNOWN) &&
526 tidbit(TERM, "cps", &print_rate) == -1) {
527 signal(SIGTERM, SIG_IGN);
528 fprintf(stderr, gettext("Trouble identifying printer "
529 "type \"%s\"; check the Terminfo database.\n"), TERM);
530 exit(E_BAD_TERM);
532 if (STREQU(TERM, NAME_UNKNOWN))
533 print_rate = -1;
535 effective_rate = baudrate() / 10; /* okay for most bauds */
536 if (print_rate != -1 && print_rate < effective_rate)
537 effective_rate = print_rate;
538 if (argc > 1 && (n = atoi(argv[1])) >= 0 && n < effective_rate)
539 effective_rate = n; /* 0 means infinite delay */
540 if (effective_rate)
541 max_delay = DELAY(BUFSIZ, effective_rate);
544 * We'll use the "alarm()" system call to keep us from
545 * waiting too long to write to a printer in trouble.
547 if (max_delay)
548 signal(SIGALRM, sigalrm);
551 * While not end of standard input, copy blocks to
552 * standard output.
554 while ((nin = read(0, buffer, BUFSIZ)) > 0) {
555 char *ptr = buffer;
558 * We should be safe from incomplete writes to a full
559 * pipe, as long as the size of the buffer we write is
560 * a even divisor of the pipe buffer limit. As long as
561 * we read from files or pipes (not communication devices)
562 * this should be true for all but the last buffer. The
563 * last will be smaller, and won't straddle the pipe max
564 * limit (think about it).
566 #if PIPE_BUF < BUFSIZ || (PIPE_MAX % BUFSIZ)
567 this_wont_compile;
568 #endif
569 if (report_rate)
570 epoch_start = times(&tms);
571 do {
572 wait_state(1, func);
574 if (max_delay)
575 alarm(max_delay);
576 nout = write(1, ptr, nin);
577 alarm(0);
578 if (nout < 0) {
579 fprintf(stderr, gettext("Write failed "
580 "(%s);\nperhaps the printer has gone "
581 "off-line.\n"), PERROR);
582 fflush(stderr);
583 if (errno != EINTR)
584 /* I/O error on device, get lpcshed to retry */
585 exit(PRINTER_IO_ERROR);
586 else /* wait for printer to come back online */
587 sleep(15);
588 } else {
589 nin -= nout;
590 ptr += nout;
592 } while (nin > 0);
594 if (max_delay)
595 alarm(0);
596 else if (report_rate) {
597 epoch_end = times(&tms);
598 if (epoch_end - epoch_start > 0)
599 fprintf(stderr, "%d CPS\n",
600 R((100 * BUFSIZ) /
601 (double)(epoch_end - epoch_start)));
606 return (E_SUCCESS);
610 * sighup() - CATCH A HANGUP (LOSS OF CARRIER)
612 void
613 sighup()
615 signal(SIGTERM, SIG_IGN);
616 signal(SIGHUP, SIG_IGN);
617 fprintf(stderr, gettext(HANGUP_FAULT_LPCAT));
618 exit(E_HANGUP);
622 * sigint() - CATCH AN INTERRUPT
624 void
625 sigint()
627 signal(SIGTERM, SIG_IGN);
628 signal(SIGINT, SIG_IGN);
629 fprintf(stderr, gettext(INTERRUPT_FAULT));
630 exit(E_INTERRUPT);
634 * sigpipe() - CATCH EARLY CLOSE OF PIPE
636 void
637 sigpipe()
639 signal(SIGTERM, SIG_IGN);
640 signal(SIGPIPE, SIG_IGN);
641 fprintf(stderr, gettext(PIPE_FAULT));
642 exit(E_INTERRUPT);
646 * sigalrm() - CATCH AN ALARM
648 void
649 sigalrm()
651 signal(SIGTERM, SIG_IGN);
652 fprintf(stderr, gettext("Excessive write delay; "
653 "perhaps the printer has gone off-line.\n"));
654 exit(E_TIMEOUT);
658 * sigterm() - CATCH A TERMINATION SIGNAL
660 void
661 sigterm()
663 signal(SIGTERM, SIG_IGN);
665 * try to flush the output queue in the case of ecpp port.
666 * ignore the return code as this may not be the ecpp.
668 ioctl(1, I_FLUSH, FLUSHW);
669 exit(E_SUCCESS);
673 * baudrate() - RETURN BAUD RATE OF OUTPUT LINE
676 static int baud_convert[] =
678 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
679 1800, 2400, 4800, 9600, 19200, 38400, 57600,
680 76800, 115200, 153600, 230400, 307200, 460800, 921600
684 baudrate()
686 struct termio tm;
687 struct termios tms;
688 int speed;
690 if (ioctl(1, TCGETS, &tms) < 0) {
691 if (ioctl(1, TCGETA, &tm) < 0)
692 return (1200);
693 else
694 speed = tm.c_cflag&CBAUD;
695 } else
696 speed = cfgetospeed(&tms);
698 return (speed ? baud_convert[speed] : 1200);