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 * 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 * 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 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 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