1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
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>
40
41 #include "lp.h"
42
43 #include <locale.h>
44
45 /*
46 * Begin Sun Additions for Parallel ports
47 */
48
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>
56
57 #include <sys/bpp_io.h>
58 #include <sys/ecppsys.h>
59 #include <stropts.h>
60
61 /*
62 * the parameter structure for the parallel port
63 */
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 */
72 };
73
74
75
76 static void printer_info(char *fmt, ...);
77
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);
85
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
94
95
96 /*
97 * for BPP PARALLEL interfaces
98 */
99
100 int
is_a_parallel_bpp(int fd)101 is_a_parallel_bpp(int fd)
102 {
103 if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
104 return (1);
105 return (0);
106 }
107
108
109 #if defined(DEBUG) && defined(NOTDEF)
110 char *
BppState(int state)111 BppState(int state)
112 {
113 static char buf[BUFSIZ];
114
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 " : ""));
121
122 return (buf);
123 }
124 #endif
125
126 int
bpp_state(int fd)127 bpp_state(int fd)
128 {
129 if (ioctl(fd, BPPIOC_TESTIO)) {
130 struct bpp_error_status bpp_stat;
131 int state;
132
133 if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
134 exit(PRINTER_IO_ERROR);
135 state = bpp_stat.pin_status;
136
137 #if defined(DEBUG) && defined(NOTDEF)
138 logit("%s", BppState(state));
139 #endif
140
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);
160 }
161 return (0);
162 }
163
164 /*
165 * For ecpp parallel port
166 */
167
168 int
get_ecpp_status(int fd)169 get_ecpp_status(int fd)
170 {
171 int state;
172 struct ecpp_transfer_parms transfer_parms;
173
174
175 if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
176 return (-1);
177 }
178
179 state = transfer_parms.mode;
180 /*
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.
184 */
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;
191 }
192 }
193
194
195 return (state);
196 }
197
198 /*
199 * For prnio(7I) - generic printer interface
200 */
201 int
is_a_prnio(int fd)202 is_a_prnio(int fd)
203 {
204 uint_t cap;
205
206 /* check if device supports prnio */
207 if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
208 return (0);
209 }
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);
216 }
217 }
218 return (1);
219 }
220
221 int
prnio_state(int fd)222 prnio_state(int fd)
223 {
224 uint_t status;
225 uchar_t pins;
226
227 if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
228 (status & PRN_READY)) {
229 return (0);
230 }
231
232 if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
233 return (PRINTER_ERROR_UNKNOWN);
234 }
235
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);
254 }
255
256 return (0);
257 }
258
259 /*
260 * Common routines
261 */
262
263 /*ARGSUSED0*/
264 static void
ByeByeParallel(int sig)265 ByeByeParallel(int sig)
266 {
267 /* try to shove out the EOT */
268 (void) write(1, "\004", 1);
269 exit(0);
270 }
271
272
273 /*ARGSUSED0*/
274 static void
printer_info(char * fmt,...)275 printer_info(char *fmt, ...)
276 {
277 char mesg[BUFSIZ];
278 va_list ap;
279
280 va_start(ap, fmt);
281 vsprintf(mesg, fmt, ap);
282 va_end(ap);
283 /*
284 * fprintf(stderr,
285 * "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
286 * mesg);
287 */
288 fprintf(stderr, "%s\n", mesg);
289 fflush(stderr);
290 fsync(2);
291
292 }
293
294 static void
printer_error(int error)295 printer_error(int error)
296 {
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");
324 }
325 }
326
327
328 static void
wait_state(int fd,int get_state ())329 wait_state(int fd, int get_state())
330 {
331 int state;
332 int was_faulted = 0;
333
334 while (state = get_state(fd)) {
335 was_faulted = 1;
336 printer_error(state);
337 sleep(15);
338 }
339
340 if (was_faulted) {
341 fprintf(stderr, "printer ok\n");
342 fflush(stderr);
343 fsync(2);
344 }
345 }
346
347 /*
348 * end of Sun Additions for parallel port
349 */
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)
353
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
363
364 #define SAFETY_FACTOR 2.0
365 #define R(F) (int)((F) + .5)
366 #define DELAY(N, D) R(SAFETY_FACTOR * ((N) / (double)(D)))
367
368 char buffer[BUFSIZ];
369
370 void sighup(),
371 sigint(),
372 sigquit(),
373 sigpipe(),
374 sigalrm(),
375 sigterm();
376
377 #if defined(baudrate)
378 #undef baudrate
379 #endif
380
381 int baudrate();
382
383
384 int
nop(int fd)385 nop(int fd)
386 {
387 return (0);
388 }
389
390 int bpp_state(int);
391
392
393 /*
394 * main()
395 */
396
397 int
main(int argc,char * argv[])398 main(int argc, char *argv[])
399 {
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);
408
409 /*
410 * The Spooler can hit us with SIGTERM for three reasons:
411 *
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
416 *
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.
421 *
422 * The method of avoiding any problem is to turn off the
423 * trapping of SIGTERM before telling the Spooler about
424 * the fault.
425 *
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)
432 *
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
437 */
438 signal(SIGTERM, sigterm);
439 signal(SIGHUP, sighup);
440 signal(SIGINT, sigint);
441 signal(SIGQUIT, sigint);
442 signal(SIGPIPE, sigpipe);
443
444
445 if (argc > 1 && STREQU(argv[1], "-r")) {
446 report_rate = 1;
447 argc--;
448 argv++;
449 } else
450 report_rate = 0;
451
452 (void) setlocale(LC_ALL, "");
453 #if !defined(TEXT_DOMAIN)
454 #define TEXT_DOMAIN "SYS_TEST"
455 #endif
456 (void) textdomain(TEXT_DOMAIN);
457
458 /*
459 * Stat the standard output to be sure it is defined.
460 */
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);
466 }
467
468 /*
469 * Stat the standard input to be sure it is defined.
470 */
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);
476 }
477
478 /*
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.
482 *
483 * If we are an ecpp parallel port in centronics mode treat
484 * ourselves as a bpp compatible device.
485 */
486
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;
497 }
498
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);
504 }
505
506 /*
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.
517 */
518
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);
524 }
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);
531 }
532 if (STREQU(TERM, NAME_UNKNOWN))
533 print_rate = -1;
534
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);
542
543 /*
544 * We'll use the "alarm()" system call to keep us from
545 * waiting too long to write to a printer in trouble.
546 */
547 if (max_delay)
548 signal(SIGALRM, sigalrm);
549
550 /*
551 * While not end of standard input, copy blocks to
552 * standard output.
553 */
554 while ((nin = read(0, buffer, BUFSIZ)) > 0) {
555 char *ptr = buffer;
556
557 /*
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).
565 */
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);
573
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;
591 }
592 } while (nin > 0);
593
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)));
602 }
603
604 }
605
606 return (E_SUCCESS);
607 }
608
609 /*
610 * sighup() - CATCH A HANGUP (LOSS OF CARRIER)
611 */
612 void
sighup()613 sighup()
614 {
615 signal(SIGTERM, SIG_IGN);
616 signal(SIGHUP, SIG_IGN);
617 fprintf(stderr, gettext(HANGUP_FAULT_LPCAT));
618 exit(E_HANGUP);
619 }
620
621 /*
622 * sigint() - CATCH AN INTERRUPT
623 */
624 void
sigint()625 sigint()
626 {
627 signal(SIGTERM, SIG_IGN);
628 signal(SIGINT, SIG_IGN);
629 fprintf(stderr, gettext(INTERRUPT_FAULT));
630 exit(E_INTERRUPT);
631 }
632
633 /*
634 * sigpipe() - CATCH EARLY CLOSE OF PIPE
635 */
636 void
sigpipe()637 sigpipe()
638 {
639 signal(SIGTERM, SIG_IGN);
640 signal(SIGPIPE, SIG_IGN);
641 fprintf(stderr, gettext(PIPE_FAULT));
642 exit(E_INTERRUPT);
643 }
644
645 /*
646 * sigalrm() - CATCH AN ALARM
647 */
648 void
sigalrm()649 sigalrm()
650 {
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);
655 }
656
657 /*
658 * sigterm() - CATCH A TERMINATION SIGNAL
659 */
660 void
sigterm()661 sigterm()
662 {
663 signal(SIGTERM, SIG_IGN);
664 /*
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.
667 */
668 ioctl(1, I_FLUSH, FLUSHW);
669 exit(E_SUCCESS);
670 }
671
672 /*
673 * baudrate() - RETURN BAUD RATE OF OUTPUT LINE
674 */
675
676 static int baud_convert[] =
677 {
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
681 };
682
683 int
baudrate()684 baudrate()
685 {
686 struct termio tm;
687 struct termios tms;
688 int speed;
689
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);
697
698 return (speed ? baud_convert[speed] : 1200);
699 }
700