1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 */
27
28 /* $Id: lpd-misc.c 155 2006-04-26 02:34:54Z ktou $ */
29
30 #define __EXTENSIONS__ /* for strtok_r() */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <sys/socket.h>
40 #include <errno.h>
41 #include <wait.h>
42 #include <stropts.h>
43 #include <papi_impl.h>
44
45 #include <config-site.h>
46
47 char *
fdgets(char * buf,size_t len,int fd)48 fdgets(char *buf, size_t len, int fd)
49 {
50 char tmp;
51 int count = 0;
52
53 memset(buf, 0, len);
54 while ((count < len) && (read(fd, &tmp, 1) > 0))
55 if ((buf[count++] = tmp) == '\n') break;
56
57 if (count != 0)
58 return (buf);
59 return (NULL);
60 }
61
62 char *
queue_name_from_uri(uri_t * uri)63 queue_name_from_uri(uri_t *uri)
64 {
65 char *result = NULL;
66
67 if ((uri != NULL) && (uri->path != NULL)) {
68 char *ptr = strrchr(uri->path, '/');
69
70 if (ptr == NULL)
71 result = uri->path;
72 else
73 result = ++ptr;
74 }
75
76 return (result);
77 }
78
79 static int
recvfd(int sockfd)80 recvfd(int sockfd)
81 {
82 int fd = -1;
83 #if defined(sun) && defined(unix) && defined(I_RECVFD)
84 struct strrecvfd recv_fd;
85
86 memset(&recv_fd, 0, sizeof (recv_fd));
87 if (ioctl(sockfd, I_RECVFD, &recv_fd) == 0)
88 fd = recv_fd.fd;
89 #else
90 struct iovec iov[1];
91 struct msghdr msg;
92
93 #ifdef CMSG_DATA
94 struct cmsghdr cmp[1];
95 char buf[24]; /* send/recv 2 byte protocol */
96
97 memset(buf, 0, sizeof (buf));
98
99 iov[0].iov_base = buf;
100 iov[0].iov_len = sizeof (buf);
101
102 msg.msg_control = cmp;
103 msg.msg_controllen = sizeof (struct cmsghdr) + sizeof (int);
104 #else
105 iov[0].iov_base = NULL;
106 iov[0].iov_len = 0;
107 msg.msg_accrights = (caddr_t)&fd;
108 msg.msg_accrights = sizeof (fd);
109 #endif
110 msg.msg_iov = iov;
111 msg.msg_iovlen = 1;
112 msg.msg_name = NULL;
113 msg.msg_namelen = 0;
114
115 if (recvmsg(sockfd, &msg, 0) < 0)
116 fd = -1;
117 #ifdef CMSG_DATA
118 else
119 fd = * (int *)CMSG_DATA(cmp);
120 #endif
121 #endif
122 return (fd);
123 }
124
125 int
lpd_open(service_t * svc,char type,char ** args,int timeout)126 lpd_open(service_t *svc, char type, char **args, int timeout)
127 {
128 int ac, rc = -1, fds[2];
129 pid_t pid;
130 char *av[64], *tmp, buf[BUFSIZ];
131
132 if ((svc == NULL) || (svc->uri == NULL))
133 return (-1);
134
135 #ifndef SUID_LPD_PORT
136 #define SUID_LPD_PORT "/usr/lib/print/lpd-port"
137 #endif
138
139 av[0] = SUID_LPD_PORT;
140 ac = 1;
141
142 /* server */
143 av[ac++] = "-H";
144 av[ac++] = svc->uri->host;
145
146 /* timeout */
147 if (timeout > 0) {
148 snprintf(buf, sizeof (buf), "%d", timeout);
149 av[ac++] = "-t";
150 av[ac++] = strdup(buf);
151 }
152
153 /* operation */
154 snprintf(buf, sizeof (buf), "-%c", type);
155 av[ac++] = buf;
156
157 /* queue */
158 if (svc->uri->path == NULL) {
159 tmp = "";
160 } else {
161 if ((tmp = strrchr(svc->uri->path, '/')) == NULL)
162 tmp = svc->uri->path;
163 else
164 tmp++;
165 }
166 av[ac++] = tmp;
167
168 /* args */
169 if (args != NULL)
170 while ((*args != NULL) && (ac < 62))
171 av[ac++] = *args++;
172
173 av[ac++] = NULL;
174
175 #if defined(sun) && defined(unix) && defined(I_RECVFD)
176 pipe(fds);
177 #else
178 socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
179 #endif
180
181 switch (pid = fork()) {
182 case -1: /* failed */
183 break;
184 case 0: /* child */
185 dup2(fds[1], 1);
186 execv(av[0], &av[0]);
187 perror("exec");
188 exit(1);
189 break;
190 default: { /* parent */
191 int err, status = 0;
192
193 while ((waitpid(pid, &status, 0) < 0) && (errno == EINTR))
194 ;
195 errno = WEXITSTATUS(status);
196
197 if (errno == 0)
198 rc = recvfd(fds[0]);
199
200 err = errno;
201 close(fds[0]);
202 close(fds[1]);
203 errno = err;
204 }
205 }
206
207 return (rc);
208 }
209