]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
2 * "$Id: lpd.c,v 1.28.2.29 2004/02/24 21:51:36 mike Exp $"
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 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-3111 USA
20 * Voice: (301) 373-9603
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() - A simple implementation of rresvport().
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
38 * Include necessary headers.
41 #include <cups/cups.h>
46 #include <cups/http-private.h>
47 #include <cups/string.h>
49 #include <sys/types.h>
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # include <arpa/inet.h>
67 static char tmpfilename
[1024] = ""; /* Temporary spool file name */
71 * The order for control and data files in LPD requests...
74 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
75 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
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 */
88 * It appears that rresvport() is never declared on most systems...
91 extern int rresvport(int *port
);
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
);
110 * 'main()' - Send a file to the printer or server.
114 * printer-uri job-id user title copies options [file]
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 */
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 */
147 * Make sure status messages are not buffered...
150 setbuf(stderr
, NULL
);
153 * Ignore SIGPIPE and catch SIGTERM signals...
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
);
164 sigemptyset(&action
.sa_mask
);
165 sigaddset(&action
.sa_mask
, SIGTERM
);
166 action
.sa_handler
= sigterm_handler
;
167 sigaction(SIGTERM
, &action
, NULL
);
169 signal(SIGPIPE
, SIG_IGN
);
170 signal(SIGTERM
, sigterm_handler
);
171 #endif /* HAVE_SIGSET */
174 * Check command-line...
179 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
182 else if (argc
< 6 || argc
> 7)
184 fprintf(stderr
, "Usage: %s job-id user title copies options [file]\n",
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
198 * Copy stdin to a temporary file...
201 int fd
; /* Temporary file */
202 char buffer
[8192]; /* Buffer for copying */
203 int bytes
; /* Number of bytes read */
206 if ((fd
= cupsTempFd(tmpfilename
, sizeof(tmpfilename
))) < 0)
208 perror("ERROR: unable to create temporary file");
212 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
213 if (write(fd
, buffer
, bytes
) < bytes
)
215 perror("ERROR: unable to write to temporary file");
222 filename
= tmpfilename
;
228 * Extract the hostname and printer name from the URI...
231 httpSeparate(argv
[0], method
, username
, hostname
, &port
, resource
);
234 * See if there are any options...
239 order
= ORDER_CONTROL_DATA
;
240 reserve
= RESERVE_ANY
;
245 #if defined(__APPLE__)
246 /* We want to pass utf-8 characters, not re-map them (3071945) */
250 if ((options
= strchr(resource
, '?')) != NULL
)
253 * Yup, terminate the device name string and move to the first
254 * character of the options...
269 for (ptr
= name
; *options
&& *options
!= '=';)
281 for (ptr
= value
; *options
&& *options
!= '+';)
292 * Process the option...
295 if (strcasecmp(name
, "banner") == 0)
301 banner
= !value
[0] ||
302 strcasecmp(value
, "on") == 0 ||
303 strcasecmp(value
, "yes") == 0 ||
304 strcasecmp(value
, "true") == 0;
306 else if (strcasecmp(name
, "format") == 0 && value
[0])
309 * Set output format...
312 if (strchr("cdfglnoprtv", value
[0]) != NULL
)
315 fprintf(stderr
, "ERROR: Unknown format character \"%c\"\n", value
[0]);
317 else if (strcasecmp(name
, "order") == 0 && value
[0])
320 * Set control/data order...
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
;
328 fprintf(stderr
, "ERROR: Unknown file order \"%s\"\n", value
);
330 else if (strcasecmp(name
, "reserve") == 0)
333 * Set port reservation mode...
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
;
345 reserve
= RESERVE_NONE
;
347 else if (strcasecmp(name
, "manual_copies") == 0)
350 * Set manual copies...
353 manual_copies
= !value
[0] ||
354 strcasecmp(value
, "on") == 0 ||
355 strcasecmp(value
, "yes") == 0 ||
356 strcasecmp(value
, "true") == 0;
358 else if (strcasecmp(name
, "sanitize_title") == 0)
361 * Set sanitize title...
364 sanitize_title
= !value
[0] ||
365 strcasecmp(value
, "on") == 0 ||
366 strcasecmp(value
, "yes") == 0 ||
367 strcasecmp(value
, "true") == 0;
369 else if (strcasecmp(name
, "timeout") == 0)
376 timeout
= atoi(value
);
382 * Sanitize the document title...
385 strlcpy(title
, argv
[3], sizeof(title
));
390 * Sanitize the title string so that we don't cause problems on
394 for (ptr
= title
; *ptr
; ptr
++)
395 if (!isalnum(*ptr
) && !isspace(*ptr
))
407 manual_copies
= atoi(argv
[4]);
413 copies
= atoi(argv
[4]);
416 status
= lpd_queue(hostname
, port
, resource
+ 1, filename
,
417 argv
[2] /* user */, title
, copies
,
418 banner
, format
, order
, reserve
, manual_copies
, timeout
);
421 fprintf(stderr
, "PAGE: 1 %d\n", atoi(argv
[4]));
424 status
= lpd_queue(hostname
, port
, resource
+ 1, filename
,
425 argv
[2] /* user */, title
, 1,
426 banner
, format
, order
, reserve
, 1, timeout
);
429 * Remove the temporary file if necessary...
436 * Return the queue status...
444 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
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 */
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 */
460 * Format the string...
463 va_start(ap
, format
);
464 bytes
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
467 fprintf(stderr
, "DEBUG: lpd_command %2.2x %s", buf
[0], buf
+ 1);
470 * Send the command...
473 fprintf(stderr
, "DEBUG: Sending command string (%d bytes)...\n", bytes
);
475 if (lpd_write(fd
, buf
, bytes
) < bytes
)
477 perror("ERROR: Unable to send LPD command");
482 * Read back the status from the command and return it...
485 fprintf(stderr
, "DEBUG: Reading command status...\n");
489 if (recv(fd
, &status
, 1, 0) < 1)
491 fprintf(stderr
, "WARNING: Remote host did not respond with command "
492 "status byte after %d seconds!\n", timeout
);
498 fprintf(stderr
, "DEBUG: lpd_command returning %d\n", status
);
505 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
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... */
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 */
544 * Setup an alarm handler for timeouts...
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
));
552 sigemptyset(&action
.sa_mask
);
553 action
.sa_handler
= lpd_timeout
;
554 sigaction(SIGALRM
, &action
, NULL
);
556 signal(SIGALRM
, lpd_timeout
);
557 #endif /* HAVE_SIGSET */
560 * Loop forever trying to print the file...
563 for (;;) /* FOREVER */
566 * First try to reserve a port for this connection...
569 if ((hostaddr
= httpGetHostByName(hostname
)) == NULL
)
571 fprintf(stderr
, "ERROR: Unable to locate printer \'%s\' - %s\n",
572 hostname
, hstrerror(h_errno
));
576 fprintf(stderr
, "INFO: Attempting to connect to host %s for printer %s\n",
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
);
584 for (lport
= reserve
== RESERVE_RFC1179
? 732 : 1024;;)
587 * Choose the next priviledged port...
592 if (lport
< 721 && reserve
== RESERVE_RFC1179
)
597 if (getuid() || !reserve
)
600 * Just create a regular socket...
603 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
605 perror("ERROR: Unable to create socket");
614 * We're running as root and want to comply with RFC 1179. Reserve a
615 * priviledged lport between 721 and 731...
618 if ((fd
= rresvport(&lport
)) < 0)
620 perror("ERROR: Unable to reserve port");
627 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
633 if (error
== ECONNREFUSED
|| error
== EHOSTDOWN
||
634 error
== EHOSTUNREACH
)
636 fprintf(stderr
, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
640 else if (error
== EADDRINUSE
)
643 * Try on another port...
650 perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
658 fprintf(stderr
, "INFO: Connected to %s...\n", hostname
);
659 fprintf(stderr
, "DEBUG: Connected on ports %d (local %d)...\n", port
,
663 * Next, open the print file and figure out its size...
666 if (stat(filename
, &filestats
))
668 perror("ERROR: unable to stat print file");
672 filestats
.st_size
*= manual_copies
;
674 if ((fp
= fopen(filename
, "rb")) == NULL
)
676 perror("ERROR: unable to open print file for reading");
681 * Send a job header to the printer, specifying no banner page and
685 if (lpd_command(fd
, timeout
, "\002%s\n",
686 printer
)) /* Receive print job(s) */
689 gethostname(localhost
, sizeof(localhost
));
690 localhost
[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
692 snprintf(control
, sizeof(control
), "H%s\nP%s\nJ%s\n", localhost
, user
,
694 cptr
= control
+ strlen(control
);
698 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "C%s\nL%s\n",
700 cptr
+= strlen(cptr
);
705 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "%cdfA%03d%.15s\n", format
,
706 getpid() % 1000, localhost
);
707 cptr
+= strlen(cptr
);
711 snprintf(cptr
, sizeof(control
) - (cptr
- control
),
712 "UdfA%03d%.15s\nN%s\n",
713 getpid() % 1000, localhost
, title
);
715 fprintf(stderr
, "DEBUG: Control file is:\n%s", control
);
717 if (order
== ORDER_CONTROL_DATA
)
719 if (lpd_command(fd
, timeout
, "\002%d cfA%03.3d%.15s\n", strlen(control
),
720 getpid() % 1000, localhost
))
723 fprintf(stderr
, "INFO: Sending control file (%lu bytes)\n",
724 (unsigned long)strlen(control
));
726 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
729 perror("ERROR: Unable to write control file");
735 if (read(fd
, &status
, 1) < 1)
737 fprintf(stderr
, "WARNING: Remote host did not respond with control "
738 "status byte after %d seconds!\n", timeout
);
746 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
749 fputs("INFO: Control file sent successfully\n", stderr
);
757 * Send the print file...
760 if (lpd_command(fd
, timeout
, "\003%u dfA%03.3d%.15s\n",
761 (unsigned)filestats
.st_size
, getpid() % 1000,
765 fprintf(stderr
, "INFO: Sending data file (%u bytes)\n",
766 (unsigned)filestats
.st_size
);
769 for (copy
= 0; copy
< manual_copies
; copy
++)
773 while ((nbytes
= fread(buffer
, 1, sizeof(buffer
), fp
)) > 0)
775 fprintf(stderr
, "INFO: Spooling LPR job, %u%% complete...\n",
776 (unsigned)(100.0f
* tbytes
/ filestats
.st_size
));
778 if (lpd_write(fd
, buffer
, nbytes
) < nbytes
)
780 perror("ERROR: Unable to send print file to printer");
788 if (tbytes
< filestats
.st_size
)
790 else if (lpd_write(fd
, "", 1) < 1)
792 perror("ERROR: Unable to send trailing nul to printer");
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...
806 if (recv(fd
, &status
, 1, 0) < 1)
808 fprintf(stderr
, "WARNING: Remote host did not respond with data "
809 "status byte after %d seconds!\n", timeout
);
817 fprintf(stderr
, "ERROR: Remote host did not accept data file (%d)\n",
820 fputs("INFO: Data file sent successfully\n", stderr
);
823 if (status
== 0 && order
== ORDER_DATA_CONTROL
)
825 if (lpd_command(fd
, timeout
, "\002%d cfA%03.3d%.15s\n", strlen(control
),
826 getpid() % 1000, localhost
))
829 fprintf(stderr
, "INFO: Sending control file (%lu bytes)\n",
830 (unsigned long)strlen(control
));
832 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
835 perror("ERROR: Unable to write control file");
841 if (read(fd
, &status
, 1) < 1)
843 fprintf(stderr
, "WARNING: Remote host did not respond with control "
844 "status byte after %d seconds!\n", timeout
);
852 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
855 fputs("INFO: Control file sent successfully\n", stderr
);
859 * Close the socket connection and input file...
869 * Waiting for a retry...
878 * 'lpd_timeout()' - Handle timeout alarms...
882 lpd_timeout(int sig
) /* I - Signal number */
886 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
887 signal(SIGALRM
, lpd_timeout
);
888 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
893 * 'lpd_write()' - Write a buffer of data to an LPD server.
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 */
901 int bytes
, /* Number of bytes written */
902 total
; /* Total number of bytes written */
906 while ((bytes
= send(lpd_fd
, buffer
, length
- total
, 0)) >= 0)
922 #ifndef HAVE_RRESVPORT
924 * 'rresvport()' - A simple implementation of rresvport().
927 int /* O - Socket or -1 on error */
928 rresvport(int *port
) /* IO - Port number to bind to */
930 struct sockaddr_in addr
; /* Socket address */
931 int fd
; /* Socket file descriptor */
935 * Try to create an IPv4 socket...
938 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
942 * Initialize the address buffer...
945 memset(&addr
, 0, sizeof(addr
));
947 addr
.sin_family
= AF_INET
;
948 addr
.sin_addr
.s_addr
= INADDR_ANY
;
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...
960 * Set the port number...
963 addr
.sin_port
= htons(*port
);
966 * Try binding the port to the socket; return if all is OK...
969 if (!bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)))
973 * Stop if we have any error other than "address already in use"...
976 if (errno
!= EADDRINUSE
)
988 * Try the next port...
995 * Wasn't able to bind to a reserved port, so close the socket and return
1007 #endif /* !HAVE_RRESVPORT */
1011 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1015 sigterm_handler(int sig
) /* I - Signal */
1017 (void)sig
; /* remove compiler warnings... */
1020 * Remove the temporary file if necessary...
1024 unlink(tmpfilename
);
1031 * End of "$Id: lpd.c,v 1.28.2.29 2004/02/24 21:51:36 mike Exp $".