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