]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
Local authentication certificates are now stored in
[thirdparty/cups.git] / backend / lpd.c
1 /*
2 * "$Id$"
3 *
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
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
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the printer or server.
29 * lpd_command() - Send an LPR command sequence and wait for a reply.
30 * lpd_queue() - Queue a file using the Line Printer Daemon protocol.
31 * lpd_timeout() - Handle timeout alarms...
32 * lpd_write() - Write a buffer of data to an LPD server.
33 * rresvport() - A simple implementation of rresvport().
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
35 */
36
37 /*
38 * Include necessary headers.
39 */
40
41 #include <cups/cups.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <ctype.h>
46 #include <cups/http-private.h>
47 #include <cups/string.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <signal.h>
52
53 #ifdef WIN32
54 # include <winsock.h>
55 #else
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # include <arpa/inet.h>
59 # include <netdb.h>
60 #endif /* WIN32 */
61
62
63 /*
64 * Globals...
65 */
66
67 static char tmpfilename[1024] = ""; /* Temporary spool file name */
68
69
70 /*
71 * The order for control and data files in LPD requests...
72 */
73
74 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
75 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
76
77
78 /*
79 * What to reserve...
80 */
81
82 #define RESERVE_NONE 0 /* Don't reserve a priviledged port */
83 #define RESERVE_RFC1179 1 /* Reserve port 721-731 */
84 #define RESERVE_ANY 2 /* Reserve port 1-1023 */
85
86
87 /*
88 * It appears that rresvport() is never declared on most systems...
89 */
90
91 extern int rresvport(int *port);
92
93
94 /*
95 * Local functions...
96 */
97
98 static int lpd_command(int lpd_fd, int timeout, char *format, ...);
99 static int lpd_queue(const char *hostname, int port, const char *printer,
100 const char *filename,
101 const char *user, const char *title, int copies,
102 int banner, int format, int order, int reserve,
103 int manual_copies, int timeout);
104 static void lpd_timeout(int sig);
105 static int lpd_write(int lpd_fd, char *buffer, int length);
106 static void sigterm_handler(int sig);
107
108
109 /*
110 * 'main()' - Send a file to the printer or server.
111 *
112 * Usage:
113 *
114 * printer-uri job-id user title copies options [file]
115 */
116
117 int /* O - Exit status */
118 main(int argc, /* I - Number of command-line arguments (6 or 7) */
119 char *argv[]) /* I - Command-line arguments */
120 {
121 char method[255], /* Method in URI */
122 hostname[1024], /* Hostname */
123 username[255], /* Username info */
124 resource[1024], /* Resource info (printer name) */
125 *options, /* Pointer to options */
126 name[255], /* Name of option */
127 value[255], /* Value of option */
128 *ptr, /* Pointer into name or value */
129 *filename, /* File to print */
130 title[256]; /* Title string */
131 int port; /* Port number */
132 int status; /* Status of LPD job */
133 int banner; /* Print banner page? */
134 int format; /* Print format */
135 int order; /* Order of control/data files */
136 int reserve; /* Reserve priviledged port? */
137 int sanitize_title; /* Sanitize title string? */
138 int manual_copies, /* Do manual copies? */
139 timeout, /* Timeout */
140 copies; /* Number of copies */
141 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
142 struct sigaction action; /* Actions for POSIX signals */
143 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
144
145
146 /*
147 * Make sure status messages are not buffered...
148 */
149
150 setbuf(stderr, NULL);
151
152 /*
153 * Ignore SIGPIPE and catch SIGTERM signals...
154 */
155
156 #ifdef HAVE_SIGSET
157 sigset(SIGPIPE, SIG_IGN);
158 sigset(SIGTERM, sigterm_handler);
159 #elif defined(HAVE_SIGACTION)
160 memset(&action, 0, sizeof(action));
161 action.sa_handler = SIG_IGN;
162 sigaction(SIGPIPE, &action, NULL);
163
164 sigemptyset(&action.sa_mask);
165 sigaddset(&action.sa_mask, SIGTERM);
166 action.sa_handler = sigterm_handler;
167 sigaction(SIGTERM, &action, NULL);
168 #else
169 signal(SIGPIPE, SIG_IGN);
170 signal(SIGTERM, sigterm_handler);
171 #endif /* HAVE_SIGSET */
172
173 /*
174 * Check command-line...
175 */
176
177 if (argc == 1)
178 {
179 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
180 return (0);
181 }
182 else if (argc < 6 || argc > 7)
183 {
184 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
185 argv[0]);
186 return (1);
187 }
188
189 /*
190 * If we have 7 arguments, print the file named on the command-line.
191 * Otherwise, copy stdin to a temporary file and print the temporary
192 * file.
193 */
194
195 if (argc == 6)
196 {
197 /*
198 * Copy stdin to a temporary file...
199 */
200
201 int fd; /* Temporary file */
202 char buffer[8192]; /* Buffer for copying */
203 int bytes; /* Number of bytes read */
204
205
206 if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
207 {
208 perror("ERROR: unable to create temporary file");
209 return (1);
210 }
211
212 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
213 if (write(fd, buffer, bytes) < bytes)
214 {
215 perror("ERROR: unable to write to temporary file");
216 close(fd);
217 unlink(tmpfilename);
218 return (1);
219 }
220
221 close(fd);
222 filename = tmpfilename;
223 }
224 else
225 filename = argv[6];
226
227 /*
228 * Extract the hostname and printer name from the URI...
229 */
230
231 httpSeparate(argv[0], method, username, hostname, &port, resource);
232
233 if (!username[0])
234 {
235 /*
236 * If no username is in the device URI, then use the print job user...
237 */
238
239 strlcpy(username, argv[2], sizeof(username));
240 }
241
242 /*
243 * See if there are any options...
244 */
245
246 banner = 0;
247 format = 'l';
248 order = ORDER_CONTROL_DATA;
249 reserve = RESERVE_ANY;
250 manual_copies = 1;
251 timeout = 300;
252 sanitize_title = 1;
253
254 #if defined(__APPLE__)
255 /* We want to pass utf-8 characters, not re-map them (3071945) */
256 sanitize_title= 0;
257 #endif
258
259 if ((options = strchr(resource, '?')) != NULL)
260 {
261 /*
262 * Yup, terminate the device name string and move to the first
263 * character of the options...
264 */
265
266 *options++ = '\0';
267
268 /*
269 * Parse options...
270 */
271
272 while (*options)
273 {
274 /*
275 * Get the name...
276 */
277
278 for (ptr = name; *options && *options != '=';)
279 if (ptr < (name + sizeof(name) - 1))
280 *ptr++ = *options++;
281 *ptr = '\0';
282
283 if (*options == '=')
284 {
285 /*
286 * Get the value...
287 */
288
289 options ++;
290
291 for (ptr = value; *options && *options != '+' && *options != '&';)
292 if (ptr < (value + sizeof(value) - 1))
293 *ptr++ = *options++;
294 *ptr = '\0';
295
296 if (*options == '+')
297 options ++;
298 }
299 else
300 value[0] = '\0';
301
302 /*
303 * Process the option...
304 */
305
306 if (strcasecmp(name, "banner") == 0)
307 {
308 /*
309 * Set the banner...
310 */
311
312 banner = !value[0] ||
313 strcasecmp(value, "on") == 0 ||
314 strcasecmp(value, "yes") == 0 ||
315 strcasecmp(value, "true") == 0;
316 }
317 else if (strcasecmp(name, "format") == 0 && value[0])
318 {
319 /*
320 * Set output format...
321 */
322
323 if (strchr("cdfglnoprtv", value[0]) != NULL)
324 format = value[0];
325 else
326 fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
327 }
328 else if (strcasecmp(name, "order") == 0 && value[0])
329 {
330 /*
331 * Set control/data order...
332 */
333
334 if (strcasecmp(value, "control,data") == 0)
335 order = ORDER_CONTROL_DATA;
336 else if (strcasecmp(value, "data,control") == 0)
337 order = ORDER_DATA_CONTROL;
338 else
339 fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
340 }
341 else if (strcasecmp(name, "reserve") == 0)
342 {
343 /*
344 * Set port reservation mode...
345 */
346
347 if (!value[0] ||
348 !strcasecmp(value, "on") ||
349 !strcasecmp(value, "yes") ||
350 !strcasecmp(value, "true") ||
351 !strcasecmp(value, "rfc1179"))
352 reserve = RESERVE_RFC1179;
353 else if (!strcasecmp(value, "any"))
354 reserve = RESERVE_ANY;
355 else
356 reserve = RESERVE_NONE;
357 }
358 else if (strcasecmp(name, "manual_copies") == 0)
359 {
360 /*
361 * Set manual copies...
362 */
363
364 manual_copies = !value[0] ||
365 strcasecmp(value, "on") == 0 ||
366 strcasecmp(value, "yes") == 0 ||
367 strcasecmp(value, "true") == 0;
368 }
369 else if (strcasecmp(name, "sanitize_title") == 0)
370 {
371 /*
372 * Set sanitize title...
373 */
374
375 sanitize_title = !value[0] ||
376 strcasecmp(value, "on") == 0 ||
377 strcasecmp(value, "yes") == 0 ||
378 strcasecmp(value, "true") == 0;
379 }
380 else if (strcasecmp(name, "timeout") == 0)
381 {
382 /*
383 * Set the timeout...
384 */
385
386 if (atoi(value) > 0)
387 timeout = atoi(value);
388 }
389 }
390 }
391
392 /*
393 * Sanitize the document title...
394 */
395
396 strlcpy(title, argv[3], sizeof(title));
397
398 if (sanitize_title)
399 {
400 /*
401 * Sanitize the title string so that we don't cause problems on
402 * the remote end...
403 */
404
405 for (ptr = title; *ptr; ptr ++)
406 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
407 *ptr = '_';
408 }
409
410 /*
411 * Queue the job...
412 */
413
414 if (argc > 6)
415 {
416 if (manual_copies)
417 {
418 manual_copies = atoi(argv[4]);
419 copies = 1;
420 }
421 else
422 {
423 manual_copies = 1;
424 copies = atoi(argv[4]);
425 }
426
427 status = lpd_queue(hostname, port, resource + 1, filename,
428 username, title, copies,
429 banner, format, order, reserve, manual_copies, timeout);
430
431 if (!status)
432 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
433 }
434 else
435 status = lpd_queue(hostname, port, resource + 1, filename,
436 username, title, 1,
437 banner, format, order, reserve, 1, timeout);
438
439 /*
440 * Remove the temporary file if necessary...
441 */
442
443 if (tmpfilename[0])
444 unlink(tmpfilename);
445
446 /*
447 * Return the queue status...
448 */
449
450 return (status);
451 }
452
453
454 /*
455 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
456 */
457
458 static int /* O - Status of command */
459 lpd_command(int fd, /* I - Socket connection to LPD host */
460 int timeout, /* I - Seconds to wait for a response */
461 char *format, /* I - printf()-style format string */
462 ...) /* I - Additional args as necessary */
463 {
464 va_list ap; /* Argument pointer */
465 char buf[1024]; /* Output buffer */
466 int bytes; /* Number of bytes to output */
467 char status; /* Status from command */
468
469
470 /*
471 * Format the string...
472 */
473
474 va_start(ap, format);
475 bytes = vsnprintf(buf, sizeof(buf), format, ap);
476 va_end(ap);
477
478 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
479
480 /*
481 * Send the command...
482 */
483
484 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
485
486 if (lpd_write(fd, buf, bytes) < bytes)
487 {
488 perror("ERROR: Unable to send LPD command");
489 return (-1);
490 }
491
492 /*
493 * Read back the status from the command and return it...
494 */
495
496 fprintf(stderr, "DEBUG: Reading command status...\n");
497
498 alarm(timeout);
499
500 if (recv(fd, &status, 1, 0) < 1)
501 {
502 fprintf(stderr, "WARNING: Remote host did not respond with command "
503 "status byte after %d seconds!\n", timeout);
504 status = errno;
505 }
506
507 alarm(0);
508
509 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
510
511 return (status);
512 }
513
514
515 /*
516 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
517 */
518
519 static int /* O - Zero on success, non-zero on failure */
520 lpd_queue(const char *hostname, /* I - Host to connect to */
521 int port, /* I - Port to connect on */
522 const char *printer, /* I - Printer/queue name */
523 const char *filename, /* I - File to print */
524 const char *user, /* I - Requesting user */
525 const char *title, /* I - Job title */
526 int copies, /* I - Number of copies */
527 int banner, /* I - Print LPD banner? */
528 int format, /* I - Format specifier */
529 int order, /* I - Order of data/control files */
530 int reserve, /* I - Reserve ports? */
531 int manual_copies, /* I - Do copies by hand... */
532 int timeout) /* I - Timeout... */
533 {
534 FILE *fp; /* Job file */
535 char localhost[255]; /* Local host name */
536 int error; /* Error number */
537 struct stat filestats; /* File statistics */
538 int lport; /* LPD connection local port */
539 int fd; /* LPD socket */
540 char control[10240], /* LPD control 'file' */
541 *cptr; /* Pointer into control file string */
542 char status; /* Status byte from command */
543 struct sockaddr_in addr; /* Socket address */
544 struct hostent *hostaddr; /* Host address */
545 int copy; /* Copies written */
546 size_t nbytes, /* Number of bytes written */
547 tbytes; /* Total bytes written */
548 char buffer[8192]; /* Output buffer */
549 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
550 struct sigaction action; /* Actions for POSIX signals */
551 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
552
553
554 /*
555 * Setup an alarm handler for timeouts...
556 */
557
558 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
559 sigset(SIGALRM, lpd_timeout);
560 #elif defined(HAVE_SIGACTION)
561 memset(&action, 0, sizeof(action));
562
563 sigemptyset(&action.sa_mask);
564 action.sa_handler = lpd_timeout;
565 sigaction(SIGALRM, &action, NULL);
566 #else
567 signal(SIGALRM, lpd_timeout);
568 #endif /* HAVE_SIGSET */
569
570 /*
571 * Loop forever trying to print the file...
572 */
573
574 for (;;) /* FOREVER */
575 {
576 /*
577 * First try to reserve a port for this connection...
578 */
579
580 if ((hostaddr = httpGetHostByName(hostname)) == NULL)
581 {
582 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
583 hostname, hstrerror(h_errno));
584 return (1);
585 }
586
587 fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
588 hostname, printer);
589
590 memset(&addr, 0, sizeof(addr));
591 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
592 addr.sin_family = hostaddr->h_addrtype;
593 addr.sin_port = htons(port);
594
595 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024;;)
596 {
597 /*
598 * Choose the next priviledged port...
599 */
600
601 lport --;
602
603 if (lport < 721 && reserve == RESERVE_RFC1179)
604 lport = 731;
605 else if (lport < 1)
606 lport = 1023;
607
608 #ifdef HAVE_GETEUID
609 if (geteuid() || !reserve)
610 #else
611 if (getuid() || !reserve)
612 #endif /* HAVE_GETEUID */
613 {
614 /*
615 * Just create a regular socket...
616 */
617
618 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
619 {
620 perror("ERROR: Unable to create socket");
621 return (1);
622 }
623
624 lport = 0;
625 }
626 else
627 {
628 /*
629 * We're running as root and want to comply with RFC 1179. Reserve a
630 * priviledged lport between 721 and 731...
631 */
632
633 if ((fd = rresvport(&lport)) < 0)
634 {
635 perror("ERROR: Unable to reserve port");
636 sleep(1);
637
638 continue;
639 }
640 }
641
642 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
643 {
644 error = errno;
645 close(fd);
646 fd = -1;
647
648 if (error == ECONNREFUSED || error == EHOSTDOWN ||
649 error == EHOSTUNREACH)
650 {
651 fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
652 hostname);
653 sleep(30);
654 }
655 else if (error == EADDRINUSE)
656 {
657 /*
658 * Try on another port...
659 */
660
661 sleep(1);
662 }
663 else
664 {
665 perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
666 sleep(30);
667 }
668 }
669 else
670 break;
671 }
672
673 fprintf(stderr, "INFO: Connected to %s...\n", hostname);
674 fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
675 lport);
676
677 /*
678 * Next, open the print file and figure out its size...
679 */
680
681 if (stat(filename, &filestats))
682 {
683 perror("ERROR: unable to stat print file");
684 return (1);
685 }
686
687 filestats.st_size *= manual_copies;
688
689 if ((fp = fopen(filename, "rb")) == NULL)
690 {
691 perror("ERROR: unable to open print file for reading");
692 return (1);
693 }
694
695 /*
696 * Send a job header to the printer, specifying no banner page and
697 * literal output...
698 */
699
700 if (lpd_command(fd, timeout, "\002%s\n",
701 printer)) /* Receive print job(s) */
702 return (1);
703
704 gethostname(localhost, sizeof(localhost));
705 localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
706
707 snprintf(control, sizeof(control), "H%s\nP%s\nJ%s\n", localhost, user,
708 title);
709 cptr = control + strlen(control);
710
711 if (banner)
712 {
713 snprintf(cptr, sizeof(control) - (cptr - control), "C%s\nL%s\n",
714 localhost, user);
715 cptr += strlen(cptr);
716 }
717
718 while (copies > 0)
719 {
720 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n", format,
721 getpid() % 1000, localhost);
722 cptr += strlen(cptr);
723 copies --;
724 }
725
726 snprintf(cptr, sizeof(control) - (cptr - control),
727 "UdfA%03d%.15s\nN%s\n",
728 getpid() % 1000, localhost, title);
729
730 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
731
732 if (order == ORDER_CONTROL_DATA)
733 {
734 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
735 getpid() % 1000, localhost))
736 return (1);
737
738 fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
739 (unsigned long)strlen(control));
740
741 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
742 {
743 status = errno;
744 perror("ERROR: Unable to write control file");
745 }
746 else
747 {
748 alarm(timeout);
749
750 if (read(fd, &status, 1) < 1)
751 {
752 fprintf(stderr, "WARNING: Remote host did not respond with control "
753 "status byte after %d seconds!\n", timeout);
754 status = errno;
755 }
756
757 alarm(0);
758 }
759
760 if (status != 0)
761 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
762 status);
763 else
764 fputs("INFO: Control file sent successfully\n", stderr);
765 }
766 else
767 status = 0;
768
769 if (status == 0)
770 {
771 /*
772 * Send the print file...
773 */
774
775 if (lpd_command(fd, timeout, "\003%u dfA%03.3d%.15s\n",
776 (unsigned)filestats.st_size, getpid() % 1000,
777 localhost))
778 return (1);
779
780 fprintf(stderr, "INFO: Sending data file (%u bytes)\n",
781 (unsigned)filestats.st_size);
782
783 tbytes = 0;
784 for (copy = 0; copy < manual_copies; copy ++)
785 {
786 rewind(fp);
787
788 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
789 {
790 fprintf(stderr, "INFO: Spooling LPR job, %u%% complete...\n",
791 (unsigned)(100.0f * tbytes / filestats.st_size));
792
793 if (lpd_write(fd, buffer, nbytes) < nbytes)
794 {
795 perror("ERROR: Unable to send print file to printer");
796 break;
797 }
798 else
799 tbytes += nbytes;
800 }
801 }
802
803 if (tbytes < filestats.st_size)
804 status = errno;
805 else if (lpd_write(fd, "", 1) < 1)
806 {
807 perror("ERROR: Unable to send trailing nul to printer");
808 status = errno;
809 }
810 else
811 {
812 /*
813 * Read the status byte from the printer; if we can't read the byte
814 * back now, we should set status to "errno", however at this point
815 * we know the printer got the whole file and we don't necessarily
816 * want to requeue it over and over...
817 */
818
819 alarm(timeout);
820
821 if (recv(fd, &status, 1, 0) < 1)
822 {
823 fprintf(stderr, "WARNING: Remote host did not respond with data "
824 "status byte after %d seconds!\n", timeout);
825 status = 0;
826 }
827
828 alarm(0);
829 }
830
831 if (status != 0)
832 fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
833 status);
834 else
835 fputs("INFO: Data file sent successfully\n", stderr);
836 }
837
838 if (status == 0 && order == ORDER_DATA_CONTROL)
839 {
840 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
841 getpid() % 1000, localhost))
842 return (1);
843
844 fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
845 (unsigned long)strlen(control));
846
847 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
848 {
849 status = errno;
850 perror("ERROR: Unable to write control file");
851 }
852 else
853 {
854 alarm(timeout);
855
856 if (read(fd, &status, 1) < 1)
857 {
858 fprintf(stderr, "WARNING: Remote host did not respond with control "
859 "status byte after %d seconds!\n", timeout);
860 status = errno;
861 }
862
863 alarm(0);
864 }
865
866 if (status != 0)
867 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
868 status);
869 else
870 fputs("INFO: Control file sent successfully\n", stderr);
871 }
872
873 /*
874 * Close the socket connection and input file...
875 */
876
877 close(fd);
878 fclose(fp);
879
880 if (status == 0)
881 return (0);
882
883 /*
884 * Waiting for a retry...
885 */
886
887 sleep(30);
888 }
889 }
890
891
892 /*
893 * 'lpd_timeout()' - Handle timeout alarms...
894 */
895
896 static void
897 lpd_timeout(int sig) /* I - Signal number */
898 {
899 (void)sig;
900
901 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
902 signal(SIGALRM, lpd_timeout);
903 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
904 }
905
906
907 /*
908 * 'lpd_write()' - Write a buffer of data to an LPD server.
909 */
910
911 static int /* O - Number of bytes written or -1 on error */
912 lpd_write(int lpd_fd, /* I - LPD socket */
913 char *buffer, /* I - Buffer to write */
914 int length) /* I - Number of bytes to write */
915 {
916 int bytes, /* Number of bytes written */
917 total; /* Total number of bytes written */
918
919
920 total = 0;
921 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
922 {
923 total += bytes;
924 buffer += bytes;
925
926 if (total == length)
927 break;
928 }
929
930 if (bytes < 0)
931 return (-1);
932 else
933 return (length);
934 }
935
936
937 #ifndef HAVE_RRESVPORT
938 /*
939 * 'rresvport()' - A simple implementation of rresvport().
940 */
941
942 int /* O - Socket or -1 on error */
943 rresvport(int *port) /* IO - Port number to bind to */
944 {
945 struct sockaddr_in addr; /* Socket address */
946 int fd; /* Socket file descriptor */
947
948
949 /*
950 * Try to create an IPv4 socket...
951 */
952
953 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
954 return (-1);
955
956 /*
957 * Initialize the address buffer...
958 */
959
960 memset(&addr, 0, sizeof(addr));
961
962 addr.sin_family = AF_INET;
963 addr.sin_addr.s_addr = INADDR_ANY;
964
965 /*
966 * Try to bind the socket to a reserved port; unlike the standard
967 * BSD rresvport(), we limit the port number to 721 through 732
968 * (instead of 512 to 1023) since RFC 1179 defines the local port
969 * number between 721 and 732...
970 */
971
972 while (*port > 720)
973 {
974 /*
975 * Set the port number...
976 */
977
978 addr.sin_port = htons(*port);
979
980 /*
981 * Try binding the port to the socket; return if all is OK...
982 */
983
984 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
985 return (fd);
986
987 /*
988 * Stop if we have any error other than "address already in use"...
989 */
990
991 if (errno != EADDRINUSE)
992 {
993 # ifdef WIN32
994 closesocket(fd);
995 # else
996 close(fd);
997 # endif /* WIN32 */
998
999 return (-1);
1000 }
1001
1002 /*
1003 * Try the next port...
1004 */
1005
1006 (*port)--;
1007 }
1008
1009 /*
1010 * Wasn't able to bind to a reserved port, so close the socket and return
1011 * -1...
1012 */
1013
1014 # ifdef WIN32
1015 closesocket(fd);
1016 # else
1017 close(fd);
1018 # endif /* WIN32 */
1019
1020 return (-1);
1021 }
1022 #endif /* !HAVE_RRESVPORT */
1023
1024
1025 /*
1026 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1027 */
1028
1029 static void
1030 sigterm_handler(int sig) /* I - Signal */
1031 {
1032 (void)sig; /* remove compiler warnings... */
1033
1034 /*
1035 * Remove the temporary file if necessary...
1036 */
1037
1038 if (tmpfilename[0])
1039 unlink(tmpfilename);
1040
1041 exit(1);
1042 }
1043
1044
1045 /*
1046 * End of "$Id$".
1047 */