4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
41 #include <sys/utsname.h>
45 static void usage_exit();
47 static void pipehandler(int);
48 char data_file_type
= 0;
51 * null() is to be used as a signal handler that does nothing. It is used in
52 * place of SIG_IGN, because we want the signal to be delivered and
53 * interupt the current system call.
58 syslog(LOG_DEBUG
, "null(%d)", i
);
62 * net_open() opens a tcp connection to the printer port on the host specified
63 * in the arguments passed in. If the connection is not made in the
64 * timeout (in seconds) passed in, an error it returned. If the host is
65 * unknown, an error is returned. If all is well, a file descriptor is
66 * returned to be used for future communications.
69 net_open(char *host
, int timeout
)
73 struct sockaddr_in6 sin
;
74 void (*old_handler
)();
75 static struct utsname uts
;
83 syslog(LOG_DEBUG
, "net_open(%s, %d)", (host
!= NULL
? host
: "NULL"),
86 * Get the host address and port number to connect to.
92 (void) memset((char *)&sin
, NULL
, sizeof (sin
));
93 if ((hp
= getipnodebyname(host
, AF_INET6
, AI_DEFAULT
,
94 &error_num
)) == NULL
) {
95 syslog(LOG_DEBUG
|LOG_ERR
, "unknown host %s "
96 "getipnodebyname() returned %d", host
, error_num
);
97 return (NETWORK_ERROR_HOST
);
99 (void) memcpy((caddr_t
)&sin
.sin6_addr
, hp
->h_addr
, hp
->h_length
);
100 sin
.sin6_family
= hp
->h_addrtype
;
103 if ((sp
= getservbyname("printer", "tcp")) == NULL
) {
104 syslog(LOG_DEBUG
|LOG_ERR
, "printer/tcp: unknown service");
105 return (NETWORK_ERROR_SERVICE
);
107 sin
.sin6_port
= sp
->s_port
;
111 * Try connecting to the server.
113 * Use 0 as lport means that rresvport_af() will bind to a port in
114 * the anonymous privileged port range.
117 s
= rresvport_af(&lport
, AF_INET6
);
119 return (NETWORK_ERROR_PORT
);
121 old_handler
= signal(SIGALRM
, null
);
122 (void) alarm(timeout
);
123 if (connect(s
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
125 (void) signal(SIGALRM
, old_handler
);
129 if (errno
== EADDRINUSE
) {
133 * If connecting to the local system fails, try
134 * again with "localhost" address instead.
136 if (uts
.nodename
[0] == '\0')
138 if (strcmp(host
, uts
.nodename
) == 0) {
139 IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_LOOPBACK
),
141 sin
.sin6_family
= AF_INET6
;
144 if (errno
== ECONNREFUSED
&& timo
<= 16) {
149 return (NETWORK_ERROR_UNKNOWN
);
152 (void) signal(SIGALRM
, old_handler
);
157 main(int argc
, char *argv
[])
163 char *destination
= NULL
;
167 int pr_order
= CONTROL_FIRST
;
168 char *vendor_pr_name
= NULL
;
169 char *tcp_port
= NULL
;
178 (void) setlocale(LC_ALL
, "");
179 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
180 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
182 (void) textdomain(TEXT_DOMAIN
);
184 openlog("netpr", LOG_PID
, LOG_LPR
);
185 (void) signal(SIGPIPE
, pipehandler
);
187 /* reduce privileges until needed to open reserved port */
188 if (seteuid(getuid())) {
189 syslog(LOG_DEBUG
, "seteuid failed, exiting netpr");
193 if ((job_data
= init_job()) == NULL
) {
194 fprintf(stderr
, gettext("init_job(): out of memory\n"));
198 while ((opt
= getopt(argc
, argv
, "f:I:p:d:T:P:t:U:c:b")) != EOF
)
201 data_file_type
= optarg
[0];
203 case 'I': /* foo-49 */
204 job_data
->request_id
= alloc_str((char *)optarg
);
205 syslog(LOG_DEBUG
, "request_id: %s",
206 job_data
->request_id
);
208 case 'U': /* awe172-126!wendyp */
209 job_data
->username
= alloc_str((char *)optarg
);
210 syslog(LOG_DEBUG
, "username: %s", job_data
->username
);
213 job_data
->printer
= alloc_str((char *)optarg
);
214 syslog(LOG_DEBUG
, "printer: %s", job_data
->printer
);
216 case 'd': /* server for printer */
217 job_data
->dest
= alloc_str((char *)optarg
);
218 syslog(LOG_DEBUG
, "dest: %s", job_data
->dest
);
220 case 'T': /* /tmp/file2 */
221 job_data
->title
= alloc_str((char *)optarg
);
222 syslog(LOG_DEBUG
, "title: %s", job_data
->title
);
225 if ((strcmp(optarg
, "bsd")) == 0)
226 job_data
->protocol
= BSD
;
227 else if ((strcmp(optarg
, "tcp")) == 0)
228 job_data
->protocol
= TCP
;
232 syslog(LOG_DEBUG
, "protocol: %d", job_data
->protocol
);
235 job_data
->timeout
= atoi(optarg
);
236 if (job_data
->timeout
< 0)
240 if ((strcmp(optarg
, "first")) == 0)
241 pr_order
= CONTROL_FIRST
;
242 else if ((strcmp(optarg
, "last")) == 0)
243 pr_order
= DATA_FIRST
;
247 syslog(LOG_DEBUG
, "bsd print order: %d", pr_order
);
250 job_data
->banner
= NOBANNER
;
251 syslog(LOG_DEBUG
, "banner : %d", job_data
->banner
);
258 if ((job_data
->dest
== NULL
) || (job_data
->request_id
== NULL
) ||
259 (job_data
->printer
== NULL
) || (job_data
->username
== NULL
))
263 * Check that there is a file
265 if (optind
== argc
) {
269 job_data
->filename
= alloc_str(argv
[optind
]);
270 syslog(LOG_DEBUG
, "filename : %s", job_data
->filename
);
274 * Sanity check the file
278 if ((filesize
= check_file(job_data
->filename
)) == -1) {
279 syslog(LOG_DEBUG
, "Skipping file %s",
281 job_data
->filename
: "Error NULL file");
285 (void) fprintf(stderr
,
286 gettext("Netpr: %s: Not a regular file\n"),
288 job_data
->filename
: "Noname");
289 syslog(LOG_DEBUG
, "Not a regular file");
292 (void) fprintf(stderr
,
293 gettext("Netpr: %s: Empty file\n"),
295 job_data
->filename
: "Noname");
296 syslog(LOG_DEBUG
, "Empty file");
299 perror(job_data
->filename
);
300 (void) fprintf(stderr
,
301 gettext("Netpr: Cannot access file %s\n"),
303 job_data
->filename
: "Noname");
304 syslog(LOG_DEBUG
, "Cannot access file.");
310 * This file not valid, so bail
311 * Exit with zero so system will keep printing
317 * file looks ok, open and mmap it
319 if ((fd
= open(job_data
->filename
, O_RDONLY
)) < 0) {
320 (void) fprintf(stderr
, gettext("Netpr: Cannot open file %s\n"),
322 job_data
->filename
: "Error: NULL file");
323 syslog(LOG_DEBUG
, "Cannot open file: %s",
325 job_data
->filename
: "Error NULL file");
329 if ((pa
= mmap((caddr_t
)0, filesize
, PROT_READ
,
330 (MAP_SHARED
| MAP_NORESERVE
), fd
, (off_t
)0)) == MAP_FAILED
) {
333 (void) fprintf(stderr
, gettext("Netpr: Cannot mmap file %s"),
335 job_data
->filename
: "Error: NULL file");
337 syslog(LOG_DEBUG
, "Cannot mmap file: %s",
339 job_data
->filename
: "Error NULL file");
345 if (job_data
->protocol
== BSD
) {
346 bsdjob
= (np_bsdjob_t
*)
347 create_bsd_job(job_data
, pr_order
, filesize
);
351 tcpjob
= (np_tcpjob_t
*)create_tcp_job(job_data
, filesize
);
360 if ((strpbrk(job_data
->dest
, DEST_SEP
)) != NULL
) {
361 if (job_data
->protocol
== BSD
) {
362 parse_dest(job_data
->dest
, &destination
,
363 &vendor_pr_name
, DEST_SEP
);
364 if (vendor_pr_name
!= NULL
) {
365 bsdjob
->np_printer
= vendor_pr_name
;
366 syslog(LOG_DEBUG
, "bsd vendor name: %s",
370 parse_dest(job_data
->dest
, &destination
, &tcp_port
,
372 if (tcp_port
!= NULL
)
373 tcpjob
->np_port
= tcp_port
;
374 syslog(LOG_DEBUG
, "tcp_port %s", tcpjob
->np_port
);
376 if (destination
== NULL
||
377 (job_data
->protocol
== TCP
&& tcp_port
== NULL
)) {
378 (void) fprintf(stderr
, gettext("Netpr: system error "
379 "parsing destination %s\n"), job_data
->dest
);
380 syslog(LOG_DEBUG
, "system error parsing destination %s",
387 destination
= job_data
->dest
;
389 syslog(LOG_DEBUG
, "destination : %s", destination
);
392 * We are now ready to open a connection to the printer
393 * and print each of the files
396 if (job_data
->protocol
== BSD
) {
398 /* set privileges to get reserved port */
400 syslog(LOG_DEBUG
, "seteuid(0) failed, exiting netpr");
403 if ((sockfd
= net_open(destination
, 20)) < 0) {
404 (void) fprintf(stderr
,
405 gettext("Netpr: Cannot open connection to <%s>\n"),
408 "Cannot open connection to %s: retrying",
413 if ((sockfd
= tcp_open(destination
, tcpjob
, 20)) == -1) {
418 /* lower privileges as we now have the reserved port */
419 if (setuid(getuid())) {
420 syslog(LOG_DEBUG
, "setuid() failed, exiting netpr");
425 /* Set SO_KEEPALIVE on socket to keep open */
426 if ((setsockopt(sockfd
, SOL_SOCKET
, SO_KEEPALIVE
,
427 (char *)&on
, sizeof (on
))) < 0) {
428 syslog(LOG_DEBUG
, "setsocket (SO_KEEPALIVE): %m");
431 if (job_data
->protocol
== BSD
) {
432 if ((jobstatus
= bsd_print(sockfd
, pa
, bsdjob
)) != 0) {
433 (void) fprintf(stderr
, gettext("Netpr: Error return "
434 "from bsd_print <%d>\n"), jobstatus
);
436 "Error return from bsd_print <%d>", jobstatus
);
437 exit_status
= E_RETRY
;
441 tcp_print(sockfd
, pa
, tcpjob
)) != 0) {
442 (void) fprintf(stderr
, gettext("Netpr: Error return "
443 "from tcp_print <%d>\n"), jobstatus
);
445 "Error return from tcp_print <%d>", jobstatus
);
446 exit_status
= E_RETRY
;
451 (void) close(sockfd
);
452 (void) munmap(pa
, filesize
);
454 syslog(LOG_DEBUG
, "exit status: %d", exit_status
);
455 return (exit_status
);
461 (void) fprintf(stderr
,
462 gettext("Usage: netpr -I request_id -p printer -d destination\n"));
463 (void) fprintf(stderr
,
464 gettext("\t\t-U username [ -f type ] [ -T title ] [ -P protocol ]\n"));
465 (void) fprintf(stderr
,
466 gettext("\t\t[-t timeout] [ -c ] [ -b ]\n"));
467 (void) fprintf(stderr
, gettext("\t\tfiles\n"));
475 (void) signal(SIGPIPE
, pipehandler
);
476 syslog(LOG_DEBUG
, "Received SIGPIPE, connection to printer broken");