xref: /illumos-gate/usr/src/cmd/lp/model/lp.cat.c (revision 49218d4f8e4d84d1c08aeb267bcf6e451f2056dc)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include "stdio.h"
33 #include "termio.h"
34 #include "sys/types.h"
35 #include "errno.h"
36 #include "signal.h"
37 #include "sys/times.h"
38 #include "string.h"
39 #include "limits.h"
40 #include <sys/prnio.h>
41 
42 #include "lp.h"
43 
44 #include <locale.h>
45 
46 /**
47  **	Begin Sun Additions for Parallel ports
48  **/
49 
50 extern char *_sys_errlist[];
51 #include <string.h>
52 #include <stdarg.h>
53 #include <signal.h>
54 #include <unistd.h>
55 #include <sys/types.h>
56 #include <sys/ioccom.h>
57 #include <sys/ioctl.h>
58 
59 #include <sys/bpp_io.h>
60 #include <sys/ecppsys.h>
61 #include <stropts.h>
62 
63 /*
64  * the parameter structure for the parallel port
65  */
66 struct ppc_params_t {
67 	int		flags;		/* same as above */
68 	int		state;		/* status of the printer interface */
69 	int		strobe_w;	/* strobe width, in uS */
70 	int		data_setup;	/* data setup time, in uS */
71 	int		ack_timeout;	/* ACK timeout, in secs */
72 	int		error_timeout;	/* PAPER OUT, etc... timeout, in secs */
73 	int		busy_timeout;	/* BUSY timeout, in seconds */
74 };
75 
76 
77 
78 static void printer_info(char *fmt, ...);
79 
80 /*	These are the routines avaliable to others for use 	*/
81 int is_a_parallel_bpp(int);
82 int bpp_state(int);
83 int parallel_comm(int, int());
84 int get_ecpp_status(int fd);
85 int is_a_prnio(int);
86 int prnio_state(int);
87 
88 #define PRINTER_ERROR_PAPER_OUT		1
89 #define PRINTER_ERROR_OFFLINE		2
90 #define PRINTER_ERROR_BUSY		3
91 #define PRINTER_ERROR_ERROR		4
92 #define PRINTER_ERROR_CABLE_POWER	5
93 #define PRINTER_ERROR_UNKNOWN		6
94 #define PRINTER_ERROR_TIMEOUT		7
95 #define	PRINTER_IO_ERROR		129
96 
97 
98 /****************************************************************************/
99 
100 /**
101  *	for BPP PARALLEL interfaces
102  **/
103 
104 int is_a_parallel_bpp(int fd)
105 {
106 	if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
107 		return(1);
108 	return(0);
109 }
110 
111 
112 #if defined(DEBUG) && defined(NOTDEF)
113 char *BppState(int state)
114 {
115 	static char buf[BUFSIZ];
116 
117 	memset(buf, 0, sizeof(buf));
118 	sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
119 		((state & BPP_SLCT_ERR) ?  "offline " : ""),
120 		((state & BPP_BUSY_ERR) ?  "busy " : ""),
121 		((state & BPP_PE_ERR) ?  "paper " : ""),
122 		((state & BPP_ERR_ERR) ?  "error " : ""));
123 
124 	return(buf);
125 }
126 #endif
127 
128 int bpp_state(int fd)
129 {
130 	if (ioctl(fd, BPPIOC_TESTIO)) {
131 		struct bpp_error_status  bpp_stat;
132 		int state;
133 
134 		if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
135 			exit(PRINTER_IO_ERROR);
136 		state = bpp_stat.pin_status;
137 
138 #if defined(DEBUG) && defined(NOTDEF)
139 		logit("%s", BppState(state));
140 #endif
141 
142 		if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
143 			/* paper is out */
144 			return(PRINTER_ERROR_PAPER_OUT);
145 		} else if (state & BPP_BUSY_ERR) {
146 			/* printer is busy */
147 			return(PRINTER_ERROR_BUSY);
148 		} else if (state & BPP_SLCT_ERR) {
149 			/* printer is offline */
150 			return(PRINTER_ERROR_OFFLINE);
151 		} else if (state & BPP_ERR_ERR) {
152 			/* printer is errored */
153 			return(PRINTER_ERROR_ERROR);
154 		} else if (state == BPP_PE_ERR) {
155 			/* printer is off/unplugged */
156 			return(PRINTER_ERROR_CABLE_POWER);
157 		} else if (state) {
158 			return(PRINTER_ERROR_UNKNOWN);
159 		} else
160 			return(0);
161 	}
162 	return(0);
163 }
164 
165 /*
166  * For ecpp parallel port
167  */
168 
169 int
170 get_ecpp_status(int fd)
171 {
172 	int state;
173 	struct ecpp_transfer_parms transfer_parms;
174 
175 
176 	if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
177 		return(-1);
178 	}
179 
180 	state = transfer_parms.mode;
181 	/*
182 	 * We don't know what all printers will return in
183 	 * nibble mode, therefore if we support nibble mode we will
184 	 * force the printer to be in CENTRONICS mode.
185 	 */
186 	if (state != ECPP_CENTRONICS) {
187 		transfer_parms.mode = ECPP_CENTRONICS;
188 		if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
189 			return(-1);
190 		} else {
191 			state = ECPP_CENTRONICS;
192 		}
193 	}
194 
195 
196 	return(state);
197 }
198 
199 /**
200  * For prnio(7I) - generic printer interface
201  **/
202 int 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 {
223 	uint_t	status;
224 	uchar_t	pins;
225 
226 	if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
227 	    (status & PRN_READY)) {
228 		return(0);
229 	}
230 
231 	if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
232 		return(PRINTER_ERROR_UNKNOWN);
233 	}
234 
235 	if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
236 		/* paper is out */
237 		return(PRINTER_ERROR_PAPER_OUT);
238 	} else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
239 				PRN_1284_NOFAULT | PRN_1284_BUSY)) {
240 		/* printer is off/unplugged */
241 		return(PRINTER_ERROR_CABLE_POWER);
242 	} else if ((pins & PRN_1284_SELECT) == 0) {
243 		/* printer is offline */
244 		return(PRINTER_ERROR_OFFLINE);
245 	} else if ((pins & PRN_1284_NOFAULT) == 0) {
246 		/* printer is errored */
247 		return(PRINTER_ERROR_ERROR);
248 	} else if (pins & PRN_1284_PE) {
249 		/* paper is out */
250 		return(PRINTER_ERROR_PAPER_OUT);
251 	} else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
252 		return(PRINTER_ERROR_UNKNOWN);
253 	}
254 
255 	return(0);
256 }
257 
258 /**
259  *	Common routines
260  **/
261 
262 /*ARGSUSED0*/
263 static void
264 ByeByeParallel(int sig)
265 {
266 	/* try to shove out the EOT */
267 	(void) write(1, "\004", 1);
268 	exit(0);
269 }
270 
271 
272 /*ARGSUSED0*/
273 static void
274 printer_info(char *fmt, ...)
275 {
276 	char mesg[BUFSIZ];
277 	va_list ap;
278 
279 	va_start(ap, fmt);
280 	vsprintf(mesg, fmt, ap);
281 	va_end(ap);
282 /*
283 	fprintf(stderr,
284 		"%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
285 		mesg);
286 */
287 	fprintf(stderr, "%s\n", mesg);
288 	fflush(stderr);
289 	fsync(2);
290 
291 }
292 
293 static void
294 printer_error(int error)
295 {
296 	switch (error) {
297 		case -1:
298 			printer_info("ioctl(): %s", _sys_errlist[errno]);
299 			break;
300 		case PRINTER_ERROR_PAPER_OUT:
301 			printer_info("out of paper");
302 			break;
303 		case PRINTER_ERROR_OFFLINE:
304 			printer_info("offline");
305 			break;
306 		case PRINTER_ERROR_BUSY:
307 			printer_info("busy");
308 			break;
309 		case PRINTER_ERROR_ERROR:
310 			printer_info("printer error");
311 			break;
312 		case PRINTER_ERROR_CABLE_POWER:
313 			printer_info("printer powered off or disconnected");
314 			break;
315 		case PRINTER_ERROR_UNKNOWN:
316 			printer_info("unknown error");
317 			break;
318 		case PRINTER_ERROR_TIMEOUT:
319 			printer_info("communications timeout");
320 			break;
321 		default:
322 			printer_info("get_status() failed");
323 	}
324 }
325 
326 
327 static void
328 wait_state(int fd, int get_state())
329 {
330 	int state;
331 	int was_faulted = 0;
332 
333 	while (state = get_state(fd)) {
334 		was_faulted=1;
335 		printer_error(state);
336 		sleep(15);
337 	}
338 
339 	if (was_faulted) {
340 		fprintf(stderr, "printer ok\n");
341 		fflush(stderr);
342 		fsync(2);
343 	}
344 }
345 
346 /**
347  **  end of Sun Additions for parallel port
348  **/
349 #define	IDENTICAL(A,B)	(A.st_dev==B.st_dev && A.st_ino==B.st_ino)
350 #define ISBLK(A)	((A.st_mode & S_IFMT) == S_IFBLK)
351 #define ISCHR(A)	((A.st_mode & S_IFMT) == S_IFCHR)
352 
353 #define E_SUCCESS	0
354 #define E_BAD_INPUT	1
355 #define E_BAD_OUTPUT	2
356 #define E_BAD_TERM	3
357 #define E_IDENTICAL	4
358 #define	E_WRITE_FAILED	5
359 #define	E_TIMEOUT	6
360 #define E_HANGUP	7
361 #define E_INTERRUPT	8
362 
363 #define SAFETY_FACTOR	2.0
364 #define R(F)		(int)((F) + .5)
365 #define DELAY(N,D)	R(SAFETY_FACTOR * ((N) / (double)(D)))
366 
367 extern int		sys_nerr;
368 
369 extern char		*sys_errlist[],
370 			*getenv();
371 
372 extern int		atoi();
373 
374 char			buffer[BUFSIZ];
375 
376 void			sighup(),
377 			sigint(),
378 			sigquit(),
379 			sigpipe(),
380 			sigalrm(),
381 			sigterm();
382 
383 #if	defined(baudrate)
384 # undef	baudrate
385 #endif
386 
387 int			baudrate();
388 
389 
390 int nop(int fd) { return (0); }
391 int bpp_state(int);
392 
393 
394 /**
395  ** main()
396  **/
397 
398 int
399 main(int argc, char *argv[])
400 {
401 	int			nin,
402 				nout,
403 				effective_rate,
404 				max_delay	= 0,
405 				n;
406 
407 	int			report_rate;
408 
409 	short			print_rate;
410 
411 	struct stat		in,
412 				out;
413 
414 	struct tms		tms;
415 
416 	long			epoch_start,
417 				epoch_end;
418 
419 	char			*TERM;
420 
421 	int			(*func)(int fd);
422 
423 	/*
424 	 * The Spooler can hit us with SIGTERM for three reasons:
425 	 *
426 	 *	- the user's job has been canceled
427 	 *	- the printer has been disabled while we were printing
428 	 *	- the Spooler heard that the printer has a fault,
429 	 *	  and the fault recovery is wait or beginning
430 	 *
431 	 * We should exit cleanly for the first two cases,
432 	 * but we have to be careful with the last. If it was THIS
433 	 * PROGRAM that told the Spooler about the fault, we must
434 	 * exit consistently.
435 	 *
436 	 * The method of avoiding any problem is to turn off the
437 	 * trapping of SIGTERM before telling the Spooler about
438 	 * the fault.
439 	 *
440 	 * Faults that we can detect:
441 	 *	- hangup (drop of carrier)
442 	 *	- interrupt (printer sent a break or quit character)
443 	 *	- SIGPIPE (output port is a FIFO, and was closed early)
444 	 *	- failed or incomplete write()
445 	 *	- excess delay in write() (handled with SIGALRM later)
446 	 *
447 	 * Pseudo-faults (errors in use):
448 	 *	- No input/output, or strange input/output
449 	 *	- Input/output identical
450 	 *	- No TERM defined or trouble reading Terminfo database
451 	 */
452 	signal (SIGTERM, sigterm);
453 	signal (SIGHUP, sighup);
454 	signal (SIGINT, sigint);
455 	signal (SIGQUIT, sigint);
456 	signal (SIGPIPE, sigpipe);
457 
458 
459 	if (argc > 1 && STREQU(argv[1], "-r")) {
460 		report_rate = 1;
461 		argc--;
462 		argv++;
463 	} else
464 		report_rate = 0;
465 
466 	(void) setlocale(LC_ALL, "");
467 #if !defined(TEXT_DOMAIN)
468 #define TEXT_DOMAIN "SYS_TEST"
469 #endif
470 	(void) textdomain(TEXT_DOMAIN);
471 
472 	/*
473 	 * Stat the standard output to be sure it is defined.
474 	 */
475 	if (fstat(1, &out) < 0) {
476 		signal (SIGTERM, SIG_IGN);
477 		fprintf (
478 			stderr,
479 		gettext("Can't stat output (%s);\nincorrect use of lp.cat!\n"),
480 			PERROR
481 		);
482 		exit (E_BAD_OUTPUT);
483 	}
484 
485 	/*
486 	 * Stat the standard input to be sure it is defined.
487 	 */
488 	if (fstat(0, &in) < 0) {
489 		signal (SIGTERM, SIG_IGN);
490 		fprintf (
491 			stderr,
492 		gettext("Can't stat input (%s);\nincorrect use of lp.cat!\n"),
493 			PERROR
494 		);
495 		exit (E_BAD_INPUT);
496 	}
497 
498 	/*
499 	 * If the standard output is not a character special file or a
500 	 * block special file, make sure it is not identical to the
501 	 * standard input.
502 	 *
503 	 * If we are an ecpp parallel port in centronics mode treat
504 	 * ourselves as a bpp compatible device.
505 	 */
506 
507 	if (is_a_prnio(1)) {
508 		func = prnio_state;
509 	} else if (is_a_parallel_bpp(1) ||
510 		    (get_ecpp_status(1) == ECPP_CENTRONICS)) {
511 		func = bpp_state;
512         } else if (isatty(1)) {
513 		/* serial connection (probably) - continue as usual */
514 		func = nop;
515         } else {
516 		func = nop;
517         }
518 
519 	if (!ISCHR(out) && !ISBLK(out) && IDENTICAL(out, in)) {
520 		signal (SIGTERM, SIG_IGN);
521 		fprintf (
522 			stderr,
523 	gettext("Input and output are identical; incorrect use of lp.cat!\n")
524 		);
525 		exit (E_IDENTICAL);
526 	}
527 
528 	/*
529 	 * The effective data transfer rate is the lesser
530 	 * of the transmission rate and print rate. If an
531 	 * argument was passed to us, it should be a data
532 	 * rate and it may be lower still.
533 	 * Based on the effective data transfer rate,
534 	 * we can predict the maximum delay we should experience.
535 	 * But there are other factors that could introduce
536 	 * delay, so let's be generous; after all, we'd rather
537 	 * err in favor of waiting too long to detect a fault
538 	 * than err too often on false alarms.
539 	 */
540 
541 	if (
542 		!(TERM = getenv("TERM"))
543 	     || !*TERM
544 	) {
545 		signal (SIGTERM, SIG_IGN);
546 		fprintf (
547 			stderr,
548 	gettext("No TERM variable defined! Trouble with the Spooler!\n")
549 		);
550 		exit (E_BAD_TERM);
551 	}
552 	if (
553 		!STREQU(TERM, NAME_UNKNOWN)
554 	     && tidbit(TERM, "cps", &print_rate) == -1
555 	) {
556 		signal (SIGTERM, SIG_IGN);
557 		fprintf (
558 			stderr,
559 gettext("Trouble identifying printer type \"%s\"; check the Terminfo database.\n"),
560 			TERM
561 		);
562 		exit (E_BAD_TERM);
563 	}
564 	if (STREQU(TERM, NAME_UNKNOWN))
565 		print_rate = -1;
566 
567 	effective_rate = baudrate() / 10; /* okay for most bauds */
568 	if (print_rate != -1 && print_rate < effective_rate)
569 		effective_rate = print_rate;
570 	if (argc > 1 && (n = atoi(argv[1])) >= 0 && n < effective_rate)
571 		effective_rate = n;	  /* 0 means infinite delay */
572 	if (effective_rate)
573 		max_delay = DELAY(BUFSIZ, effective_rate);
574 
575 	/*
576 	 * We'll use the "alarm()" system call to keep us from
577 	 * waiting too long to write to a printer in trouble.
578 	 */
579 	if (max_delay)
580 		signal (SIGALRM, sigalrm);
581 
582 	/*
583 	 * While not end of standard input, copy blocks to
584 	 * standard output.
585 	 */
586 	while ((nin = read(0, buffer, BUFSIZ)) > 0) {
587 		char *ptr = buffer;
588 
589 		/*
590 		 * We should be safe from incomplete writes to a full
591 		 * pipe, as long as the size of the buffer we write is
592 		 * a even divisor of the pipe buffer limit. As long as
593 		 * we read from files or pipes (not communication devices)
594 		 * this should be true for all but the last buffer. The
595 		 * last will be smaller, and won't straddle the pipe max
596 		 * limit (think about it).
597 		 */
598 #if	PIPE_BUF < BUFSIZ || (PIPE_MAX % BUFSIZ)
599 		this_wont_compile;
600 #endif
601 		if (report_rate)
602 			epoch_start = times(&tms);
603 		do {
604 			wait_state(1, func);
605 
606 			if (max_delay)
607 				alarm (max_delay);
608 			nout = write(1, ptr, nin);
609 			alarm(0);
610 			if (nout < 0) {
611 				fprintf (
612 					stderr,
613 	gettext("Write failed (%s);\nperhaps the printer has gone off-line.\n"),
614 					PERROR
615 				);
616 				fflush(stderr);
617 				if (errno != EINTR)
618 				/* I/O error on device, get lpcshed to retry */
619 					exit(PRINTER_IO_ERROR);
620 				else /* wait for printer to come back online */
621 					sleep(15);
622 			} else {
623 				nin -= nout;
624 				ptr += nout;
625 			}
626 		} while (nin > 0);
627 
628 		if (max_delay)
629 			alarm (0);
630 		else if (report_rate) {
631 			epoch_end = times(&tms);
632 			if (epoch_end - epoch_start > 0)
633 				fprintf (
634 					stderr,
635 					"%d CPS\n",
636 		R((100 * BUFSIZ) / (double)(epoch_end - epoch_start))
637 				);
638 		}
639 
640 	}
641 
642 	return (E_SUCCESS);
643 }
644 
645 /**
646  ** sighup() - CATCH A HANGUP (LOSS OF CARRIER)
647  **/
648 
649 void			sighup ()
650 {
651 	signal (SIGTERM, SIG_IGN);
652 	signal (SIGHUP, SIG_IGN);
653 	fprintf (stderr, gettext(HANGUP_FAULT_LPCAT));
654 	exit (E_HANGUP);
655 }
656 
657 /**
658  ** sigint() - CATCH AN INTERRUPT
659  **/
660 
661 void			sigint ()
662 {
663 	signal (SIGTERM, SIG_IGN);
664 	signal (SIGINT, SIG_IGN);
665 	fprintf (stderr, gettext(INTERRUPT_FAULT));
666 	exit (E_INTERRUPT);
667 }
668 
669 /**
670  ** sigpipe() - CATCH EARLY CLOSE OF PIPE
671  **/
672 
673 void			sigpipe ()
674 {
675 	signal (SIGTERM, SIG_IGN);
676 	signal (SIGPIPE, SIG_IGN);
677 	fprintf (stderr, gettext(PIPE_FAULT));
678 	exit (E_INTERRUPT);
679 }
680 
681 /**
682  ** sigalrm() - CATCH AN ALARM
683  **/
684 
685 void			sigalrm ()
686 {
687 	signal (SIGTERM, SIG_IGN);
688 	fprintf (
689 		stderr,
690 	gettext("Excessive write delay; perhaps the printer has gone off-line.\n")
691 	);
692 	exit (E_TIMEOUT);
693 }
694 
695 /**
696  ** sigterm() - CATCH A TERMINATION SIGNAL
697  **/
698 
699 void			sigterm ()
700 {
701 	signal (SIGTERM, SIG_IGN);
702 	/*
703 	 * try to flush the output queue in the case of ecpp port.
704 	 * ignore the return code as this may not be the ecpp.
705 	 */
706 	ioctl(1, I_FLUSH, FLUSHW);
707 	exit (E_SUCCESS);
708 }
709 
710 /**
711  ** baudrate() - RETURN BAUD RATE OF OUTPUT LINE
712  **/
713 
714 static int		baud_convert[] =
715 {
716 	0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
717 	1800, 2400, 4800, 9600, 19200, 38400, 57600,
718 	76800, 115200, 153600, 230400, 307200, 460800
719 };
720 
721 int			baudrate ()
722 {
723 	struct termio		tm;
724 	struct termios		tms;
725 	int			speed;
726 
727 	if (ioctl(1, TCGETS, &tms) < 0) {
728 		if (ioctl(1, TCGETA, &tm) < 0)
729 			return (1200);
730 		else
731 			speed = tm.c_cflag&CBAUD;
732 	} else
733 		speed = cfgetospeed(&tms);
734 
735 	return (speed ? baud_convert[speed] : 1200);
736 }
737