1/* 2 * socket.c - Unix domain socket module 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 2002 Peter Stephenson 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Peter Stephenson or the Zsh Development 16 * Group be liable to any party for direct, indirect, special, incidental, 17 * or consequential damages arising out of the use of this software and 18 * its documentation, even if Peter Stephenson, and the Zsh 19 * Development Group have been advised of the possibility of such damage. 20 * 21 * Peter Stephenson and the Zsh Development Group specifically 22 * disclaim any warranties, including, but not limited to, the implied 23 * warranties of merchantability and fitness for a particular purpose. The 24 * software provided hereunder is on an "as is" basis, and Peter Stephenson 25 * and the Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "socket.mdh" 31#include "socket.pro" 32 33#include <sys/socket.h> 34#include <sys/un.h> 35 36/* 37 * We need to include the zsh headers later to avoid clashes with 38 * the definitions on some systems, however we need the configuration 39 * file to decide whether we can include netinet/in_systm.h, which 40 * doesn't exist on cygwin. 41 */ 42 43/* 44 * We use poll() in preference to select because some subset of manuals says 45 * that's the thing to do, plus it's a bit less fiddly. I don't actually 46 * have access to a system with poll but not select, however, though 47 * both bits of the code have been tested on a machine with both. 48 */ 49#ifdef HAVE_POLL_H 50# include <poll.h> 51#endif 52#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM) 53# undef HAVE_POLL 54#endif 55 56static int 57bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func)) 58{ 59 int err=1, verbose=0, test=0, targetfd=0; 60 ZSOCKLEN_T len; 61 struct sockaddr_un soun; 62 int sfd; 63 64 if (OPT_ISSET(ops,'v')) 65 verbose = 1; 66 67 if (OPT_ISSET(ops,'t')) 68 test = 1; 69 70 if (OPT_ISSET(ops,'d')) { 71 targetfd = atoi(OPT_ARG(ops,'d')); 72 if (!targetfd) { 73 zwarnnam(nam, "%s is an invalid argument to -d", 74 OPT_ARG(ops, 'd')); 75 return 1; 76 } 77 if (targetfd <= max_zsh_fd && fdtable[targetfd] != FDT_UNUSED) { 78 zwarnnam(nam, "file descriptor %d is in use by the shell", 79 targetfd); 80 return 1; 81 } 82 } 83 84 if (OPT_ISSET(ops,'l')) { 85 char *localfn; 86 87 if (!args[0]) { 88 zwarnnam(nam, "-l requires an argument"); 89 return 1; 90 } 91 92 localfn = args[0]; 93 94 sfd = socket(PF_UNIX, SOCK_STREAM, 0); 95 96 if (sfd == -1) { 97 zwarnnam(nam, "socket error: %e ", errno); 98 return 1; 99 } 100 101 soun.sun_family = AF_UNIX; 102 strncpy(soun.sun_path, localfn, sizeof(soun.sun_path)-1); 103 104 if (bind(sfd, (struct sockaddr *)&soun, sizeof(struct sockaddr_un))) 105 { 106 zwarnnam(nam, "could not bind to %s: %e", soun.sun_path, errno); 107 close(sfd); 108 return 1; 109 } 110 111 if (listen(sfd, 1)) 112 { 113 zwarnnam(nam, "could not listen on socket: %e", errno); 114 close(sfd); 115 return 1; 116 } 117 118 if (targetfd) { 119 sfd = redup(sfd, targetfd); 120 } 121 else { 122 /* move the fd since no one will want to read from it */ 123 sfd = movefd(sfd); 124 } 125 if (sfd == -1) { 126 zerrnam(nam, "cannot duplicate fd %d: %e", sfd, errno); 127 return 1; 128 } 129 130 setiparam("REPLY", sfd); 131 132 if (verbose) 133 printf("%s listener is on fd %d\n", soun.sun_path, sfd); 134 135 return 0; 136 137 } 138 else if (OPT_ISSET(ops,'a')) 139 { 140 int lfd, rfd; 141 142 if (!args[0]) { 143 zwarnnam(nam, "-a requires an argument"); 144 return 1; 145 } 146 147 lfd = atoi(args[0]); 148 149 if (!lfd) { 150 zwarnnam(nam, "invalid numerical argument"); 151 return 1; 152 } 153 154 if (test) { 155#if defined(HAVE_POLL) || defined(HAVE_SELECT) 156# ifdef HAVE_POLL 157 struct pollfd pfd; 158 int ret; 159 160 pfd.fd = lfd; 161 pfd.events = POLLIN; 162 if ((ret = poll(&pfd, 1, 0)) == 0) return 1; 163 else if (ret == -1) 164 { 165 zwarnnam(nam, "poll error: %e", errno); 166 return 1; 167 } 168# else 169 fd_set rfds; 170 struct timeval tv; 171 int ret; 172 173 FD_ZERO(&rfds); 174 FD_SET(lfd, &rfds); 175 tv.tv_sec = 0; 176 tv.tv_usec = 0; 177 178 if ((ret = select(lfd+1, &rfds, NULL, NULL, &tv))) return 1; 179 else if (ret == -1) 180 { 181 zwarnnam(nam, "select error: %e", errno); 182 return 1; 183 } 184 185# endif 186 187#else 188 zwarnnam(nam, "not currently supported"); 189 return 1; 190#endif 191 } 192 193 len = sizeof(soun); 194 if ((rfd = accept(lfd, (struct sockaddr *)&soun, &len)) == -1) 195 { 196 zwarnnam(nam, "could not accept connection: %e", errno); 197 return 1; 198 } 199 200 if (targetfd) { 201 sfd = redup(rfd, targetfd); 202 if (sfd < 0) { 203 zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); 204 return 1; 205 } 206 } 207 else { 208 sfd = rfd; 209 } 210 211 setiparam("REPLY", sfd); 212 213 if (verbose) 214 printf("new connection from %s is on fd %d\n", soun.sun_path, sfd); 215 } 216 else 217 { 218 if (!args[0]) { 219 zwarnnam(nam, "zsocket requires an argument"); 220 return 1; 221 } 222 223 sfd = socket(PF_UNIX, SOCK_STREAM, 0); 224 225 if (sfd == -1) { 226 zwarnnam(nam, "socket creation failed: %e", errno); 227 return 1; 228 } 229 230 soun.sun_family = AF_UNIX; 231 strncpy(soun.sun_path, args[0], sizeof(soun.sun_path)-1); 232 233 if ((err = connect(sfd, (struct sockaddr *)&soun, sizeof(struct sockaddr_un)))) { 234 zwarnnam(nam, "connection failed: %e", errno); 235 close(sfd); 236 return 1; 237 } 238 else 239 { 240 if (targetfd) { 241 sfd = redup(sfd, targetfd); 242 if (sfd < 0) { 243 zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); 244 return 1; 245 } 246 } 247 248 setiparam("REPLY", sfd); 249 250 if (verbose) 251 printf("%s is now on fd %d\n", soun.sun_path, sfd); 252 } 253 254 } 255 256 return 0; 257} 258 259static struct builtin bintab[] = { 260 BUILTIN("zsocket", 0, bin_zsocket, 0, 3, 0, "ad:ltv", NULL), 261}; 262 263static struct features module_features = { 264 bintab, sizeof(bintab)/sizeof(*bintab), 265 NULL, 0, 266 NULL, 0, 267 NULL, 0, 268 0 269}; 270 271/* The load/unload routines required by the zsh library interface */ 272 273/**/ 274int 275setup_(UNUSED(Module m)) 276{ 277 return 0; 278} 279 280/**/ 281int 282features_(Module m, char ***features) 283{ 284 *features = featuresarray(m, &module_features); 285 return 0; 286} 287 288/**/ 289int 290enables_(Module m, int **enables) 291{ 292 return handlefeatures(m, &module_features, enables); 293} 294 295/**/ 296int 297boot_(Module m) 298{ 299 return 0; 300} 301 302/**/ 303int 304cleanup_(Module m) 305{ 306 return setfeatureenables(m, &module_features, NULL); 307} 308 309/**/ 310int 311finish_(UNUSED(Module m)) 312{ 313 return 0; 314} 315