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, NULL, 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; ac = 1;
140
141 /* server */
142 av[ac++] = "-H";
143 av[ac++] = svc->uri->host;
144
145 /* timeout */
146 if (timeout > 0) {
147 snprintf(buf, sizeof (buf), "%d", timeout);
148 av[ac++] = "-t";
149 av[ac++] = strdup(buf);
150 }
151
152 /* operation */
153 snprintf(buf, sizeof (buf), "-%c", type);
154 av[ac++] = buf;
155
156 /* queue */
157 if (svc->uri->path == NULL) {
158 tmp = "";
159 } else {
160 if ((tmp = strrchr(svc->uri->path, '/')) == NULL)
161 tmp = svc->uri->path;
162 else
163 tmp++;
164 }
165 av[ac++] = tmp;
166
167 /* args */
168 if (args != NULL)
169 while ((*args != NULL) && (ac < 62))
170 av[ac++] = *args++;
171
172 av[ac++] = NULL;
173
174 #if defined(sun) && defined(unix) && defined(I_RECVFD)
175 pipe(fds);
176 #else
177 socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
178 #endif
179
180 switch (pid = fork()) {
181 case -1: /* failed */
182 break;
183 case 0: /* child */
184 dup2(fds[1], 1);
185 execv(av[0], &av[0]);
186 perror("exec");
187 exit(1);
188 break;
189 default: { /* parent */
190 int err, status = 0;
191
192 while ((waitpid(pid, &status, 0) < 0) && (errno == EINTR));
193 errno = WEXITSTATUS(status);
194
195 if (errno == 0)
196 rc = recvfd(fds[0]);
197
198 err = errno;
199 close(fds[0]);
200 close(fds[1]);
201 errno = err;
202 }
203 }
204
205 return (rc);
206 }
207