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