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(4I) - 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 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
678 1800, 2400, 4800, 9600, 19200, 38400, 57600,
679 76800, 115200, 153600, 230400, 307200, 460800, 921600,
680 1000000, 1152000, 1500000, 2000000, 2500000, 3000000,
681 3500000, 4000000
682 };
683
684 int
baudrate()685 baudrate()
686 {
687 struct termio tm;
688 struct termios tms;
689 int speed;
690
691 if (ioctl(1, TCGETS, &tms) < 0) {
692 if (ioctl(1, TCGETA, &tm) < 0) {
693 return (1200);
694 } else {
695 speed = tm.c_cflag&CBAUD;
696 }
697 } else {
698 speed = cfgetospeed(&tms);
699 }
700
701 return (speed ? baud_convert[speed] : 1200);
702 }
703