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