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