]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/parallel.c
Revamp child signal handling to remove all processing from the handler
[thirdparty/cups.git] / backend / parallel.c
CommitLineData
43e2fc22 1/*
6bce3201 2 * "$Id: parallel.c,v 1.46 2003/08/30 23:12:09 mike Exp $"
43e2fc22 3 *
e73c6c0a 4 * Parallel port backend for the Common UNIX Printing System (CUPS).
43e2fc22 5 *
997fbfa7 6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
43e2fc22 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
43e2fc22 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
34410ef2 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
43e2fc22 26 * Contents:
27 *
68edc300 28 * main() - Send a file to the specified parallel port.
29 * list_devices() - List all parallel devices.
43e2fc22 30 */
31
32/*
33 * Include necessary headers.
34 */
35
e73c6c0a 36#include <cups/cups.h>
37#include <stdio.h>
38#include <stdlib.h>
a3e17a89 39#include <errno.h>
e73c6c0a 40#include <cups/string.h>
4ff40357 41#include <signal.h>
e73c6c0a 42
3620d932 43#ifdef WIN32
7c88bf41 44# include <io.h>
45#else
46# include <unistd.h>
47# include <fcntl.h>
48# include <termios.h>
3620d932 49#endif /* WIN32 */
7c88bf41 50
92a63e4c 51#ifdef __sgi
52# include <invent.h>
53# ifndef INV_EPP_ECP_PLP
54# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */
55# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */
56# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */
57# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */
58# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */
59# endif /* !INV_EPP_ECP_PLP */
60#endif /* __sgi */
61
e73c6c0a 62
68edc300 63/*
64 * Local functions...
65 */
66
67void list_devices(void);
68
69
e73c6c0a 70/*
7c88bf41 71 * 'main()' - Send a file to the specified parallel port.
e73c6c0a 72 *
73 * Usage:
74 *
75 * printer-uri job-id user title copies options [file]
76 */
77
78int /* O - Exit status */
79main(int argc, /* I - Number of command-line arguments (6 or 7) */
80 char *argv[]) /* I - Command-line arguments */
81{
7c88bf41 82 char method[255], /* Method in URI */
83 hostname[1024], /* Hostname */
84 username[255], /* Username info (not used) */
85 resource[1024], /* Resource info (device and options) */
86 *options; /* Pointer to options */
87 int port; /* Port number (not used) */
b0841309 88 int fp; /* Print file */
3f9cb6c6 89 int copies; /* Number of copies to print */
7c88bf41 90 int fd; /* Parallel device */
1c33ff6a 91 int wbytes; /* Number of bytes written */
92 size_t nbytes, /* Number of bytes read */
7c88bf41 93 tbytes; /* Total number of bytes written */
1c33ff6a 94 char buffer[8192], /* Output buffer */
95 *bufptr; /* Pointer into buffer */
7c88bf41 96 struct termios opts; /* Parallel port options */
4ff40357 97#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
98 struct sigaction action; /* Actions for POSIX signals */
99#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
7c88bf41 100
101
4b23f3b3 102 /*
103 * Make sure status messages are not buffered...
104 */
105
106 setbuf(stderr, NULL);
107
bd3705dd 108 /*
109 * Ignore SIGPIPE signals...
110 */
111
112#ifdef HAVE_SIGSET
113 sigset(SIGPIPE, SIG_IGN);
114#elif defined(HAVE_SIGACTION)
115 memset(&action, 0, sizeof(action));
116 action.sa_handler = SIG_IGN;
117 sigaction(SIGPIPE, &action, NULL);
118#else
119 signal(SIGPIPE, SIG_IGN);
120#endif /* HAVE_SIGSET */
121
4b23f3b3 122 /*
123 * Check command-line...
124 */
125
68edc300 126 if (argc == 1)
127 {
128 list_devices();
129 return (0);
130 }
131 else if (argc < 6 || argc > 7)
e73c6c0a 132 {
7c88bf41 133 fputs("Usage: parallel job-id user title copies options [file]\n", stderr);
134 return (1);
135 }
136
137 /*
138 * If we have 7 arguments, print the file named on the command-line.
139 * Otherwise, send stdin instead...
140 */
141
142 if (argc == 6)
3f9cb6c6 143 {
b0841309 144 fp = 0;
3f9cb6c6 145 copies = 1;
146 }
7c88bf41 147 else
148 {
149 /*
150 * Try to open the print file...
151 */
152
b0841309 153 if ((fp = open(argv[6], O_RDONLY)) < 0)
7c88bf41 154 {
decc1f36 155 perror("ERROR: unable to open print file");
7c88bf41 156 return (1);
157 }
3f9cb6c6 158
159 copies = atoi(argv[4]);
7c88bf41 160 }
161
162 /*
163 * Extract the device name and options from the URI...
164 */
165
166 httpSeparate(argv[0], method, username, hostname, &port, resource);
167
168 /*
169 * See if there are any options...
170 */
171
172 if ((options = strchr(resource, '?')) != NULL)
173 {
174 /*
175 * Yup, terminate the device name string and move to the first
176 * character of the options...
177 */
178
179 *options++ = '\0';
180 }
181
182 /*
183 * Open the parallel port device...
184 */
185
a3e17a89 186 do
7c88bf41 187 {
a3e17a89 188 if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1)
189 {
190 if (errno == EBUSY)
191 {
192 fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr);
193 sleep(30);
194 }
7ed009b3 195 else if (errno == ENXIO || errno == EIO || errno == ENOENT)
e6af753a 196 {
197 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
198 sleep(30);
199 }
a3e17a89 200 else
201 {
290fdb61 202 fprintf(stderr, "ERROR: Unable to open parallel port device file \"%s\": %s\n",
203 resource, strerror(errno));
a3e17a89 204 return (1);
205 }
206 }
e73c6c0a 207 }
a3e17a89 208 while (fd < 0);
e73c6c0a 209
7c88bf41 210 /*
211 * Set any options provided...
212 */
213
214 tcgetattr(fd, &opts);
215
216 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
217
218 /**** No options supported yet ****/
219
220 tcsetattr(fd, TCSANOW, &opts);
221
4ff40357 222 /*
223 * Now that we are "connected" to the port, ignore SIGTERM so that we
224 * can finish out any page data the driver sends (e.g. to eject the
62f24dbf 225 * current page... Only ignore SIGTERM if we are printing data from
226 * stdin (otherwise you can't cancel raw jobs...)
4ff40357 227 */
228
62f24dbf 229 if (argc < 7)
230 {
4ff40357 231#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
62f24dbf 232 sigset(SIGTERM, SIG_IGN);
4ff40357 233#elif defined(HAVE_SIGACTION)
62f24dbf 234 memset(&action, 0, sizeof(action));
4ff40357 235
62f24dbf 236 sigemptyset(&action.sa_mask);
237 action.sa_handler = SIG_IGN;
238 sigaction(SIGTERM, &action, NULL);
4ff40357 239#else
62f24dbf 240 signal(SIGTERM, SIG_IGN);
4ff40357 241#endif /* HAVE_SIGSET */
62f24dbf 242 }
4ff40357 243
7c88bf41 244 /*
245 * Finally, send the print file...
246 */
247
3f9cb6c6 248 while (copies > 0)
7c88bf41 249 {
3f9cb6c6 250 copies --;
7c88bf41 251
b0841309 252 if (fp != 0)
7c88bf41 253 {
3f9cb6c6 254 fputs("PAGE: 1 1\n", stderr);
b0841309 255 lseek(fp, 0, SEEK_SET);
7c88bf41 256 }
7c88bf41 257
3f9cb6c6 258 tbytes = 0;
b0841309 259 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
3f9cb6c6 260 {
261 /*
262 * Write the print data to the printer...
263 */
264
1c33ff6a 265 tbytes += nbytes;
266 bufptr = buffer;
267
268 while (nbytes > 0)
3f9cb6c6 269 {
1c33ff6a 270 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
271 if (errno == ENOTTY)
272 wbytes = write(fd, bufptr, nbytes);
273
274 if (wbytes < 0)
275 {
276 perror("ERROR: Unable to send print file to printer");
277 break;
278 }
279
280 nbytes -= wbytes;
281 bufptr += wbytes;
3f9cb6c6 282 }
3f9cb6c6 283
6bce3201 284 if (wbytes < 0)
285 break;
286
3f9cb6c6 287 if (argc > 6)
56f7e7b2 288 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
289 (unsigned long)tbytes);
3f9cb6c6 290 }
7c88bf41 291 }
292
293 /*
294 * Close the socket connection and input file and return...
295 */
296
297 close(fd);
b0841309 298 if (fp != 0)
299 close(fp);
e73c6c0a 300
ac1d9665 301 fputs("INFO: Ready to print.\n", stderr);
302
7c88bf41 303 return (0);
e73c6c0a 304}
43e2fc22 305
306
307/*
68edc300 308 * 'list_devices()' - List all parallel devices.
309 */
310
311void
312list_devices(void)
313{
b6ea8f29 314#if defined(__hpux) || defined(__sgi) || defined(__sun)
92a63e4c 315 static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
316 /* Funky hex numbering used for some devices */
b6ea8f29 317#endif /* __hpux || __sgi || __sun */
92a63e4c 318
68edc300 319#ifdef __linux
a2c6b8b1 320 int i; /* Looping var */
321 int fd; /* File descriptor */
095ce1ee 322 char device[255], /* Device filename */
eb989f10 323 probefile[255], /* Probe filename */
324 basedevice[255]; /* Base device filename for ports */
a2c6b8b1 325 FILE *probe; /* /proc/parport/n/autoprobe file */
326 char line[1024], /* Line from file */
327 *delim, /* Delimiter in file */
328 make[IPP_MAX_NAME], /* Make from file */
329 model[IPP_MAX_NAME]; /* Model from file */
68edc300 330
331
332 for (i = 0; i < 4; i ++)
333 {
095ce1ee 334 /*
335 * First open the device to make sure the driver module is loaded...
336 */
337
eb989f10 338 if ((fd = open("/dev/parallel/0", O_WRONLY)) >= 0)
339 {
095ce1ee 340 close(fd);
eb989f10 341 strcpy(basedevice, "/dev/parallel/");
342 }
095ce1ee 343 else
344 {
eb989f10 345 sprintf(device, "/dev/lp%d", i);
095ce1ee 346 if ((fd = open(device, O_WRONLY)) >= 0)
eb989f10 347 {
095ce1ee 348 close(fd);
eb989f10 349 strcpy(basedevice, "/dev/lp");
350 }
351 else
352 {
353 sprintf(device, "/dev/par%d", i);
354 if ((fd = open(device, O_WRONLY)) >= 0)
355 {
356 close(fd);
357 strcpy(basedevice, "/dev/par");
358 }
359 else
dbe9f6ee 360 {
361 sprintf(device, "/dev/printers/%d", i);
362 if ((fd = open(device, O_WRONLY)) >= 0)
363 {
364 close(fd);
365 strcpy(basedevice, "/dev/printers/");
366 }
367 else
368 strcpy(basedevice, "/dev/unknown-parallel");
369 }
eb989f10 370 }
095ce1ee 371 }
372
373 /*
374 * Then try looking at the probe file...
375 */
376
377 sprintf(probefile, "/proc/parport/%d/autoprobe", i);
378 if ((probe = fopen(probefile, "r")) == NULL)
8ec4b03f 379 {
095ce1ee 380 /*
381 * Linux 2.4 kernel has different path...
382 */
383
384 sprintf(probefile, "/proc/sys/dev/parport/parport%d/autoprobe", i);
385 probe = fopen(probefile, "r");
386 }
387
388 if (probe != NULL)
389 {
390 /*
391 * Found a probe file!
392 */
393
a2c6b8b1 394 memset(make, 0, sizeof(make));
395 memset(model, 0, sizeof(model));
396 strcpy(model, "Unknown");
397
398 while (fgets(line, sizeof(line), probe) != NULL)
399 {
400 /*
401 * Strip trailing ; and/or newline.
402 */
403
404 if ((delim = strrchr(line, ';')) != NULL)
405 *delim = '\0';
406 else if ((delim = strrchr(line, '\n')) != NULL)
407 *delim = '\0';
408
409 /*
410 * Look for MODEL and MANUFACTURER lines...
411 */
412
413 if (strncmp(line, "MODEL:", 6) == 0 &&
414 strncmp(line, "MODEL:Unknown", 13) != 0)
17438bf4 415 strlcpy(model, line + 6, sizeof(model));
a2c6b8b1 416 else if (strncmp(line, "MANUFACTURER:", 13) == 0 &&
417 strncmp(line, "MANUFACTURER:Unknown", 20) != 0)
17438bf4 418 strlcpy(make, line + 13, sizeof(make));
a2c6b8b1 419 }
420
421 fclose(probe);
422
423 if (make[0])
eb989f10 424 printf("direct parallel:%s%d \"%s %s\" \"Parallel Port #%d\"\n",
425 basedevice, i, make, model, i + 1);
a2c6b8b1 426 else
eb989f10 427 printf("direct parallel:%s%d \"%s\" \"Parallel Port #%d\"\n",
428 basedevice, i, model, i + 1);
8ec4b03f 429 }
095ce1ee 430 else if (fd >= 0)
8ec4b03f 431 {
095ce1ee 432 /*
433 * No probe file, but we know the port is there...
434 */
435
436 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
8ec4b03f 437 }
68edc300 438 }
439#elif defined(__sgi)
92a63e4c 440 int i, j, n; /* Looping vars */
441 char device[255]; /* Device filename */
442 inventory_t *inv; /* Hardware inventory info */
443
444
445 /*
446 * IRIX maintains a hardware inventory of most devices...
447 */
448
449 setinvent();
450
451 while ((inv = getinvent()) != NULL)
452 {
453 if (inv->inv_class == INV_PARALLEL &&
454 (inv->inv_type == INV_ONBOARD_PLP ||
455 inv->inv_type == INV_EPP_ECP_PLP))
456 {
457 /*
458 * Standard parallel port...
459 */
460
461 puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\"");
462 }
463 else if (inv->inv_class == INV_PARALLEL &&
464 inv->inv_type == INV_EPC_PLP)
465 {
466 /*
467 * EPC parallel port...
468 */
469
470 printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n",
471 inv->inv_controller, inv->inv_controller);
472 }
473 }
474
475 endinvent();
476
477 /*
478 * Central Data makes serial and parallel "servers" that can be
479 * connected in a number of ways. Look for ports...
480 */
481
482 for (i = 0; i < 10; i ++)
483 for (j = 0; j < 8; j ++)
484 for (n = 0; n < 32; n ++)
485 {
486 if (i == 8) /* EtherLite */
487 sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]);
488 else if (i == 9) /* PCI */
489 sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]);
490 else /* SCSI */
491 sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]);
492
493 if (access(device, 0) == 0)
494 {
495 if (i == 8)
496 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
497 device, j, n);
498 else if (i == 9)
499 printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n",
500 device, j, n);
501 else
502 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
503 device, i, j, n);
504 }
505 }
68edc300 506#elif defined(__sun)
92a63e4c 507 int i, j, n; /* Looping vars */
508 char device[255]; /* Device filename */
92a63e4c 509
510
511 /*
512 * Standard parallel ports...
513 */
514
515 for (i = 0; i < 10; i ++)
516 {
517 sprintf(device, "/dev/ecpp%d", i);
518 if (access(device, 0) == 0)
519 printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n",
520 device, i + 1);
521 }
522
523 for (i = 0; i < 10; i ++)
524 {
525 sprintf(device, "/dev/bpp%d", i);
526 if (access(device, 0) == 0)
527 printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n",
528 device, i + 1);
529 }
530
531 for (i = 0; i < 3; i ++)
532 {
533 sprintf(device, "/dev/lp%d", i);
534
535 if (access(device, 0) == 0)
536 printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n",
537 device, i + 1);
538 }
539
540 /*
541 * MAGMA parallel ports...
542 */
543
544 for (i = 0; i < 40; i ++)
545 {
546 sprintf(device, "/dev/pm%02d", i);
547 if (access(device, 0) == 0)
548 printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n",
549 device, (i / 10) + 1, (i % 10) + 1);
550 }
551
552 /*
553 * Central Data parallel ports...
554 */
555
556 for (i = 0; i < 9; i ++)
557 for (j = 0; j < 8; j ++)
558 for (n = 0; n < 32; n ++)
559 {
560 if (i == 8) /* EtherLite */
561 sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]);
562 else
563 sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j,
564 funky_hex[n]);
565
566 if (access(device, 0) == 0)
567 {
568 if (i == 8)
569 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
570 device, j, n);
571 else
572 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
573 device, i, j, n);
574 }
575 }
68edc300 576#elif defined(__hpux)
92a63e4c 577 int i, j, n; /* Looping vars */
578 char device[255]; /* Device filename */
579
580
581 /*
582 * Standard parallel ports...
583 */
584
585 if (access("/dev/rlp", 0) == 0)
586 puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\"");
587
588 for (i = 0; i < 7; i ++)
589 for (j = 0; j < 7; j ++)
590 {
591 sprintf(device, "/dev/c%dt%dd0_lp", i, j);
592 if (access(device, 0) == 0)
a93f46ca 593 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n",
594 device, i, j);
92a63e4c 595 }
596
597 /*
598 * Central Data parallel ports...
599 */
600
601 for (i = 0; i < 9; i ++)
602 for (j = 0; j < 8; j ++)
603 for (n = 0; n < 32; n ++)
604 {
605 if (i == 8) /* EtherLite */
606 sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]);
607 else
608 sprintf(device, "/dev/lp%c%d%c", i + 'C', j,
609 funky_hex[n]);
610
611 if (access(device, 0) == 0)
612 {
613 if (i == 8)
614 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
615 device, j, n);
616 else
617 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
618 device, i, j, n);
619 }
620 }
621#elif defined(__osf__)
622 int i; /* Looping var */
3a5ad272 623 int fd; /* File descriptor */
92a63e4c 624 char device[255]; /* Device filename */
625
626
627 for (i = 0; i < 3; i ++)
628 {
629 sprintf(device, "/dev/lp%d", i);
630 if ((fd = open(device, O_WRONLY)) >= 0)
631 {
632 close(fd);
633 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
634 }
635 }
b43fa007 636#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
92a63e4c 637 int i; /* Looping var */
a3e17a89 638 int fd; /* File descriptor */
92a63e4c 639 char device[255]; /* Device filename */
640
641
642 for (i = 0; i < 3; i ++)
643 {
644 sprintf(device, "/dev/lpt%d", i);
645 if ((fd = open(device, O_WRONLY)) >= 0)
646 {
647 close(fd);
428bdf25 648 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (interrupt-driven)\"\n", device, i + 1);
92a63e4c 649 }
31d9b588 650
651 sprintf(device, "/dev/lpa%d", i);
652 if ((fd = open(device, O_WRONLY)) >= 0)
653 {
654 close(fd);
428bdf25 655 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
31d9b588 656 }
92a63e4c 657 }
58bca2c3 658#elif defined(_AIX)
659 int i; /* Looping var */
660 int fd; /* File descriptor */
661 char device[255]; /* Device filename */
662
663
664 for (i = 0; i < 8; i ++)
665 {
666 sprintf(device, "/dev/lp%d", i);
667 if ((fd = open(device, O_WRONLY)) >= 0)
668 {
669 close(fd);
670 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
671 }
672 }
68edc300 673#endif
674}
675
676
677/*
6bce3201 678 * End of "$Id: parallel.c,v 1.46 2003/08/30 23:12:09 mike Exp $".
43e2fc22 679 */