1 /* $OpenBSD: client.c,v 1.22 2009/09/23 12:03:30 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 #include <sys/socket.h> 22 #include <sys/stat.h> 23 #include <sys/un.h> 24 #include <sys/wait.h> 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <pwd.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <unistd.h> 33 34 #include "tmux.h" 35 36 void client_send_environ(struct client_ctx *); 37 38 int 39 client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) 40 { 41 struct sockaddr_un sa; 42 struct stat sb; 43 struct msg_identify_data data; 44 struct winsize ws; 45 size_t size; 46 int fd, fd2, mode; 47 char *term; 48 char rpathbuf[MAXPATHLEN]; 49 50 if (realpath(path, rpathbuf) == NULL) 51 strlcpy(rpathbuf, path, sizeof rpathbuf); 52 setproctitle("client (%s)", rpathbuf); 53 54 if (lstat(path, &sb) != 0) { 55 if (cmdflags & CMD_STARTSERVER && errno == ENOENT) { 56 if ((fd = server_start(path)) == -1) 57 goto start_failed; 58 goto server_started; 59 } 60 goto not_found; 61 } 62 if (!S_ISSOCK(sb.st_mode)) { 63 errno = ENOTSOCK; 64 goto not_found; 65 } 66 67 memset(&sa, 0, sizeof sa); 68 sa.sun_family = AF_UNIX; 69 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); 70 if (size >= sizeof sa.sun_path) { 71 errno = ENAMETOOLONG; 72 goto not_found; 73 } 74 75 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 76 fatal("socket failed"); 77 78 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { 79 if (errno == ECONNREFUSED) { 80 if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER)) 81 goto not_found; 82 if ((fd = server_start(path)) == -1) 83 goto start_failed; 84 goto server_started; 85 } 86 goto not_found; 87 } 88 89 server_started: 90 if ((mode = fcntl(fd, F_GETFL)) == -1) 91 fatal("fcntl failed"); 92 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) 93 fatal("fcntl failed"); 94 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 95 fatal("fcntl failed"); 96 imsg_init(&cctx->ibuf, fd); 97 98 if (cmdflags & CMD_SENDENVIRON) 99 client_send_environ(cctx); 100 if (isatty(STDIN_FILENO)) { 101 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) 102 fatal("ioctl(TIOCGWINSZ)"); 103 data.flags = flags; 104 105 if (getcwd(data.cwd, sizeof data.cwd) == NULL) 106 *data.cwd = '\0'; 107 108 *data.term = '\0'; 109 if ((term = getenv("TERM")) != NULL) { 110 if (strlcpy(data.term, 111 term, sizeof data.term) >= sizeof data.term) 112 *data.term = '\0'; 113 } 114 115 if ((fd2 = dup(STDIN_FILENO)) == -1) 116 fatal("dup failed"); 117 imsg_compose(&cctx->ibuf, MSG_IDENTIFY, 118 PROTOCOL_VERSION, -1, fd2, &data, sizeof data); 119 } 120 121 return (0); 122 123 start_failed: 124 log_warnx("server failed to start"); 125 return (1); 126 127 not_found: 128 log_warn("server not found"); 129 return (1); 130 } 131 132 void 133 client_send_environ(struct client_ctx *cctx) 134 { 135 char **var; 136 struct msg_environ_data data; 137 138 for (var = environ; *var != NULL; var++) { 139 if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) 140 continue; 141 client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); 142 } 143 } 144 145 int 146 client_main(struct client_ctx *cctx) 147 { 148 struct pollfd pfd; 149 int n, nfds; 150 151 siginit(); 152 153 logfile("client"); 154 155 /* 156 * imsg_read in the first client poll loop (before the terminal has 157 * been initialiased) may have read messages into the buffer after the 158 * MSG_READY switched to here. Process anything outstanding now so poll 159 * doesn't hang waiting for messages that have already arrived. 160 */ 161 if (client_msg_dispatch(cctx) != 0) 162 goto out; 163 164 for (;;) { 165 if (sigterm) 166 client_write_server(cctx, MSG_EXITING, NULL, 0); 167 if (sigchld) { 168 waitpid(WAIT_ANY, NULL, WNOHANG); 169 sigchld = 0; 170 } 171 if (sigwinch) { 172 client_write_server(cctx, MSG_RESIZE, NULL, 0); 173 sigwinch = 0; 174 } 175 if (sigcont) { 176 siginit(); 177 client_write_server(cctx, MSG_WAKEUP, NULL, 0); 178 sigcont = 0; 179 } 180 181 pfd.fd = cctx->ibuf.fd; 182 pfd.events = POLLIN; 183 if (cctx->ibuf.w.queued > 0) 184 pfd.events |= POLLOUT; 185 186 if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { 187 if (errno == EAGAIN || errno == EINTR) 188 continue; 189 fatal("poll failed"); 190 } 191 if (nfds == 0) 192 continue; 193 194 if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL)) 195 fatalx("socket error"); 196 197 if (pfd.revents & POLLIN) { 198 if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { 199 cctx->exittype = CCTX_DIED; 200 break; 201 } 202 if (client_msg_dispatch(cctx) != 0) 203 break; 204 } 205 206 if (pfd.revents & POLLOUT) { 207 if (msgbuf_write(&cctx->ibuf.w) < 0) { 208 cctx->exittype = CCTX_DIED; 209 break; 210 } 211 } 212 } 213 214 out: 215 if (sigterm) { 216 printf("[terminated]\n"); 217 return (1); 218 } 219 switch (cctx->exittype) { 220 case CCTX_DIED: 221 printf("[lost server]\n"); 222 return (0); 223 case CCTX_SHUTDOWN: 224 printf("[server exited]\n"); 225 return (0); 226 case CCTX_EXIT: 227 if (cctx->errstr != NULL) { 228 printf("[error: %s]\n", cctx->errstr); 229 return (1); 230 } 231 printf("[exited]\n"); 232 return (0); 233 case CCTX_DETACH: 234 printf("[detached]\n"); 235 return (0); 236 default: 237 printf("[unknown error]\n"); 238 return (1); 239 } 240 } 241 242 int 243 client_msg_dispatch(struct client_ctx *cctx) 244 { 245 struct imsg imsg; 246 struct msg_print_data printdata; 247 struct msg_lock_data lockdata; 248 ssize_t n, datalen; 249 250 for (;;) { 251 if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) 252 fatalx("imsg_get failed"); 253 if (n == 0) 254 return (0); 255 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 256 257 switch (imsg.hdr.type) { 258 case MSG_DETACH: 259 if (datalen != 0) 260 fatalx("bad MSG_DETACH size"); 261 262 client_write_server(cctx, MSG_EXITING, NULL, 0); 263 cctx->exittype = CCTX_DETACH; 264 break; 265 case MSG_ERROR: 266 if (datalen != sizeof printdata) 267 fatalx("bad MSG_ERROR size"); 268 memcpy(&printdata, imsg.data, sizeof printdata); 269 270 printdata.msg[(sizeof printdata.msg) - 1] = '\0'; 271 /* Error string used after exit message from server. */ 272 cctx->errstr = xstrdup(printdata.msg); 273 imsg_free(&imsg); 274 return (-1); 275 case MSG_EXIT: 276 if (datalen != 0) 277 fatalx("bad MSG_EXIT size"); 278 279 client_write_server(cctx, MSG_EXITING, NULL, 0); 280 cctx->exittype = CCTX_EXIT; 281 break; 282 case MSG_EXITED: 283 if (datalen != 0) 284 fatalx("bad MSG_EXITED size"); 285 286 imsg_free(&imsg); 287 return (-1); 288 case MSG_SHUTDOWN: 289 if (datalen != 0) 290 fatalx("bad MSG_SHUTDOWN size"); 291 292 client_write_server(cctx, MSG_EXITING, NULL, 0); 293 cctx->exittype = CCTX_SHUTDOWN; 294 break; 295 case MSG_SUSPEND: 296 if (datalen != 0) 297 fatalx("bad MSG_SUSPEND size"); 298 299 client_suspend(); 300 break; 301 case MSG_LOCK: 302 if (datalen != sizeof lockdata) 303 fatalx("bad MSG_LOCK size"); 304 memcpy(&lockdata, imsg.data, sizeof lockdata); 305 306 lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; 307 system(lockdata.cmd); 308 client_write_server(cctx, MSG_UNLOCK, NULL, 0); 309 break; 310 default: 311 fatalx("unexpected message"); 312 } 313 314 imsg_free(&imsg); 315 } 316 } 317