17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5de81e71eSTim Marsland * Common Development and Distribution License (the "License").
6de81e71eSTim Marsland * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21de81e71eSTim Marsland
227c478bd9Sstevel@tonic-gate /*
23de81e71eSTim Marsland * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate
30ace1a5f1Sdp #include <stdio.h>
31ace1a5f1Sdp #include <stdlib.h>
32ace1a5f1Sdp #include <termio.h>
33ace1a5f1Sdp #include <sys/types.h>
34ace1a5f1Sdp #include <errno.h>
35ace1a5f1Sdp #include <signal.h>
36ace1a5f1Sdp #include <sys/times.h>
37ace1a5f1Sdp #include <string.h>
38ace1a5f1Sdp #include <limits.h>
397c478bd9Sstevel@tonic-gate #include <sys/prnio.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #include "lp.h"
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate #include <locale.h>
447c478bd9Sstevel@tonic-gate
45de81e71eSTim Marsland /*
46de81e71eSTim Marsland * Begin Sun Additions for Parallel ports
47de81e71eSTim Marsland */
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include <string.h>
507c478bd9Sstevel@tonic-gate #include <stdarg.h>
517c478bd9Sstevel@tonic-gate #include <signal.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate #include <sys/types.h>
547c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
557c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate #include <sys/bpp_io.h>
587c478bd9Sstevel@tonic-gate #include <sys/ecppsys.h>
597c478bd9Sstevel@tonic-gate #include <stropts.h>
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate * the parameter structure for the parallel port
637c478bd9Sstevel@tonic-gate */
647c478bd9Sstevel@tonic-gate struct ppc_params_t {
657c478bd9Sstevel@tonic-gate int flags; /* same as above */
667c478bd9Sstevel@tonic-gate int state; /* status of the printer interface */
677c478bd9Sstevel@tonic-gate int strobe_w; /* strobe width, in uS */
687c478bd9Sstevel@tonic-gate int data_setup; /* data setup time, in uS */
697c478bd9Sstevel@tonic-gate int ack_timeout; /* ACK timeout, in secs */
707c478bd9Sstevel@tonic-gate int error_timeout; /* PAPER OUT, etc... timeout, in secs */
717c478bd9Sstevel@tonic-gate int busy_timeout; /* BUSY timeout, in seconds */
727c478bd9Sstevel@tonic-gate };
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate static void printer_info(char *fmt, ...);
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /* These are the routines avaliable to others for use */
797c478bd9Sstevel@tonic-gate int is_a_parallel_bpp(int);
807c478bd9Sstevel@tonic-gate int bpp_state(int);
817c478bd9Sstevel@tonic-gate int parallel_comm(int, int());
827c478bd9Sstevel@tonic-gate int get_ecpp_status(int fd);
837c478bd9Sstevel@tonic-gate int is_a_prnio(int);
847c478bd9Sstevel@tonic-gate int prnio_state(int);
857c478bd9Sstevel@tonic-gate
86de81e71eSTim Marsland #define PRINTER_ERROR_PAPER_OUT 1
87de81e71eSTim Marsland #define PRINTER_ERROR_OFFLINE 2
88de81e71eSTim Marsland #define PRINTER_ERROR_BUSY 3
89de81e71eSTim Marsland #define PRINTER_ERROR_ERROR 4
90de81e71eSTim Marsland #define PRINTER_ERROR_CABLE_POWER 5
91de81e71eSTim Marsland #define PRINTER_ERROR_UNKNOWN 6
92de81e71eSTim Marsland #define PRINTER_ERROR_TIMEOUT 7
937c478bd9Sstevel@tonic-gate #define PRINTER_IO_ERROR 129
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate
96de81e71eSTim Marsland /*
977c478bd9Sstevel@tonic-gate * for BPP PARALLEL interfaces
98de81e71eSTim Marsland */
997c478bd9Sstevel@tonic-gate
100de81e71eSTim Marsland int
is_a_parallel_bpp(int fd)101de81e71eSTim Marsland is_a_parallel_bpp(int fd)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
104de81e71eSTim Marsland return (1);
105de81e71eSTim Marsland return (0);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate #if defined(DEBUG) && defined(NOTDEF)
110de81e71eSTim Marsland char *
BppState(int state)111de81e71eSTim Marsland BppState(int state)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate static char buf[BUFSIZ];
1147c478bd9Sstevel@tonic-gate
115de81e71eSTim Marsland memset(buf, 0, sizeof (buf));
116de81e71eSTim Marsland sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
117de81e71eSTim Marsland ((state & BPP_SLCT_ERR) ? "offline " : ""),
118de81e71eSTim Marsland ((state & BPP_BUSY_ERR) ? "busy " : ""),
119de81e71eSTim Marsland ((state & BPP_PE_ERR) ? "paper " : ""),
120de81e71eSTim Marsland ((state & BPP_ERR_ERR) ? "error " : ""));
1217c478bd9Sstevel@tonic-gate
122de81e71eSTim Marsland return (buf);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate #endif
1257c478bd9Sstevel@tonic-gate
126de81e71eSTim Marsland int
bpp_state(int fd)127de81e71eSTim Marsland bpp_state(int fd)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate if (ioctl(fd, BPPIOC_TESTIO)) {
1307c478bd9Sstevel@tonic-gate struct bpp_error_status bpp_stat;
1317c478bd9Sstevel@tonic-gate int state;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
1347c478bd9Sstevel@tonic-gate exit(PRINTER_IO_ERROR);
1357c478bd9Sstevel@tonic-gate state = bpp_stat.pin_status;
1367c478bd9Sstevel@tonic-gate
137de81e71eSTim Marsland #if defined(DEBUG) && defined(NOTDEF)
1387c478bd9Sstevel@tonic-gate logit("%s", BppState(state));
1397c478bd9Sstevel@tonic-gate #endif
140de81e71eSTim Marsland
1417c478bd9Sstevel@tonic-gate if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
1427c478bd9Sstevel@tonic-gate /* paper is out */
143de81e71eSTim Marsland return (PRINTER_ERROR_PAPER_OUT);
1447c478bd9Sstevel@tonic-gate } else if (state & BPP_BUSY_ERR) {
1457c478bd9Sstevel@tonic-gate /* printer is busy */
146de81e71eSTim Marsland return (PRINTER_ERROR_BUSY);
1477c478bd9Sstevel@tonic-gate } else if (state & BPP_SLCT_ERR) {
1487c478bd9Sstevel@tonic-gate /* printer is offline */
149de81e71eSTim Marsland return (PRINTER_ERROR_OFFLINE);
1507c478bd9Sstevel@tonic-gate } else if (state & BPP_ERR_ERR) {
1517c478bd9Sstevel@tonic-gate /* printer is errored */
152de81e71eSTim Marsland return (PRINTER_ERROR_ERROR);
1537c478bd9Sstevel@tonic-gate } else if (state == BPP_PE_ERR) {
1547c478bd9Sstevel@tonic-gate /* printer is off/unplugged */
155de81e71eSTim Marsland return (PRINTER_ERROR_CABLE_POWER);
1567c478bd9Sstevel@tonic-gate } else if (state) {
157de81e71eSTim Marsland return (PRINTER_ERROR_UNKNOWN);
1587c478bd9Sstevel@tonic-gate } else
159de81e71eSTim Marsland return (0);
1607c478bd9Sstevel@tonic-gate }
161de81e71eSTim Marsland return (0);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate * For ecpp parallel port
1667c478bd9Sstevel@tonic-gate */
1677c478bd9Sstevel@tonic-gate
168de81e71eSTim Marsland int
get_ecpp_status(int fd)1697c478bd9Sstevel@tonic-gate get_ecpp_status(int fd)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate int state;
1727c478bd9Sstevel@tonic-gate struct ecpp_transfer_parms transfer_parms;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
176de81e71eSTim Marsland return (-1);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate state = transfer_parms.mode;
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * We don't know what all printers will return in
1827c478bd9Sstevel@tonic-gate * nibble mode, therefore if we support nibble mode we will
1837c478bd9Sstevel@tonic-gate * force the printer to be in CENTRONICS mode.
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate if (state != ECPP_CENTRONICS) {
1867c478bd9Sstevel@tonic-gate transfer_parms.mode = ECPP_CENTRONICS;
1877c478bd9Sstevel@tonic-gate if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
188de81e71eSTim Marsland return (-1);
1897c478bd9Sstevel@tonic-gate } else {
1907c478bd9Sstevel@tonic-gate state = ECPP_CENTRONICS;
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
194de81e71eSTim Marsland
195de81e71eSTim Marsland return (state);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate
198de81e71eSTim Marsland /*
199*bbf21555SRichard Lowe * For prnio(4I) - generic printer interface
200de81e71eSTim Marsland */
201de81e71eSTim Marsland int
is_a_prnio(int fd)202de81e71eSTim Marsland is_a_prnio(int fd)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate uint_t cap;
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate /* check if device supports prnio */
2077c478bd9Sstevel@tonic-gate if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
2087c478bd9Sstevel@tonic-gate return (0);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate /* we will use 1284 status if available */
2117c478bd9Sstevel@tonic-gate if ((cap & PRN_1284_STATUS) == 0) {
2127c478bd9Sstevel@tonic-gate /* some devices may only support 1284 status in unidir. mode */
2137c478bd9Sstevel@tonic-gate if (cap & PRN_BIDI) {
2147c478bd9Sstevel@tonic-gate cap &= ~PRN_BIDI;
2157c478bd9Sstevel@tonic-gate (void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate return (1);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
221de81e71eSTim Marsland int
prnio_state(int fd)222de81e71eSTim Marsland prnio_state(int fd)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate uint_t status;
2257c478bd9Sstevel@tonic-gate uchar_t pins;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
2287c478bd9Sstevel@tonic-gate (status & PRN_READY)) {
229de81e71eSTim Marsland return (0);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
233de81e71eSTim Marsland return (PRINTER_ERROR_UNKNOWN);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
2377c478bd9Sstevel@tonic-gate /* paper is out */
238de81e71eSTim Marsland return (PRINTER_ERROR_PAPER_OUT);
2397c478bd9Sstevel@tonic-gate } else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
240de81e71eSTim Marsland PRN_1284_NOFAULT | PRN_1284_BUSY)) {
2417c478bd9Sstevel@tonic-gate /* printer is off/unplugged */
242de81e71eSTim Marsland return (PRINTER_ERROR_CABLE_POWER);
2437c478bd9Sstevel@tonic-gate } else if ((pins & PRN_1284_SELECT) == 0) {
2447c478bd9Sstevel@tonic-gate /* printer is offline */
245de81e71eSTim Marsland return (PRINTER_ERROR_OFFLINE);
2467c478bd9Sstevel@tonic-gate } else if ((pins & PRN_1284_NOFAULT) == 0) {
2477c478bd9Sstevel@tonic-gate /* printer is errored */
248de81e71eSTim Marsland return (PRINTER_ERROR_ERROR);
2497c478bd9Sstevel@tonic-gate } else if (pins & PRN_1284_PE) {
2507c478bd9Sstevel@tonic-gate /* paper is out */
251de81e71eSTim Marsland return (PRINTER_ERROR_PAPER_OUT);
2527c478bd9Sstevel@tonic-gate } else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
253de81e71eSTim Marsland return (PRINTER_ERROR_UNKNOWN);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate
256de81e71eSTim Marsland return (0);
2577c478bd9Sstevel@tonic-gate }
258de81e71eSTim Marsland
259de81e71eSTim Marsland /*
2607c478bd9Sstevel@tonic-gate * Common routines
261de81e71eSTim Marsland */
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
2647c478bd9Sstevel@tonic-gate static void
ByeByeParallel(int sig)2657c478bd9Sstevel@tonic-gate ByeByeParallel(int sig)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate /* try to shove out the EOT */
2687c478bd9Sstevel@tonic-gate (void) write(1, "\004", 1);
2697c478bd9Sstevel@tonic-gate exit(0);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
2747c478bd9Sstevel@tonic-gate static void
printer_info(char * fmt,...)2757c478bd9Sstevel@tonic-gate printer_info(char *fmt, ...)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate char mesg[BUFSIZ];
2787c478bd9Sstevel@tonic-gate va_list ap;
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate va_start(ap, fmt);
2817c478bd9Sstevel@tonic-gate vsprintf(mesg, fmt, ap);
2827c478bd9Sstevel@tonic-gate va_end(ap);
2837c478bd9Sstevel@tonic-gate /*
284de81e71eSTim Marsland * fprintf(stderr,
285de81e71eSTim Marsland * "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
286de81e71eSTim Marsland * mesg);
287de81e71eSTim Marsland */
2887c478bd9Sstevel@tonic-gate fprintf(stderr, "%s\n", mesg);
2897c478bd9Sstevel@tonic-gate fflush(stderr);
2907c478bd9Sstevel@tonic-gate fsync(2);
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate static void
printer_error(int error)2957c478bd9Sstevel@tonic-gate printer_error(int error)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate switch (error) {
298de81e71eSTim Marsland case -1:
299de81e71eSTim Marsland printer_info("ioctl(): %s", strerror(errno));
300de81e71eSTim Marsland break;
301de81e71eSTim Marsland case PRINTER_ERROR_PAPER_OUT:
302de81e71eSTim Marsland printer_info("out of paper");
303de81e71eSTim Marsland break;
304de81e71eSTim Marsland case PRINTER_ERROR_OFFLINE:
305de81e71eSTim Marsland printer_info("offline");
306de81e71eSTim Marsland break;
307de81e71eSTim Marsland case PRINTER_ERROR_BUSY:
308de81e71eSTim Marsland printer_info("busy");
309de81e71eSTim Marsland break;
310de81e71eSTim Marsland case PRINTER_ERROR_ERROR:
311de81e71eSTim Marsland printer_info("printer error");
312de81e71eSTim Marsland break;
313de81e71eSTim Marsland case PRINTER_ERROR_CABLE_POWER:
314de81e71eSTim Marsland printer_info("printer powered off or disconnected");
315de81e71eSTim Marsland break;
316de81e71eSTim Marsland case PRINTER_ERROR_UNKNOWN:
317de81e71eSTim Marsland printer_info("unknown error");
318de81e71eSTim Marsland break;
319de81e71eSTim Marsland case PRINTER_ERROR_TIMEOUT:
320de81e71eSTim Marsland printer_info("communications timeout");
321de81e71eSTim Marsland break;
322de81e71eSTim Marsland default:
323de81e71eSTim Marsland printer_info("get_status() failed");
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate static void
wait_state(int fd,int get_state ())3297c478bd9Sstevel@tonic-gate wait_state(int fd, int get_state())
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate int state;
3327c478bd9Sstevel@tonic-gate int was_faulted = 0;
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate while (state = get_state(fd)) {
335de81e71eSTim Marsland was_faulted = 1;
3367c478bd9Sstevel@tonic-gate printer_error(state);
3377c478bd9Sstevel@tonic-gate sleep(15);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate if (was_faulted) {
3417c478bd9Sstevel@tonic-gate fprintf(stderr, "printer ok\n");
3427c478bd9Sstevel@tonic-gate fflush(stderr);
3437c478bd9Sstevel@tonic-gate fsync(2);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
347de81e71eSTim Marsland /*
348de81e71eSTim Marsland * end of Sun Additions for parallel port
349de81e71eSTim Marsland */
350de81e71eSTim Marsland #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
351de81e71eSTim Marsland #define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK)
352de81e71eSTim Marsland #define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR)
353de81e71eSTim Marsland
354de81e71eSTim Marsland #define E_SUCCESS 0
355de81e71eSTim Marsland #define E_BAD_INPUT 1
356de81e71eSTim Marsland #define E_BAD_OUTPUT 2
357de81e71eSTim Marsland #define E_BAD_TERM 3
358de81e71eSTim Marsland #define E_IDENTICAL 4
3597c478bd9Sstevel@tonic-gate #define E_WRITE_FAILED 5
3607c478bd9Sstevel@tonic-gate #define E_TIMEOUT 6
361de81e71eSTim Marsland #define E_HANGUP 7
362de81e71eSTim Marsland #define E_INTERRUPT 8
3637c478bd9Sstevel@tonic-gate
364de81e71eSTim Marsland #define SAFETY_FACTOR 2.0
365de81e71eSTim Marsland #define R(F) (int)((F) + .5)
366de81e71eSTim Marsland #define DELAY(N, D) R(SAFETY_FACTOR * ((N) / (double)(D)))
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate char buffer[BUFSIZ];
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate void sighup(),
3717c478bd9Sstevel@tonic-gate sigint(),
3727c478bd9Sstevel@tonic-gate sigquit(),
3737c478bd9Sstevel@tonic-gate sigpipe(),
3747c478bd9Sstevel@tonic-gate sigalrm(),
3757c478bd9Sstevel@tonic-gate sigterm();
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate #if defined(baudrate)
378de81e71eSTim Marsland #undef baudrate
3797c478bd9Sstevel@tonic-gate #endif
3807c478bd9Sstevel@tonic-gate
381de81e71eSTim Marsland int baudrate();
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate
384de81e71eSTim Marsland int
nop(int fd)385de81e71eSTim Marsland nop(int fd)
386de81e71eSTim Marsland {
387de81e71eSTim Marsland return (0);
388de81e71eSTim Marsland }
389de81e71eSTim Marsland
3907c478bd9Sstevel@tonic-gate int bpp_state(int);
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate
393de81e71eSTim Marsland /*
394de81e71eSTim Marsland * main()
395de81e71eSTim Marsland */
3967c478bd9Sstevel@tonic-gate
397f928ce67Sceastha int
main(int argc,char * argv[])398f928ce67Sceastha main(int argc, char *argv[])
3997c478bd9Sstevel@tonic-gate {
400de81e71eSTim Marsland int nin, nout, effective_rate, max_delay = 0, n;
401de81e71eSTim Marsland int report_rate;
402de81e71eSTim Marsland short print_rate;
403de81e71eSTim Marsland struct stat in, out;
404de81e71eSTim Marsland struct tms tms;
405de81e71eSTim Marsland long epoch_start, epoch_end;
406de81e71eSTim Marsland char *TERM;
407de81e71eSTim Marsland int (*func)(int fd);
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate * The Spooler can hit us with SIGTERM for three reasons:
4117c478bd9Sstevel@tonic-gate *
4127c478bd9Sstevel@tonic-gate * - the user's job has been canceled
4137c478bd9Sstevel@tonic-gate * - the printer has been disabled while we were printing
4147c478bd9Sstevel@tonic-gate * - the Spooler heard that the printer has a fault,
4157c478bd9Sstevel@tonic-gate * and the fault recovery is wait or beginning
4167c478bd9Sstevel@tonic-gate *
4177c478bd9Sstevel@tonic-gate * We should exit cleanly for the first two cases,
4187c478bd9Sstevel@tonic-gate * but we have to be careful with the last. If it was THIS
4197c478bd9Sstevel@tonic-gate * PROGRAM that told the Spooler about the fault, we must
4207c478bd9Sstevel@tonic-gate * exit consistently.
4217c478bd9Sstevel@tonic-gate *
4227c478bd9Sstevel@tonic-gate * The method of avoiding any problem is to turn off the
4237c478bd9Sstevel@tonic-gate * trapping of SIGTERM before telling the Spooler about
4247c478bd9Sstevel@tonic-gate * the fault.
4257c478bd9Sstevel@tonic-gate *
4267c478bd9Sstevel@tonic-gate * Faults that we can detect:
4277c478bd9Sstevel@tonic-gate * - hangup (drop of carrier)
4287c478bd9Sstevel@tonic-gate * - interrupt (printer sent a break or quit character)
4297c478bd9Sstevel@tonic-gate * - SIGPIPE (output port is a FIFO, and was closed early)
4307c478bd9Sstevel@tonic-gate * - failed or incomplete write()
4317c478bd9Sstevel@tonic-gate * - excess delay in write() (handled with SIGALRM later)
4327c478bd9Sstevel@tonic-gate *
4337c478bd9Sstevel@tonic-gate * Pseudo-faults (errors in use):
4347c478bd9Sstevel@tonic-gate * - No input/output, or strange input/output
4357c478bd9Sstevel@tonic-gate * - Input/output identical
4367c478bd9Sstevel@tonic-gate * - No TERM defined or trouble reading Terminfo database
4377c478bd9Sstevel@tonic-gate */
438de81e71eSTim Marsland signal(SIGTERM, sigterm);
439de81e71eSTim Marsland signal(SIGHUP, sighup);
440de81e71eSTim Marsland signal(SIGINT, sigint);
441de81e71eSTim Marsland signal(SIGQUIT, sigint);
442de81e71eSTim Marsland signal(SIGPIPE, sigpipe);
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate if (argc > 1 && STREQU(argv[1], "-r")) {
4467c478bd9Sstevel@tonic-gate report_rate = 1;
4477c478bd9Sstevel@tonic-gate argc--;
4487c478bd9Sstevel@tonic-gate argv++;
4497c478bd9Sstevel@tonic-gate } else
4507c478bd9Sstevel@tonic-gate report_rate = 0;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
4537c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
454de81e71eSTim Marsland #define TEXT_DOMAIN "SYS_TEST"
4557c478bd9Sstevel@tonic-gate #endif
4567c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate * Stat the standard output to be sure it is defined.
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate if (fstat(1, &out) < 0) {
462de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
463de81e71eSTim Marsland fprintf(stderr, gettext("Can't stat output "
464de81e71eSTim Marsland "(%s);\nincorrect use of lp.cat!\n"), PERROR);
465de81e71eSTim Marsland exit(E_BAD_OUTPUT);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate * Stat the standard input to be sure it is defined.
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate if (fstat(0, &in) < 0) {
472de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
473de81e71eSTim Marsland fprintf(stderr, gettext("Can't stat input "
474de81e71eSTim Marsland "(%s);\nincorrect use of lp.cat!\n"), PERROR);
475de81e71eSTim Marsland exit(E_BAD_INPUT);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate * If the standard output is not a character special file or a
4807c478bd9Sstevel@tonic-gate * block special file, make sure it is not identical to the
4817c478bd9Sstevel@tonic-gate * standard input.
4827c478bd9Sstevel@tonic-gate *
4837c478bd9Sstevel@tonic-gate * If we are an ecpp parallel port in centronics mode treat
4847c478bd9Sstevel@tonic-gate * ourselves as a bpp compatible device.
4857c478bd9Sstevel@tonic-gate */
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate if (is_a_prnio(1)) {
4887c478bd9Sstevel@tonic-gate func = prnio_state;
4897c478bd9Sstevel@tonic-gate } else if (is_a_parallel_bpp(1) ||
490de81e71eSTim Marsland (get_ecpp_status(1) == ECPP_CENTRONICS)) {
4917c478bd9Sstevel@tonic-gate func = bpp_state;
492de81e71eSTim Marsland } else if (isatty(1)) {
4937c478bd9Sstevel@tonic-gate /* serial connection (probably) - continue as usual */
4947c478bd9Sstevel@tonic-gate func = nop;
495de81e71eSTim Marsland } else {
4967c478bd9Sstevel@tonic-gate func = nop;
497de81e71eSTim Marsland }
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate if (!ISCHR(out) && !ISBLK(out) && IDENTICAL(out, in)) {
500de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
501de81e71eSTim Marsland fprintf(stderr, gettext("Input and output are identical; "
502de81e71eSTim Marsland "incorrect use of lp.cat!\n"));
503de81e71eSTim Marsland exit(E_IDENTICAL);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate * The effective data transfer rate is the lesser
5087c478bd9Sstevel@tonic-gate * of the transmission rate and print rate. If an
5097c478bd9Sstevel@tonic-gate * argument was passed to us, it should be a data
5107c478bd9Sstevel@tonic-gate * rate and it may be lower still.
5117c478bd9Sstevel@tonic-gate * Based on the effective data transfer rate,
5127c478bd9Sstevel@tonic-gate * we can predict the maximum delay we should experience.
5137c478bd9Sstevel@tonic-gate * But there are other factors that could introduce
5147c478bd9Sstevel@tonic-gate * delay, so let's be generous; after all, we'd rather
5157c478bd9Sstevel@tonic-gate * err in favor of waiting too long to detect a fault
5167c478bd9Sstevel@tonic-gate * than err too often on false alarms.
5177c478bd9Sstevel@tonic-gate */
5187c478bd9Sstevel@tonic-gate
519de81e71eSTim Marsland if (!(TERM = getenv("TERM")) || !*TERM) {
520de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
521de81e71eSTim Marsland fprintf(stderr, gettext("No TERM variable defined! "
522de81e71eSTim Marsland "Trouble with the Spooler!\n"));
523de81e71eSTim Marsland exit(E_BAD_TERM);
5247c478bd9Sstevel@tonic-gate }
525de81e71eSTim Marsland if (!STREQU(TERM, NAME_UNKNOWN) &&
526de81e71eSTim Marsland tidbit(TERM, "cps", &print_rate) == -1) {
527de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
528de81e71eSTim Marsland fprintf(stderr, gettext("Trouble identifying printer "
529de81e71eSTim Marsland "type \"%s\"; check the Terminfo database.\n"), TERM);
530de81e71eSTim Marsland exit(E_BAD_TERM);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate if (STREQU(TERM, NAME_UNKNOWN))
5337c478bd9Sstevel@tonic-gate print_rate = -1;
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate effective_rate = baudrate() / 10; /* okay for most bauds */
5367c478bd9Sstevel@tonic-gate if (print_rate != -1 && print_rate < effective_rate)
5377c478bd9Sstevel@tonic-gate effective_rate = print_rate;
5387c478bd9Sstevel@tonic-gate if (argc > 1 && (n = atoi(argv[1])) >= 0 && n < effective_rate)
5397c478bd9Sstevel@tonic-gate effective_rate = n; /* 0 means infinite delay */
5407c478bd9Sstevel@tonic-gate if (effective_rate)
5417c478bd9Sstevel@tonic-gate max_delay = DELAY(BUFSIZ, effective_rate);
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate * We'll use the "alarm()" system call to keep us from
5457c478bd9Sstevel@tonic-gate * waiting too long to write to a printer in trouble.
5467c478bd9Sstevel@tonic-gate */
5477c478bd9Sstevel@tonic-gate if (max_delay)
548de81e71eSTim Marsland signal(SIGALRM, sigalrm);
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate * While not end of standard input, copy blocks to
5527c478bd9Sstevel@tonic-gate * standard output.
5537c478bd9Sstevel@tonic-gate */
5547c478bd9Sstevel@tonic-gate while ((nin = read(0, buffer, BUFSIZ)) > 0) {
5557c478bd9Sstevel@tonic-gate char *ptr = buffer;
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate * We should be safe from incomplete writes to a full
5597c478bd9Sstevel@tonic-gate * pipe, as long as the size of the buffer we write is
5607c478bd9Sstevel@tonic-gate * a even divisor of the pipe buffer limit. As long as
5617c478bd9Sstevel@tonic-gate * we read from files or pipes (not communication devices)
5627c478bd9Sstevel@tonic-gate * this should be true for all but the last buffer. The
5637c478bd9Sstevel@tonic-gate * last will be smaller, and won't straddle the pipe max
5647c478bd9Sstevel@tonic-gate * limit (think about it).
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate #if PIPE_BUF < BUFSIZ || (PIPE_MAX % BUFSIZ)
5677c478bd9Sstevel@tonic-gate this_wont_compile;
5687c478bd9Sstevel@tonic-gate #endif
5697c478bd9Sstevel@tonic-gate if (report_rate)
5707c478bd9Sstevel@tonic-gate epoch_start = times(&tms);
5717c478bd9Sstevel@tonic-gate do {
5727c478bd9Sstevel@tonic-gate wait_state(1, func);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate if (max_delay)
575de81e71eSTim Marsland alarm(max_delay);
5767c478bd9Sstevel@tonic-gate nout = write(1, ptr, nin);
5777c478bd9Sstevel@tonic-gate alarm(0);
5787c478bd9Sstevel@tonic-gate if (nout < 0) {
579de81e71eSTim Marsland fprintf(stderr, gettext("Write failed "
580de81e71eSTim Marsland "(%s);\nperhaps the printer has gone "
581de81e71eSTim Marsland "off-line.\n"), PERROR);
5827c478bd9Sstevel@tonic-gate fflush(stderr);
5837c478bd9Sstevel@tonic-gate if (errno != EINTR)
5847c478bd9Sstevel@tonic-gate /* I/O error on device, get lpcshed to retry */
5857c478bd9Sstevel@tonic-gate exit(PRINTER_IO_ERROR);
5867c478bd9Sstevel@tonic-gate else /* wait for printer to come back online */
5877c478bd9Sstevel@tonic-gate sleep(15);
5887c478bd9Sstevel@tonic-gate } else {
5897c478bd9Sstevel@tonic-gate nin -= nout;
5907c478bd9Sstevel@tonic-gate ptr += nout;
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate } while (nin > 0);
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (max_delay)
595de81e71eSTim Marsland alarm(0);
5967c478bd9Sstevel@tonic-gate else if (report_rate) {
5977c478bd9Sstevel@tonic-gate epoch_end = times(&tms);
5987c478bd9Sstevel@tonic-gate if (epoch_end - epoch_start > 0)
599de81e71eSTim Marsland fprintf(stderr, "%d CPS\n",
600de81e71eSTim Marsland R((100 * BUFSIZ) /
601de81e71eSTim Marsland (double)(epoch_end - epoch_start)));
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate
606f928ce67Sceastha return (E_SUCCESS);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate
609de81e71eSTim Marsland /*
610de81e71eSTim Marsland * sighup() - CATCH A HANGUP (LOSS OF CARRIER)
611de81e71eSTim Marsland */
612de81e71eSTim Marsland void
sighup()613de81e71eSTim Marsland sighup()
6147c478bd9Sstevel@tonic-gate {
615de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
616de81e71eSTim Marsland signal(SIGHUP, SIG_IGN);
617de81e71eSTim Marsland fprintf(stderr, gettext(HANGUP_FAULT_LPCAT));
618de81e71eSTim Marsland exit(E_HANGUP);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
621de81e71eSTim Marsland /*
622de81e71eSTim Marsland * sigint() - CATCH AN INTERRUPT
623de81e71eSTim Marsland */
624de81e71eSTim Marsland void
sigint()625de81e71eSTim Marsland sigint()
6267c478bd9Sstevel@tonic-gate {
627de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
628de81e71eSTim Marsland signal(SIGINT, SIG_IGN);
629de81e71eSTim Marsland fprintf(stderr, gettext(INTERRUPT_FAULT));
630de81e71eSTim Marsland exit(E_INTERRUPT);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate
633de81e71eSTim Marsland /*
634de81e71eSTim Marsland * sigpipe() - CATCH EARLY CLOSE OF PIPE
635de81e71eSTim Marsland */
636de81e71eSTim Marsland void
sigpipe()637de81e71eSTim Marsland sigpipe()
6387c478bd9Sstevel@tonic-gate {
639de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
640de81e71eSTim Marsland signal(SIGPIPE, SIG_IGN);
641de81e71eSTim Marsland fprintf(stderr, gettext(PIPE_FAULT));
642de81e71eSTim Marsland exit(E_INTERRUPT);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate
645de81e71eSTim Marsland /*
646de81e71eSTim Marsland * sigalrm() - CATCH AN ALARM
647de81e71eSTim Marsland */
648de81e71eSTim Marsland void
sigalrm()649de81e71eSTim Marsland sigalrm()
6507c478bd9Sstevel@tonic-gate {
651de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
652de81e71eSTim Marsland fprintf(stderr, gettext("Excessive write delay; "
653de81e71eSTim Marsland "perhaps the printer has gone off-line.\n"));
654de81e71eSTim Marsland exit(E_TIMEOUT);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate
657de81e71eSTim Marsland /*
658de81e71eSTim Marsland * sigterm() - CATCH A TERMINATION SIGNAL
659de81e71eSTim Marsland */
660de81e71eSTim Marsland void
sigterm()661de81e71eSTim Marsland sigterm()
6627c478bd9Sstevel@tonic-gate {
663de81e71eSTim Marsland signal(SIGTERM, SIG_IGN);
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate * try to flush the output queue in the case of ecpp port.
6667c478bd9Sstevel@tonic-gate * ignore the return code as this may not be the ecpp.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate ioctl(1, I_FLUSH, FLUSHW);
669de81e71eSTim Marsland exit(E_SUCCESS);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
672de81e71eSTim Marsland /*
673de81e71eSTim Marsland * baudrate() - RETURN BAUD RATE OF OUTPUT LINE
674de81e71eSTim Marsland */
6757c478bd9Sstevel@tonic-gate
676d9c3e05cSJoshua M. Clulow static int baud_convert[] = {
677d9c3e05cSJoshua M. Clulow 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
6787c478bd9Sstevel@tonic-gate 1800, 2400, 4800, 9600, 19200, 38400, 57600,
679d9c3e05cSJoshua M. Clulow 76800, 115200, 153600, 230400, 307200, 460800, 921600,
680d9c3e05cSJoshua M. Clulow 1000000, 1152000, 1500000, 2000000, 2500000, 3000000,
681d9c3e05cSJoshua M. Clulow 3500000, 4000000
6827c478bd9Sstevel@tonic-gate };
6837c478bd9Sstevel@tonic-gate
684de81e71eSTim Marsland int
baudrate()685de81e71eSTim Marsland baudrate()
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate struct termio tm;
6887c478bd9Sstevel@tonic-gate struct termios tms;
6897c478bd9Sstevel@tonic-gate int speed;
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate if (ioctl(1, TCGETS, &tms) < 0) {
692d9c3e05cSJoshua M. Clulow if (ioctl(1, TCGETA, &tm) < 0) {
6937c478bd9Sstevel@tonic-gate return (1200);
694d9c3e05cSJoshua M. Clulow } else {
6957c478bd9Sstevel@tonic-gate speed = tm.c_cflag&CBAUD;
696d9c3e05cSJoshua M. Clulow }
697d9c3e05cSJoshua M. Clulow } else {
6987c478bd9Sstevel@tonic-gate speed = cfgetospeed(&tms);
699d9c3e05cSJoshua M. Clulow }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate return (speed ? baud_convert[speed] : 1200);
7027c478bd9Sstevel@tonic-gate }
703