1 /*
2 * Copyright (C) 1992-1997 Michael K. Johnson, johnsonm@redhat.com
3 *
4 * This file is licensed under the terms of the GNU General Public
5 * License, version 2, or any later version. See file COPYING for
6 * information on distribution conditions.
7 */
8
9 /*
10 * $Log: tunelp.c,v $
11 * Revision 1.9 1998/06/08 19:37:11 janl
12 * Thus compiles tunelp with 2.1.103 kernels
13 *
14 * Revision 1.8 1997/07/06 00:14:06 aebr
15 * Fixes to silence -Wall.
16 *
17 * Revision 1.7 1997/06/20 16:10:38 janl
18 * tunelp refreshed from authors archive.
19 *
20 * Revision 1.9 1997/06/20 12:56:43 johnsonm
21 * Finished fixing license terms.
22 *
23 * Revision 1.8 1997/06/20 12:34:59 johnsonm
24 * Fixed copyright and license.
25 *
26 * Revision 1.7 1995/03/29 11:16:23 johnsonm
27 * TYPO fixed...
28 *
29 * Revision 1.6 1995/03/29 11:12:15 johnsonm
30 * Added third argument to ioctl needed with new kernels
31 *
32 * Revision 1.5 1995/01/13 10:33:43 johnsonm
33 * Chris's changes for new ioctl numbers and backwards compatibility
34 * and the reset ioctl.
35 *
36 * Revision 1.4 1995/01/03 17:42:14 johnsonm
37 * -s isn't supposed to take an argument; removed : after s in getopt...
38 *
39 * Revision 1.3 1995/01/03 07:36:49 johnsonm
40 * Fixed typo
41 *
42 * Revision 1.2 1995/01/03 07:33:44 johnsonm
43 * revisions for lp driver updates in Linux 1.1.76
44 *
45 * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
46 * - added Native Language Support
47 *
48 * 1999-05-07 Merged LPTRUSTIRQ patch by Andrea Arcangeli (1998/11/29), aeb
49 *
50 */
51
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <getopt.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <sys/ioctl.h>
59 #include <sys/stat.h>
60 #include <sys/types.h>
61 #include <unistd.h>
62
63 #include "lp.h"
64 #include "nls.h"
65 #include "xalloc.h"
66 #include "closestream.h"
67
68 #define EXIT_BAD_VALUE 3
69 #define EXIT_LP_IO_ERR 4
70
71 struct command {
72 long op;
73 long val;
74 struct command *next;
75 };
76
print_usage(FILE * out)77 static void __attribute__((__noreturn__)) print_usage(FILE *out)
78 {
79 fputs(USAGE_HEADER, out);
80 fprintf(out, _(" %s [options] <device>\n"), program_invocation_short_name);
81
82 fputs(USAGE_OPTIONS, out);
83 fputs(_(" -i, --irq <num> specify parallel port irq\n"), out);
84 fputs(_(" -t, --time <ms> driver wait time in milliseconds\n"), out);
85 fputs(_(" -c, --chars <num> number of output characters before sleep\n"), out);
86 fputs(_(" -w, --wait <us> strobe wait in micro seconds\n"), out);
87 /* TRANSLATORS: do not translate <on|off> arguments. The
88 argument reader does not recognize locale, unless `on' is
89 exactly that very same string. */
90 fputs(_(" -a, --abort <on|off> abort on error\n"), out);
91 fputs(_(" -o, --check-status <on|off> check printer status before printing\n"), out);
92 fputs(_(" -C, --careful <on|off> extra checking to status check\n"), out);
93 fputs(_(" -s, --status query printer status\n"), out);
94 fputs(_(" -T, --trust-irq <on|off> make driver to trust irq\n"), out);
95 fputs(_(" -r, --reset reset the port\n"), out);
96 fputs(_(" -q, --print-irq <on|off> display current irq setting\n"), out);
97 fputs(USAGE_SEPARATOR, out);
98 fputs(USAGE_HELP, out);
99 fputs(USAGE_VERSION, out);
100 fprintf(out, USAGE_MAN_TAIL("tunelp(8)"));
101
102 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
103 }
104
get_val(char * val)105 static long get_val(char *val)
106 {
107 long ret;
108 if (!(sscanf(val, "%ld", &ret) == 1))
109 errx(EXIT_BAD_VALUE, _("bad value"));
110 return ret;
111 }
112
get_onoff(char * val)113 static long get_onoff(char *val)
114 {
115 if (!strncasecmp("on", val, 2))
116 return 1;
117 return 0;
118 }
119
main(int argc,char ** argv)120 int main(int argc, char **argv)
121 {
122 int c, fd, irq, status, show_irq, offset = 0, retval;
123 char *filename;
124 struct stat statbuf;
125 struct command *cmds, *cmdst;
126 static const struct option longopts[] = {
127 {"irq", required_argument, NULL, 'i'},
128 {"time", required_argument, NULL, 't'},
129 {"chars", required_argument, NULL, 'c'},
130 {"wait", required_argument, NULL, 'w'},
131 {"abort", required_argument, NULL, 'a'},
132 {"check-status", required_argument, NULL, 'o'},
133 {"careful", required_argument, NULL, 'C'},
134 {"status", no_argument, NULL, 's'},
135 {"trust-irq", required_argument, NULL, 'T'},
136 {"reset", no_argument, NULL, 'r'},
137 {"print-irq", required_argument, NULL, 'q'},
138 {"version", no_argument, NULL, 'V'},
139 {"help", no_argument, NULL, 'h'},
140 {NULL, 0, NULL, 0}
141 };
142
143 setlocale(LC_ALL, "");
144 bindtextdomain(PACKAGE, LOCALEDIR);
145 textdomain(PACKAGE);
146 atexit(close_stdout);
147
148 if (argc < 2)
149 print_usage(stderr);
150
151 cmdst = cmds = xmalloc(sizeof(struct command));
152 cmds->next = 0;
153
154 show_irq = 1;
155 while ((c = getopt_long(argc, argv, "t:c:w:a:i:ho:C:sq:rT:vV", longopts, NULL)) != -1) {
156 switch (c) {
157 case 'h':
158 print_usage(stdout);
159 break;
160 case 'i':
161 cmds->op = LPSETIRQ;
162 cmds->val = get_val(optarg);
163 cmds->next = xmalloc(sizeof(struct command));
164 cmds = cmds->next;
165 cmds->next = 0;
166 break;
167 case 't':
168 cmds->op = LPTIME;
169 cmds->val = get_val(optarg);
170 cmds->next = xmalloc(sizeof(struct command));
171 cmds = cmds->next;
172 cmds->next = 0;
173 break;
174 case 'c':
175 cmds->op = LPCHAR;
176 cmds->val = get_val(optarg);
177 cmds->next = xmalloc(sizeof(struct command));
178 cmds = cmds->next;
179 cmds->next = 0;
180 break;
181 case 'w':
182 cmds->op = LPWAIT;
183 cmds->val = get_val(optarg);
184 cmds->next = xmalloc(sizeof(struct command));
185 cmds = cmds->next;
186 cmds->next = 0;
187 break;
188 case 'a':
189 cmds->op = LPABORT;
190 cmds->val = get_onoff(optarg);
191 cmds->next = xmalloc(sizeof(struct command));
192 cmds = cmds->next;
193 cmds->next = 0;
194 break;
195 case 'q':
196 if (get_onoff(optarg)) {
197 show_irq = 1;
198 } else {
199 show_irq = 0;
200 }
201 break;
202 #ifdef LPGETSTATUS
203 case 'o':
204 cmds->op = LPABORTOPEN;
205 cmds->val = get_onoff(optarg);
206 cmds->next = xmalloc(sizeof(struct command));
207 cmds = cmds->next;
208 cmds->next = 0;
209 break;
210 case 'C':
211 cmds->op = LPCAREFUL;
212 cmds->val = get_onoff(optarg);
213 cmds->next = xmalloc(sizeof(struct command));
214 cmds = cmds->next;
215 cmds->next = 0;
216 break;
217 case 's':
218 show_irq = 0;
219 cmds->op = LPGETSTATUS;
220 cmds->val = 0;
221 cmds->next = xmalloc(sizeof(struct command));
222 cmds = cmds->next;
223 cmds->next = 0;
224 break;
225 #endif
226 #ifdef LPRESET
227 case 'r':
228 cmds->op = LPRESET;
229 cmds->val = 0;
230 cmds->next = xmalloc(sizeof(struct command));
231 cmds = cmds->next;
232 cmds->next = 0;
233 break;
234 #endif
235 #ifdef LPTRUSTIRQ
236 case 'T':
237 /* Note: this will do the wrong thing on
238 * 2.0.36 when compiled under 2.2.x
239 */
240 cmds->op = LPTRUSTIRQ;
241 cmds->val = get_onoff(optarg);
242 cmds->next = xmalloc(sizeof(struct command));
243 cmds = cmds->next;
244 cmds->next = 0;
245 break;
246 #endif
247 case 'v':
248 case 'V':
249 printf(_("%s from %s\n"),
250 program_invocation_short_name, PACKAGE_STRING);
251 return EXIT_SUCCESS;
252 default:
253 print_usage(stderr);
254 }
255 }
256
257 if (optind != argc - 1)
258 print_usage(stderr);
259
260 filename = xstrdup(argv[optind]);
261 fd = open(filename, O_WRONLY | O_NONBLOCK, 0);
262 /* Need to open O_NONBLOCK in case ABORTOPEN is already set
263 * and printer is off or off-line or in an error condition.
264 * Otherwise we would abort...
265 */
266 if (fd < 0)
267 err(EXIT_FAILURE, "%s", filename);
268
269 if (fstat(fd, &statbuf))
270 err(EXIT_FAILURE, "%s: stat() failed", filename);
271
272 if (!S_ISCHR(statbuf.st_mode)) {
273 warnx(_("%s not an lp device"), filename);
274 print_usage(stderr);
275 }
276 /* Allow for binaries compiled under a new kernel to work on
277 * the old ones The irq argument to ioctl isn't touched by
278 * the old kernels, but we don't want to cause the kernel to
279 * complain if we are using a new kernel
280 */
281 if (LPGETIRQ >= 0x0600 && ioctl(fd, LPGETIRQ, &irq) < 0
282 && errno == EINVAL)
283 /* We don't understand the new ioctls */
284 offset = 0x0600;
285
286 cmds = cmdst;
287 while (cmds->next) {
288 #ifdef LPGETSTATUS
289 if (cmds->op == LPGETSTATUS) {
290 status = 0xdeadbeef;
291 retval = ioctl(fd, LPGETSTATUS - offset, &status);
292 if (retval < 0)
293 warnx(_("LPGETSTATUS error"));
294 else {
295 if (status == (int)0xdeadbeef)
296 /* a few 1.1.7x kernels will do this */
297 status = retval;
298 printf(_("%s status is %d"), filename, status);
299 if (!(status & LP_PBUSY))
300 printf(_(", busy"));
301 if (!(status & LP_PACK))
302 printf(_(", ready"));
303 if ((status & LP_POUTPA))
304 printf(_(", out of paper"));
305 if ((status & LP_PSELECD))
306 printf(_(", on-line"));
307 if (!(status & LP_PERRORP))
308 printf(_(", error"));
309 printf("\n");
310 }
311 } else
312 #endif /* LPGETSTATUS */
313 if (ioctl(fd, cmds->op - offset, cmds->val) < 0)
314 warn(_("ioctl failed"));
315 cmdst = cmds;
316 cmds = cmds->next;
317 free(cmdst);
318 }
319
320 if (show_irq) {
321 irq = 0xdeadbeef;
322 retval = ioctl(fd, LPGETIRQ - offset, &irq);
323 if (retval == -1)
324 err(EXIT_LP_IO_ERR, _("LPGETIRQ error"));
325 if (irq == (int)0xdeadbeef)
326 /* up to 1.1.77 will do this */
327 irq = retval;
328 if (irq)
329 printf(_("%s using IRQ %d\n"), filename, irq);
330 else
331 printf(_("%s using polling\n"), filename);
332 }
333 free(filename);
334 close(fd);
335
336 return EXIT_SUCCESS;
337 }
338