]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
2 * "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $"
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
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_af() - A simple implementation of rresvport_af().
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
38 * Include necessary headers.
41 #include <cups/backend.h>
42 #include <cups/http-private.h>
43 #include <cups/cups.h>
48 #include <cups/string.h>
50 #include <sys/types.h>
57 # include <sys/socket.h>
58 # include <netinet/in.h>
59 # include <arpa/inet.h>
68 static char tmpfilename
[1024] = ""; /* Temporary spool file name */
69 static int abort_job
= 0; /* Non-zero if we get SIGTERM */
73 * The order for control and data files in LPD requests...
76 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
77 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
84 #define RESERVE_NONE 0 /* Don't reserve a priviledged port */
85 #define RESERVE_RFC1179 1 /* Reserve port 721-731 */
86 #define RESERVE_ANY 2 /* Reserve port 1-1023 */
93 static int lpd_command(int lpd_fd
, int timeout
, char *format
, ...);
94 static int lpd_queue(const char *hostname
, int port
, const char *printer
,
96 const char *user
, const char *title
, int copies
,
97 int banner
, int format
, int order
, int reserve
,
98 int manual_copies
, int timeout
);
99 static void lpd_timeout(int sig
);
100 static int lpd_write(int lpd_fd
, char *buffer
, int length
);
101 #ifndef HAVE_RRESVPORT_AF
102 static int rresvport_af(int *port
, int family
);
103 #endif /* !HAVE_RRESVPORT_AF */
104 static void sigterm_handler(int sig
);
108 * 'main()' - Send a file to the printer or server.
112 * printer-uri job-id user title copies options [file]
115 int /* O - Exit status */
116 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
117 char *argv
[]) /* I - Command-line arguments */
119 char method
[255], /* Method in URI */
120 hostname
[1024], /* Hostname */
121 username
[255], /* Username info */
122 resource
[1024], /* Resource info (printer name) */
123 *options
, /* Pointer to options */
124 name
[255], /* Name of option */
125 value
[255], /* Value of option */
126 *ptr
, /* Pointer into name or value */
127 *filename
, /* File to print */
128 title
[256]; /* Title string */
129 int port
; /* Port number */
130 int status
; /* Status of LPD job */
131 int banner
; /* Print banner page? */
132 int format
; /* Print format */
133 int order
; /* Order of control/data files */
134 int reserve
; /* Reserve priviledged port? */
135 int sanitize_title
; /* Sanitize title string? */
136 int manual_copies
, /* Do manual copies? */
137 timeout
, /* Timeout */
138 copies
; /* Number of copies */
139 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
140 struct sigaction action
; /* Actions for POSIX signals */
141 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
145 * Make sure status messages are not buffered...
148 setbuf(stderr
, NULL
);
151 * Ignore SIGPIPE and catch SIGTERM signals...
155 sigset(SIGPIPE
, SIG_IGN
);
156 sigset(SIGTERM
, sigterm_handler
);
157 #elif defined(HAVE_SIGACTION)
158 memset(&action
, 0, sizeof(action
));
159 action
.sa_handler
= SIG_IGN
;
160 sigaction(SIGPIPE
, &action
, NULL
);
162 sigemptyset(&action
.sa_mask
);
163 sigaddset(&action
.sa_mask
, SIGTERM
);
164 action
.sa_handler
= sigterm_handler
;
165 sigaction(SIGTERM
, &action
, NULL
);
167 signal(SIGPIPE
, SIG_IGN
);
168 signal(SIGTERM
, sigterm_handler
);
169 #endif /* HAVE_SIGSET */
172 * Check command-line...
177 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
178 return (CUPS_BACKEND_OK
);
180 else if (argc
< 6 || argc
> 7)
182 fprintf(stderr
, "Usage: %s job-id user title copies options [file]\n",
184 return (CUPS_BACKEND_FAILED
);
188 * If we have 7 arguments, print the file named on the command-line.
189 * Otherwise, copy stdin to a temporary file and print the temporary
196 * Copy stdin to a temporary file...
199 int fd
; /* Temporary file */
200 char buffer
[8192]; /* Buffer for copying */
201 int bytes
; /* Number of bytes read */
204 if ((fd
= cupsTempFd(tmpfilename
, sizeof(tmpfilename
))) < 0)
206 perror("ERROR: unable to create temporary file");
207 return (CUPS_BACKEND_FAILED
);
210 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
211 if (write(fd
, buffer
, bytes
) < bytes
)
213 perror("ERROR: unable to write to temporary file");
216 return (CUPS_BACKEND_FAILED
);
220 filename
= tmpfilename
;
226 * Extract the hostname and printer name from the URI...
229 httpSeparateURI(argv
[0], method
, sizeof(method
), username
, sizeof(username
),
230 hostname
, sizeof(hostname
), &port
,
231 resource
, sizeof(resource
));
236 * If no username is in the device URI, then use the print job user...
239 strlcpy(username
, argv
[2], sizeof(username
));
243 * See if there are any options...
248 order
= ORDER_CONTROL_DATA
;
249 reserve
= RESERVE_ANY
;
254 #if defined(__APPLE__)
255 /* We want to pass utf-8 characters, not re-map them (3071945) */
259 if ((options
= strchr(resource
, '?')) != NULL
)
262 * Yup, terminate the device name string and move to the first
263 * character of the options...
278 for (ptr
= name
; *options
&& *options
!= '=';)
279 if (ptr
< (name
+ sizeof(name
) - 1))
291 for (ptr
= value
; *options
&& *options
!= '+' && *options
!= '&';)
292 if (ptr
< (value
+ sizeof(value
) - 1))
303 * Process the option...
306 if (strcasecmp(name
, "banner") == 0)
312 banner
= !value
[0] ||
313 strcasecmp(value
, "on") == 0 ||
314 strcasecmp(value
, "yes") == 0 ||
315 strcasecmp(value
, "true") == 0;
317 else if (strcasecmp(name
, "format") == 0 && value
[0])
320 * Set output format...
323 if (strchr("cdfglnoprtv", value
[0]) != NULL
)
326 fprintf(stderr
, "ERROR: Unknown format character \"%c\"\n", value
[0]);
328 else if (strcasecmp(name
, "order") == 0 && value
[0])
331 * Set control/data order...
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
;
339 fprintf(stderr
, "ERROR: Unknown file order \"%s\"\n", value
);
341 else if (strcasecmp(name
, "reserve") == 0)
344 * Set port reservation mode...
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
;
356 reserve
= RESERVE_NONE
;
358 else if (strcasecmp(name
, "manual_copies") == 0)
361 * Set manual copies...
364 manual_copies
= !value
[0] ||
365 strcasecmp(value
, "on") == 0 ||
366 strcasecmp(value
, "yes") == 0 ||
367 strcasecmp(value
, "true") == 0;
369 else if (strcasecmp(name
, "sanitize_title") == 0)
372 * Set sanitize title...
375 sanitize_title
= !value
[0] ||
376 strcasecmp(value
, "on") == 0 ||
377 strcasecmp(value
, "yes") == 0 ||
378 strcasecmp(value
, "true") == 0;
380 else if (strcasecmp(name
, "timeout") == 0)
387 timeout
= atoi(value
);
393 * Sanitize the document title...
396 strlcpy(title
, argv
[3], sizeof(title
));
401 * Sanitize the title string so that we don't cause problems on
405 for (ptr
= title
; *ptr
; ptr
++)
406 if (!isalnum(*ptr
& 255) && !isspace(*ptr
& 255))
418 manual_copies
= atoi(argv
[4]);
424 copies
= atoi(argv
[4]);
427 status
= lpd_queue(hostname
, port
, resource
+ 1, filename
,
428 username
, title
, copies
,
429 banner
, format
, order
, reserve
, manual_copies
, timeout
);
432 fprintf(stderr
, "PAGE: 1 %d\n", atoi(argv
[4]));
435 status
= lpd_queue(hostname
, port
, resource
+ 1, filename
,
437 banner
, format
, order
, reserve
, 1, timeout
);
440 * Remove the temporary file if necessary...
447 * Return the queue status...
455 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
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 */
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 */
471 * Don't try to send commands if the job has been cancelled...
478 * Format the string...
481 va_start(ap
, format
);
482 bytes
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
485 fprintf(stderr
, "DEBUG: lpd_command %2.2x %s", buf
[0], buf
+ 1);
488 * Send the command...
491 fprintf(stderr
, "DEBUG: Sending command string (%d bytes)...\n", bytes
);
493 if (lpd_write(fd
, buf
, bytes
) < bytes
)
495 perror("ERROR: Unable to send LPD command");
500 * Read back the status from the command and return it...
503 fprintf(stderr
, "DEBUG: Reading command status...\n");
507 if (recv(fd
, &status
, 1, 0) < 1)
509 fprintf(stderr
, "WARNING: Remote host did not respond with command "
510 "status byte after %d seconds!\n", timeout
);
516 fprintf(stderr
, "DEBUG: lpd_command returning %d\n", status
);
523 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
526 static int /* O - Zero on success, non-zero on failure */
527 lpd_queue(const char *hostname
, /* I - Host to connect to */
528 int port
, /* I - Port to connect on */
529 const char *printer
, /* I - Printer/queue name */
530 const char *filename
, /* I - File to print */
531 const char *user
, /* I - Requesting user */
532 const char *title
, /* I - Job title */
533 int copies
, /* I - Number of copies */
534 int banner
, /* I - Print LPD banner? */
535 int format
, /* I - Format specifier */
536 int order
, /* I - Order of data/control files */
537 int reserve
, /* I - Reserve ports? */
538 int manual_copies
, /* I - Do copies by hand... */
539 int timeout
) /* I - Timeout... */
541 FILE *fp
; /* Job file */
542 char localhost
[255]; /* Local host name */
543 int error
; /* Error number */
544 struct stat filestats
; /* File statistics */
545 int lport
; /* LPD connection local port */
546 int fd
; /* LPD socket */
547 char control
[10240], /* LPD control 'file' */
548 *cptr
; /* Pointer into control file string */
549 char status
; /* Status byte from command */
550 char portname
[255]; /* Port name */
551 http_addrlist_t
*addrlist
, /* Address list */
552 *addr
; /* Socket address */
553 int copy
; /* Copies written */
554 size_t nbytes
; /* Number of bytes written */
555 off_t tbytes
; /* Total bytes written */
556 char buffer
[65536]; /* Output buffer */
557 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
558 struct sigaction action
; /* Actions for POSIX signals */
559 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
563 * Setup an alarm handler for timeouts...
566 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
567 sigset(SIGALRM
, lpd_timeout
);
568 #elif defined(HAVE_SIGACTION)
569 memset(&action
, 0, sizeof(action
));
571 sigemptyset(&action
.sa_mask
);
572 action
.sa_handler
= lpd_timeout
;
573 sigaction(SIGALRM
, &action
, NULL
);
575 signal(SIGALRM
, lpd_timeout
);
576 #endif /* HAVE_SIGSET */
579 * Find the printer...
582 sprintf(portname
, "%d", port
);
584 if ((addrlist
= httpAddrGetList(hostname
, AF_UNSPEC
, portname
)) == NULL
)
586 fprintf(stderr
, "ERROR: Unable to locate printer \'%s\'!\n",
588 return (CUPS_BACKEND_STOP
);
592 * Loop forever trying to print the file...
598 * First try to reserve a port for this connection...
601 fprintf(stderr
, "INFO: Attempting to connect to host %s for printer %s\n",
604 for (lport
= reserve
== RESERVE_RFC1179
? 732 : 1024, addr
= addrlist
;;
608 * Stop if this job has been cancelled...
613 httpAddrFreeList(addrlist
);
615 return (CUPS_BACKEND_FAILED
);
619 * Choose the next priviledged port...
627 if (lport
< 721 && reserve
== RESERVE_RFC1179
)
633 if (geteuid() || !reserve
)
635 if (getuid() || !reserve
)
636 #endif /* HAVE_GETEUID */
639 * Just create a regular socket...
642 if ((fd
= socket(addr
->addr
.addr
.sa_family
, SOCK_STREAM
, 0)) < 0)
644 perror("ERROR: Unable to create socket");
655 * We're running as root and want to comply with RFC 1179. Reserve a
656 * priviledged lport between 721 and 731...
659 if ((fd
= rresvport_af(&lport
, addr
->addr
.addr
.sa_family
)) < 0)
661 perror("ERROR: Unable to reserve port");
669 * Connect to the printer or server...
674 httpAddrFreeList(addrlist
);
678 return (CUPS_BACKEND_FAILED
);
681 if (!connect(fd
, &(addr
->addr
.addr
), httpAddrLength(&(addr
->addr
))))
691 if (getenv("CLASS") != NULL
)
694 * If the CLASS environment variable is set, the job was submitted
695 * to a class and not to a specific queue. In this case, we want
696 * to abort immediately so that the job can be requeued on the next
697 * available printer in the class.
700 fprintf(stderr
, "INFO: Unable to connect to %s, queuing on next printer in class...\n",
703 httpAddrFreeList(addrlist
);
706 * Sleep 5 seconds to keep the job from requeuing too rapidly...
711 return (CUPS_BACKEND_FAILED
);
714 if (error
== ECONNREFUSED
|| error
== EHOSTDOWN
||
715 error
== EHOSTUNREACH
)
717 fprintf(stderr
, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
721 else if (error
== EADDRINUSE
)
724 * Try on another port...
731 perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
736 fprintf(stderr
, "INFO: Connected to %s...\n", hostname
);
737 fprintf(stderr
, "DEBUG: Connected on ports %d (local %d)...\n", port
,
741 * Next, open the print file and figure out its size...
744 if (stat(filename
, &filestats
))
746 httpAddrFreeList(addrlist
);
749 perror("ERROR: unable to stat print file");
750 return (CUPS_BACKEND_FAILED
);
753 filestats
.st_size
*= manual_copies
;
755 if ((fp
= fopen(filename
, "rb")) == NULL
)
757 httpAddrFreeList(addrlist
);
760 perror("ERROR: unable to open print file for reading");
761 return (CUPS_BACKEND_FAILED
);
765 * Send a job header to the printer, specifying no banner page and
769 if (lpd_command(fd
, timeout
, "\002%s\n",
770 printer
)) /* Receive print job(s) */
772 httpAddrFreeList(addrlist
);
774 return (CUPS_BACKEND_FAILED
);
777 httpGetHostname(localhost
, sizeof(localhost
));
779 snprintf(control
, sizeof(control
),
780 "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
781 "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
782 "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
783 localhost
, user
, title
);
784 cptr
= control
+ strlen(control
);
788 snprintf(cptr
, sizeof(control
) - (cptr
- control
),
789 "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
792 cptr
+= strlen(cptr
);
797 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "%cdfA%03d%.15s\n",
798 format
, (int)getpid() % 1000, localhost
);
799 cptr
+= strlen(cptr
);
803 snprintf(cptr
, sizeof(control
) - (cptr
- control
),
805 "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
806 (int)getpid() % 1000, localhost
, title
);
808 fprintf(stderr
, "DEBUG: Control file is:\n%s", control
);
810 if (order
== ORDER_CONTROL_DATA
)
812 if (lpd_command(fd
, timeout
, "\002%d cfA%03.3d%.15s\n", strlen(control
),
813 (int)getpid() % 1000, localhost
))
815 httpAddrFreeList(addrlist
);
818 return (CUPS_BACKEND_FAILED
);
821 fprintf(stderr
, "INFO: Sending control file (%u bytes)\n",
822 (unsigned)strlen(control
));
824 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
827 perror("ERROR: Unable to write control file");
833 if (read(fd
, &status
, 1) < 1)
835 fprintf(stderr
, "WARNING: Remote host did not respond with control "
836 "status byte after %d seconds!\n", timeout
);
844 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
847 fputs("INFO: Control file sent successfully\n", stderr
);
855 * Send the print file...
858 if (lpd_command(fd
, timeout
, "\003" CUPS_LLFMT
" dfA%03.3d%.15s\n",
859 CUPS_LLCAST filestats
.st_size
, (int)getpid() % 1000,
862 httpAddrFreeList(addrlist
);
865 return (CUPS_BACKEND_FAILED
);
868 fprintf(stderr
, "INFO: Sending data file (" CUPS_LLFMT
" bytes)\n",
869 CUPS_LLCAST filestats
.st_size
);
872 for (copy
= 0; copy
< manual_copies
; copy
++)
876 while ((nbytes
= fread(buffer
, 1, sizeof(buffer
), fp
)) > 0)
878 fprintf(stderr
, "INFO: Spooling LPR job, %.0f%% complete...\n",
879 100.0 * tbytes
/ filestats
.st_size
);
881 if (lpd_write(fd
, buffer
, nbytes
) < nbytes
)
883 perror("ERROR: Unable to send print file to printer");
891 if (tbytes
< filestats
.st_size
)
893 else if (lpd_write(fd
, "", 1) < 1)
895 perror("ERROR: Unable to send trailing nul to printer");
901 * Read the status byte from the printer; if we can't read the byte
902 * back now, we should set status to "errno", however at this point
903 * we know the printer got the whole file and we don't necessarily
904 * want to requeue it over and over...
909 if (recv(fd
, &status
, 1, 0) < 1)
911 fprintf(stderr
, "WARNING: Remote host did not respond with data "
912 "status byte after %d seconds!\n", timeout
);
920 fprintf(stderr
, "ERROR: Remote host did not accept data file (%d)\n",
923 fputs("INFO: Data file sent successfully\n", stderr
);
926 if (status
== 0 && order
== ORDER_DATA_CONTROL
)
928 if (lpd_command(fd
, timeout
, "\002%d cfA%03.3d%.15s\n", strlen(control
),
929 (int)getpid() % 1000, localhost
))
931 httpAddrFreeList(addrlist
);
934 return (CUPS_BACKEND_FAILED
);
937 fprintf(stderr
, "INFO: Sending control file (%lu bytes)\n",
938 (unsigned long)strlen(control
));
940 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
943 perror("ERROR: Unable to write control file");
949 if (read(fd
, &status
, 1) < 1)
951 fprintf(stderr
, "WARNING: Remote host did not respond with control "
952 "status byte after %d seconds!\n", timeout
);
960 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
963 fputs("INFO: Control file sent successfully\n", stderr
);
967 * Close the socket connection and input file...
975 httpAddrFreeList(addrlist
);
977 return (CUPS_BACKEND_OK
);
981 * Waiting for a retry...
987 httpAddrFreeList(addrlist
);
990 * If we get here, then the job has been cancelled...
993 return (CUPS_BACKEND_FAILED
);
998 * 'lpd_timeout()' - Handle timeout alarms...
1002 lpd_timeout(int sig
) /* I - Signal number */
1006 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1007 signal(SIGALRM
, lpd_timeout
);
1008 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1013 * 'lpd_write()' - Write a buffer of data to an LPD server.
1016 static int /* O - Number of bytes written or -1 on error */
1017 lpd_write(int lpd_fd
, /* I - LPD socket */
1018 char *buffer
, /* I - Buffer to write */
1019 int length
) /* I - Number of bytes to write */
1021 int bytes
, /* Number of bytes written */
1022 total
; /* Total number of bytes written */
1029 while ((bytes
= send(lpd_fd
, buffer
, length
- total
, 0)) >= 0)
1034 if (total
== length
)
1045 #ifndef HAVE_RRESVPORT_AF
1047 * 'rresvport_af()' - A simple implementation of rresvport_af().
1050 static int /* O - Socket or -1 on error */
1051 rresvport_af(int *port
, /* IO - Port number to bind to */
1052 int family
) /* I - Address family */
1054 http_addr_t addr
; /* Socket address */
1055 int fd
; /* Socket file descriptor */
1059 * Try to create an IPv4 socket...
1062 if ((fd
= socket(family
, SOCK_STREAM
, 0)) < 0)
1066 * Initialize the address buffer...
1069 memset(&addr
, 0, sizeof(addr
));
1070 addr
.addr
.sa_family
= family
;
1073 * Try to bind the socket to a reserved port...
1079 * Set the port number...
1083 if (family
== AF_INET6
)
1084 addr
.ipv6
.sin6_port
= htons(*port
);
1086 # endif /* AF_INET6 */
1087 addr
.ipv4
.sin_port
= htons(*port
);
1090 * Try binding the port to the socket; return if all is OK...
1093 if (!bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)))
1097 * Stop if we have any error other than "address already in use"...
1100 if (errno
!= EADDRINUSE
)
1112 * Try the next port...
1119 * Wasn't able to bind to a reserved port, so close the socket and return
1131 #endif /* !HAVE_RRESVPORT_AF */
1135 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1139 sigterm_handler(int sig
) /* I - Signal */
1141 (void)sig
; /* remove compiler warnings... */
1148 * End of "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $".