xref: /illumos-gate/usr/src/cmd/lp/model/lp.cat.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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 *
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
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
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
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
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
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", 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
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
385 nop(int fd)
386 {
387 	return (0);
388 }
389 
390 int bpp_state(int);
391 
392 
393 /*
394  * main()
395  */
396 
397 int
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
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
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
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
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
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
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