xref: /illumos-gate/usr/src/cmd/lp/model/lp.cat.c (revision d9c3e05c)
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 	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