1 /* $OpenBSD: client.c,v 1.35 2009/12/03 22:50:09 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 <event.h> 28 #include <fcntl.h> 29 #include <pwd.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <unistd.h> 34 35 #include "tmux.h" 36 37 struct imsgbuf client_ibuf; 38 struct event client_event; 39 const char *client_exitmsg; 40 int client_exitval; 41 42 void client_send_identify(int); 43 void client_send_environ(void); 44 void client_write_server(enum msgtype, void *, size_t); 45 void client_update_event(void); 46 void client_signal(int, short, void *); 47 void client_callback(int, short, void *); 48 int client_dispatch(void); 49 50 struct imsgbuf * 51 client_init(char *path, int cmdflags, int flags) 52 { 53 struct sockaddr_un sa; 54 size_t size; 55 int fd, mode; 56 char rpathbuf[MAXPATHLEN]; 57 58 if (realpath(path, rpathbuf) == NULL) 59 strlcpy(rpathbuf, path, sizeof rpathbuf); 60 setproctitle("client (%s)", rpathbuf); 61 62 memset(&sa, 0, sizeof sa); 63 sa.sun_family = AF_UNIX; 64 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); 65 if (size >= sizeof sa.sun_path) { 66 errno = ENAMETOOLONG; 67 goto not_found; 68 } 69 70 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 71 fatal("socket failed"); 72 73 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { 74 if (!(cmdflags & CMD_STARTSERVER)) 75 goto not_found; 76 switch (errno) { 77 case ECONNREFUSED: 78 if (unlink(path) != 0) 79 goto not_found; 80 /* FALLTHROUGH */ 81 case ENOENT: 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(&client_ibuf, fd); 97 98 if (cmdflags & CMD_SENDENVIRON) 99 client_send_environ(); 100 if (isatty(STDIN_FILENO)) 101 client_send_identify(flags); 102 103 return (&client_ibuf); 104 105 start_failed: 106 log_warnx("server failed to start"); 107 return (NULL); 108 109 not_found: 110 log_warn("server not found"); 111 return (NULL); 112 } 113 114 void 115 client_send_identify(int flags) 116 { 117 struct msg_identify_data data; 118 struct winsize ws; 119 char *term; 120 int fd; 121 122 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) 123 fatal("ioctl(TIOCGWINSZ)"); 124 data.flags = flags; 125 126 if (getcwd(data.cwd, sizeof data.cwd) == NULL) 127 *data.cwd = '\0'; 128 129 term = getenv("TERM"); 130 if (term == NULL || 131 strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) 132 *data.term = '\0'; 133 134 if ((fd = dup(STDIN_FILENO)) == -1) 135 fatal("dup failed"); 136 imsg_compose(&client_ibuf, 137 MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); 138 } 139 140 void 141 client_send_environ(void) 142 { 143 struct msg_environ_data data; 144 char **var; 145 146 for (var = environ; *var != NULL; var++) { 147 if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) 148 continue; 149 client_write_server(MSG_ENVIRON, &data, sizeof data); 150 } 151 } 152 153 void 154 client_write_server(enum msgtype type, void *buf, size_t len) 155 { 156 imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); 157 } 158 159 void 160 client_update_event(void) 161 { 162 short events; 163 164 event_del(&client_event); 165 events = EV_READ; 166 if (client_ibuf.w.queued > 0) 167 events |= EV_WRITE; 168 event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); 169 event_add(&client_event, NULL); 170 } 171 172 __dead void 173 client_main(void) 174 { 175 struct event ev_sigcont, ev_sigterm, ev_sigwinch; 176 struct sigaction sigact; 177 178 logfile("client"); 179 180 /* Note: event_init() has already been called. */ 181 182 /* Set up signals. */ 183 memset(&sigact, 0, sizeof sigact); 184 sigemptyset(&sigact.sa_mask); 185 sigact.sa_flags = SA_RESTART; 186 sigact.sa_handler = SIG_IGN; 187 if (sigaction(SIGINT, &sigact, NULL) != 0) 188 fatal("sigaction failed"); 189 if (sigaction(SIGPIPE, &sigact, NULL) != 0) 190 fatal("sigaction failed"); 191 if (sigaction(SIGUSR1, &sigact, NULL) != 0) 192 fatal("sigaction failed"); 193 if (sigaction(SIGUSR2, &sigact, NULL) != 0) 194 fatal("sigaction failed"); 195 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 196 fatal("sigaction failed"); 197 198 signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); 199 signal_add(&ev_sigcont, NULL); 200 signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); 201 signal_add(&ev_sigterm, NULL); 202 signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); 203 signal_add(&ev_sigwinch, NULL); 204 205 /* 206 * imsg_read in the first client poll loop (before the terminal has 207 * been initialised) may have read messages into the buffer after the 208 * MSG_READY switched to here. Process anything outstanding now to 209 * avoid hanging waiting for messages that have already arrived. 210 */ 211 if (client_dispatch() != 0) 212 goto out; 213 214 /* Set the event and dispatch. */ 215 client_update_event(); 216 event_dispatch(); 217 218 out: 219 /* Print the exit message, if any, and exit. */ 220 if (client_exitmsg != NULL && !login_shell) 221 printf("[%s]\n", client_exitmsg); 222 exit(client_exitval); 223 } 224 225 /* ARGSUSED */ 226 void 227 client_signal(int sig, unused short events, unused void *data) 228 { 229 struct sigaction sigact; 230 231 switch (sig) { 232 case SIGTERM: 233 client_exitmsg = "terminated"; 234 client_exitval = 1; 235 client_write_server(MSG_EXITING, NULL, 0); 236 break; 237 case SIGWINCH: 238 client_write_server(MSG_RESIZE, NULL, 0); 239 break; 240 case SIGCONT: 241 memset(&sigact, 0, sizeof sigact); 242 sigemptyset(&sigact.sa_mask); 243 sigact.sa_flags = SA_RESTART; 244 sigact.sa_handler = SIG_IGN; 245 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 246 fatal("sigaction failed"); 247 client_write_server(MSG_WAKEUP, NULL, 0); 248 break; 249 } 250 251 client_update_event(); 252 } 253 254 /* ARGSUSED */ 255 void 256 client_callback(unused int fd, short events, unused void *data) 257 { 258 ssize_t n; 259 260 if (events & EV_READ) { 261 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) 262 goto lost_server; 263 if (client_dispatch() != 0) { 264 event_loopexit(NULL); 265 return; 266 } 267 } 268 269 if (events & EV_WRITE) { 270 if (msgbuf_write(&client_ibuf.w) < 0) 271 goto lost_server; 272 } 273 274 client_update_event(); 275 return; 276 277 lost_server: 278 client_exitmsg = "lost server"; 279 client_exitval = 1; 280 event_loopexit(NULL); 281 } 282 283 int 284 client_dispatch(void) 285 { 286 struct imsg imsg; 287 struct msg_lock_data lockdata; 288 struct sigaction sigact; 289 ssize_t n, datalen; 290 291 for (;;) { 292 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 293 fatalx("imsg_get failed"); 294 if (n == 0) 295 return (0); 296 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 297 298 log_debug("client got %d", imsg.hdr.type); 299 switch (imsg.hdr.type) { 300 case MSG_DETACH: 301 if (datalen != 0) 302 fatalx("bad MSG_DETACH size"); 303 304 client_write_server(MSG_EXITING, NULL, 0); 305 client_exitmsg = "detached"; 306 break; 307 case MSG_EXIT: 308 if (datalen != 0) 309 fatalx("bad MSG_EXIT size"); 310 311 client_write_server(MSG_EXITING, NULL, 0); 312 client_exitmsg = "exited"; 313 break; 314 case MSG_EXITED: 315 if (datalen != 0) 316 fatalx("bad MSG_EXITED size"); 317 318 imsg_free(&imsg); 319 return (-1); 320 case MSG_SHUTDOWN: 321 if (datalen != 0) 322 fatalx("bad MSG_SHUTDOWN size"); 323 324 client_write_server(MSG_EXITING, NULL, 0); 325 client_exitmsg = "server exited"; 326 client_exitval = 1; 327 break; 328 case MSG_SUSPEND: 329 if (datalen != 0) 330 fatalx("bad MSG_SUSPEND size"); 331 332 memset(&sigact, 0, sizeof sigact); 333 sigemptyset(&sigact.sa_mask); 334 sigact.sa_flags = SA_RESTART; 335 sigact.sa_handler = SIG_DFL; 336 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 337 fatal("sigaction failed"); 338 kill(getpid(), SIGTSTP); 339 break; 340 case MSG_LOCK: 341 if (datalen != sizeof lockdata) 342 fatalx("bad MSG_LOCK size"); 343 memcpy(&lockdata, imsg.data, sizeof lockdata); 344 345 lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; 346 system(lockdata.cmd); 347 client_write_server(MSG_UNLOCK, NULL, 0); 348 break; 349 default: 350 fatalx("unexpected message"); 351 } 352 353 imsg_free(&imsg); 354 } 355 } 356