xref: /titanic_52/usr/src/cmd/lp/model/lp.cat.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
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 1989-2002 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 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include "stdio.h"
34 #include "termio.h"
35 #include "sys/types.h"
36 #include "errno.h"
37 #include "signal.h"
38 #include "sys/times.h"
39 #include "string.h"
40 #include "limits.h"
41 #include <sys/prnio.h>
42 
43 #include "lp.h"
44 
45 #include <locale.h>
46 
47 /**
48  **	Begin Sun Additions for Parallel ports
49  **/
50 
51 extern char *_sys_errlist[];
52 #include <string.h>
53 #include <stdarg.h>
54 #include <signal.h>
55 #include <unistd.h>
56 #include <sys/types.h>
57 #include <sys/ioccom.h>
58 #include <sys/ioctl.h>
59 
60 #include <sys/bpp_io.h>
61 #include <sys/ecppsys.h>
62 #include <stropts.h>
63 
64 /*
65  * the parameter structure for the parallel port
66  */
67 struct ppc_params_t {
68 	int		flags;		/* same as above */
69 	int		state;		/* status of the printer interface */
70 	int		strobe_w;	/* strobe width, in uS */
71 	int		data_setup;	/* data setup time, in uS */
72 	int		ack_timeout;	/* ACK timeout, in secs */
73 	int		error_timeout;	/* PAPER OUT, etc... timeout, in secs */
74 	int		busy_timeout;	/* BUSY timeout, in seconds */
75 };
76 
77 
78 
79 static void printer_info(char *fmt, ...);
80 
81 /*	These are the routines avaliable to others for use 	*/
82 int is_a_parallel_bpp(int);
83 int bpp_state(int);
84 int parallel_comm(int, int());
85 int get_ecpp_status(int fd);
86 int is_a_prnio(int);
87 int prnio_state(int);
88 
89 #define PRINTER_ERROR_PAPER_OUT		1
90 #define PRINTER_ERROR_OFFLINE		2
91 #define PRINTER_ERROR_BUSY		3
92 #define PRINTER_ERROR_ERROR		4
93 #define PRINTER_ERROR_CABLE_POWER	5
94 #define PRINTER_ERROR_UNKNOWN		6
95 #define PRINTER_ERROR_TIMEOUT		7
96 #define	PRINTER_IO_ERROR		129
97 
98 
99 /****************************************************************************/
100 
101 /**
102  *	for BPP PARALLEL interfaces
103  **/
104 
105 int is_a_parallel_bpp(int fd)
106 {
107 	if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
108 		return(1);
109 	return(0);
110 }
111 
112 
113 #if defined(DEBUG) && defined(NOTDEF)
114 char *BppState(int state)
115 {
116 	static char buf[BUFSIZ];
117 
118 	memset(buf, 0, sizeof(buf));
119 	sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
120 		((state & BPP_SLCT_ERR) ?  "offline " : ""),
121 		((state & BPP_BUSY_ERR) ?  "busy " : ""),
122 		((state & BPP_PE_ERR) ?  "paper " : ""),
123 		((state & BPP_ERR_ERR) ?  "error " : ""));
124 
125 	return(buf);
126 }
127 #endif
128 
129 int bpp_state(int fd)
130 {
131 	if (ioctl(fd, BPPIOC_TESTIO)) {
132 		struct bpp_error_status  bpp_stat;
133 		int state;
134 
135 		if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
136 			exit(PRINTER_IO_ERROR);
137 		state = bpp_stat.pin_status;
138 
139 #if defined(DEBUG) && defined(NOTDEF)
140 		logit("%s", BppState(state));
141 #endif
142 
143 		if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
144 			/* paper is out */
145 			return(PRINTER_ERROR_PAPER_OUT);
146 		} else if (state & BPP_BUSY_ERR) {
147 			/* printer is busy */
148 			return(PRINTER_ERROR_BUSY);
149 		} else if (state & BPP_SLCT_ERR) {
150 			/* printer is offline */
151 			return(PRINTER_ERROR_OFFLINE);
152 		} else if (state & BPP_ERR_ERR) {
153 			/* printer is errored */
154 			return(PRINTER_ERROR_ERROR);
155 		} else if (state == BPP_PE_ERR) {
156 			/* printer is off/unplugged */
157 			return(PRINTER_ERROR_CABLE_POWER);
158 		} else if (state) {
159 			return(PRINTER_ERROR_UNKNOWN);
160 		} else
161 			return(0);
162 	}
163 	return(0);
164 }
165 
166 /*
167  * For ecpp parallel port
168  */
169 
170 int
171 get_ecpp_status(int fd)
172 {
173 	int state;
174 	struct ecpp_transfer_parms transfer_parms;
175 
176 
177 	if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
178 		return(-1);
179 	}
180 
181 	state = transfer_parms.mode;
182 	/*
183 	 * We don't know what all printers will return in
184 	 * nibble mode, therefore if we support nibble mode we will
185 	 * force the printer to be in CENTRONICS mode.
186 	 */
187 	if (state != ECPP_CENTRONICS) {
188 		transfer_parms.mode = ECPP_CENTRONICS;
189 		if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
190 			return(-1);
191 		} else {
192 			state = ECPP_CENTRONICS;
193 		}
194 	}
195 
196 
197 	return(state);
198 }
199 
200 /**
201  * For prnio(7I) - generic printer interface
202  **/
203 int is_a_prnio(int fd)
204 {
205 	uint_t	cap;
206 
207 	/* check if device supports prnio */
208 	if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
209 		return (0);
210 	}
211 	/* we will use 1284 status if available */
212 	if ((cap & PRN_1284_STATUS) == 0) {
213 		/* some devices may only support 1284 status in unidir. mode */
214 		if (cap & PRN_BIDI) {
215 			cap &= ~PRN_BIDI;
216 			(void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
217 		}
218 	}
219 	return (1);
220 }
221 
222 int 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
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
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
295 printer_error(int error)
296 {
297 	switch (error) {
298 		case -1:
299 			printer_info("ioctl(): %s", _sys_errlist[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
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 extern int		sys_nerr;
369 
370 extern char		*sys_errlist[],
371 			*getenv();
372 
373 extern int		atoi();
374 
375 char			buffer[BUFSIZ];
376 
377 void			sighup(),
378 			sigint(),
379 			sigquit(),
380 			sigpipe(),
381 			sigalrm(),
382 			sigterm();
383 
384 #if	defined(baudrate)
385 # undef	baudrate
386 #endif
387 
388 int			baudrate();
389 
390 
391 int nop(int fd) { return (0); }
392 int bpp_state(int);
393 
394 
395 /**
396  ** main()
397  **/
398 
399 int			main (argc, argv)
400 	int			argc;
401 	char			*argv[];
402 {
403 	register int		nin,
404 				nout,
405 				effective_rate,
406 				max_delay	= 0,
407 				n;
408 
409 	int			report_rate;
410 
411 	short			print_rate;
412 
413 	struct stat		in,
414 				out;
415 
416 	struct tms		tms;
417 
418 	long			epoch_start,
419 				epoch_end;
420 
421 	char			*TERM;
422 
423 	int			(*func)(int fd);
424 
425 	/*
426 	 * The Spooler can hit us with SIGTERM for three reasons:
427 	 *
428 	 *	- the user's job has been canceled
429 	 *	- the printer has been disabled while we were printing
430 	 *	- the Spooler heard that the printer has a fault,
431 	 *	  and the fault recovery is wait or beginning
432 	 *
433 	 * We should exit cleanly for the first two cases,
434 	 * but we have to be careful with the last. If it was THIS
435 	 * PROGRAM that told the Spooler about the fault, we must
436 	 * exit consistently.
437 	 *
438 	 * The method of avoiding any problem is to turn off the
439 	 * trapping of SIGTERM before telling the Spooler about
440 	 * the fault.
441 	 *
442 	 * Faults that we can detect:
443 	 *	- hangup (drop of carrier)
444 	 *	- interrupt (printer sent a break or quit character)
445 	 *	- SIGPIPE (output port is a FIFO, and was closed early)
446 	 *	- failed or incomplete write()
447 	 *	- excess delay in write() (handled with SIGALRM later)
448 	 *
449 	 * Pseudo-faults (errors in use):
450 	 *	- No input/output, or strange input/output
451 	 *	- Input/output identical
452 	 *	- No TERM defined or trouble reading Terminfo database
453 	 */
454 	signal (SIGTERM, sigterm);
455 	signal (SIGHUP, sighup);
456 	signal (SIGINT, sigint);
457 	signal (SIGQUIT, sigint);
458 	signal (SIGPIPE, sigpipe);
459 
460 
461 	if (argc > 1 && STREQU(argv[1], "-r")) {
462 		report_rate = 1;
463 		argc--;
464 		argv++;
465 	} else
466 		report_rate = 0;
467 
468 	(void) setlocale(LC_ALL, "");
469 #if !defined(TEXT_DOMAIN)
470 #define TEXT_DOMAIN "SYS_TEST"
471 #endif
472 	(void) textdomain(TEXT_DOMAIN);
473 
474 	/*
475 	 * Stat the standard output to be sure it is defined.
476 	 */
477 	if (fstat(1, &out) < 0) {
478 		signal (SIGTERM, SIG_IGN);
479 		fprintf (
480 			stderr,
481 		gettext("Can't stat output (%s);\nincorrect use of lp.cat!\n"),
482 			PERROR
483 		);
484 		exit (E_BAD_OUTPUT);
485 	}
486 
487 	/*
488 	 * Stat the standard input to be sure it is defined.
489 	 */
490 	if (fstat(0, &in) < 0) {
491 		signal (SIGTERM, SIG_IGN);
492 		fprintf (
493 			stderr,
494 		gettext("Can't stat input (%s);\nincorrect use of lp.cat!\n"),
495 			PERROR
496 		);
497 		exit (E_BAD_INPUT);
498 	}
499 
500 	/*
501 	 * If the standard output is not a character special file or a
502 	 * block special file, make sure it is not identical to the
503 	 * standard input.
504 	 *
505 	 * If we are an ecpp parallel port in centronics mode treat
506 	 * ourselves as a bpp compatible device.
507 	 */
508 
509 	if (is_a_prnio(1)) {
510 		func = prnio_state;
511 	} else if (is_a_parallel_bpp(1) ||
512 		    (get_ecpp_status(1) == ECPP_CENTRONICS)) {
513 		func = bpp_state;
514         } else if (isatty(1)) {
515 		/* serial connection (probably) - continue as usual */
516 		func = nop;
517         } else {
518 		func = nop;
519         }
520 
521 	if (!ISCHR(out) && !ISBLK(out) && IDENTICAL(out, in)) {
522 		signal (SIGTERM, SIG_IGN);
523 		fprintf (
524 			stderr,
525 	gettext("Input and output are identical; incorrect use of lp.cat!\n")
526 		);
527 		exit (E_IDENTICAL);
528 	}
529 
530 	/*
531 	 * The effective data transfer rate is the lesser
532 	 * of the transmission rate and print rate. If an
533 	 * argument was passed to us, it should be a data
534 	 * rate and it may be lower still.
535 	 * Based on the effective data transfer rate,
536 	 * we can predict the maximum delay we should experience.
537 	 * But there are other factors that could introduce
538 	 * delay, so let's be generous; after all, we'd rather
539 	 * err in favor of waiting too long to detect a fault
540 	 * than err too often on false alarms.
541 	 */
542 
543 	if (
544 		!(TERM = getenv("TERM"))
545 	     || !*TERM
546 	) {
547 		signal (SIGTERM, SIG_IGN);
548 		fprintf (
549 			stderr,
550 	gettext("No TERM variable defined! Trouble with the Spooler!\n")
551 		);
552 		exit (E_BAD_TERM);
553 	}
554 	if (
555 		!STREQU(TERM, NAME_UNKNOWN)
556 	     && tidbit(TERM, "cps", &print_rate) == -1
557 	) {
558 		signal (SIGTERM, SIG_IGN);
559 		fprintf (
560 			stderr,
561 gettext("Trouble identifying printer type \"%s\"; check the Terminfo database.\n"),
562 			TERM
563 		);
564 		exit (E_BAD_TERM);
565 	}
566 	if (STREQU(TERM, NAME_UNKNOWN))
567 		print_rate = -1;
568 
569 	effective_rate = baudrate() / 10; /* okay for most bauds */
570 	if (print_rate != -1 && print_rate < effective_rate)
571 		effective_rate = print_rate;
572 	if (argc > 1 && (n = atoi(argv[1])) >= 0 && n < effective_rate)
573 		effective_rate = n;	  /* 0 means infinite delay */
574 	if (effective_rate)
575 		max_delay = DELAY(BUFSIZ, effective_rate);
576 
577 	/*
578 	 * We'll use the "alarm()" system call to keep us from
579 	 * waiting too long to write to a printer in trouble.
580 	 */
581 	if (max_delay)
582 		signal (SIGALRM, sigalrm);
583 
584 	/*
585 	 * While not end of standard input, copy blocks to
586 	 * standard output.
587 	 */
588 	while ((nin = read(0, buffer, BUFSIZ)) > 0) {
589 		char *ptr = buffer;
590 
591 		/*
592 		 * We should be safe from incomplete writes to a full
593 		 * pipe, as long as the size of the buffer we write is
594 		 * a even divisor of the pipe buffer limit. As long as
595 		 * we read from files or pipes (not communication devices)
596 		 * this should be true for all but the last buffer. The
597 		 * last will be smaller, and won't straddle the pipe max
598 		 * limit (think about it).
599 		 */
600 #if	PIPE_BUF < BUFSIZ || (PIPE_MAX % BUFSIZ)
601 		this_wont_compile;
602 #endif
603 		if (report_rate)
604 			epoch_start = times(&tms);
605 		do {
606 			wait_state(1, func);
607 
608 			if (max_delay)
609 				alarm (max_delay);
610 			nout = write(1, ptr, nin);
611 			alarm(0);
612 			if (nout < 0) {
613 				fprintf (
614 					stderr,
615 	gettext("Write failed (%s);\nperhaps the printer has gone off-line.\n"),
616 					PERROR
617 				);
618 				fflush(stderr);
619 				if (errno != EINTR)
620 				/* I/O error on device, get lpcshed to retry */
621 					exit(PRINTER_IO_ERROR);
622 				else /* wait for printer to come back online */
623 					sleep(15);
624 			} else {
625 				nin -= nout;
626 				ptr += nout;
627 			}
628 		} while (nin > 0);
629 
630 		if (max_delay)
631 			alarm (0);
632 		else if (report_rate) {
633 			epoch_end = times(&tms);
634 			if (epoch_end - epoch_start > 0)
635 				fprintf (
636 					stderr,
637 					"%d CPS\n",
638 		R((100 * BUFSIZ) / (double)(epoch_end - epoch_start))
639 				);
640 		}
641 
642 	}
643 
644 	exit (E_SUCCESS);
645 	/*NOTREACHED*/
646 }
647 
648 /**
649  ** sighup() - CATCH A HANGUP (LOSS OF CARRIER)
650  **/
651 
652 void			sighup ()
653 {
654 	signal (SIGTERM, SIG_IGN);
655 	signal (SIGHUP, SIG_IGN);
656 	fprintf (stderr, gettext(HANGUP_FAULT_LPCAT));
657 	exit (E_HANGUP);
658 }
659 
660 /**
661  ** sigint() - CATCH AN INTERRUPT
662  **/
663 
664 void			sigint ()
665 {
666 	signal (SIGTERM, SIG_IGN);
667 	signal (SIGINT, SIG_IGN);
668 	fprintf (stderr, gettext(INTERRUPT_FAULT));
669 	exit (E_INTERRUPT);
670 }
671 
672 /**
673  ** sigpipe() - CATCH EARLY CLOSE OF PIPE
674  **/
675 
676 void			sigpipe ()
677 {
678 	signal (SIGTERM, SIG_IGN);
679 	signal (SIGPIPE, SIG_IGN);
680 	fprintf (stderr, gettext(PIPE_FAULT));
681 	exit (E_INTERRUPT);
682 }
683 
684 /**
685  ** sigalrm() - CATCH AN ALARM
686  **/
687 
688 void			sigalrm ()
689 {
690 	signal (SIGTERM, SIG_IGN);
691 	fprintf (
692 		stderr,
693 	gettext("Excessive write delay; perhaps the printer has gone off-line.\n")
694 	);
695 	exit (E_TIMEOUT);
696 }
697 
698 /**
699  ** sigterm() - CATCH A TERMINATION SIGNAL
700  **/
701 
702 void			sigterm ()
703 {
704 	signal (SIGTERM, SIG_IGN);
705 	/*
706 	 * try to flush the output queue in the case of ecpp port.
707 	 * ignore the return code as this may not be the ecpp.
708 	 */
709 	ioctl(1, I_FLUSH, FLUSHW);
710 	exit (E_SUCCESS);
711 }
712 
713 /**
714  ** baudrate() - RETURN BAUD RATE OF OUTPUT LINE
715  **/
716 
717 static int		baud_convert[] =
718 {
719 	0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
720 	1800, 2400, 4800, 9600, 19200, 38400, 57600,
721 	76800, 115200, 153600, 230400, 307200, 460800
722 };
723 
724 int			baudrate ()
725 {
726 	struct termio		tm;
727 	struct termios		tms;
728 	int			speed;
729 
730 	if (ioctl(1, TCGETS, &tms) < 0) {
731 		if (ioctl(1, TCGETA, &tm) < 0)
732 			return (1200);
733 		else
734 			speed = tm.c_cflag&CBAUD;
735 	} else
736 		speed = cfgetospeed(&tms);
737 
738 	return (speed ? baud_convert[speed] : 1200);
739 }
740