1 /* $Id: client.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv 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/socket.h> 21 #include <sys/stat.h> 22 #include <sys/un.h> 23 #include <sys/wait.h> 24 25 #include <errno.h> 26 #include <event.h> 27 #include <fcntl.h> 28 #include <pwd.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "tmux.h" 34 35 struct imsgbuf client_ibuf; 36 struct event client_event; 37 const char *client_exitmsg; 38 int client_exitval; 39 enum msgtype client_exittype; 40 int client_attached; 41 42 int client_connect(char *, int); 43 void client_send_identify(int); 44 void client_send_environ(void); 45 void client_write_server(enum msgtype, void *, size_t); 46 void client_update_event(void); 47 void client_signal(int, short, void *); 48 void client_callback(int, short, void *); 49 int client_dispatch_attached(void); 50 int client_dispatch_wait(void *); 51 52 /* Connect client to server. */ 53 int 54 client_connect(char *path, int start_server) 55 { 56 struct sockaddr_un sa; 57 size_t size; 58 int fd; 59 60 memset(&sa, 0, sizeof sa); 61 sa.sun_family = AF_UNIX; 62 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); 63 if (size >= sizeof sa.sun_path) { 64 errno = ENAMETOOLONG; 65 return (-1); 66 } 67 68 #ifndef __minix 69 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 70 #else 71 if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) 72 #endif 73 fatal("socket failed"); 74 75 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { 76 if (!start_server) 77 goto failed; 78 switch (errno) { 79 case ECONNREFUSED: 80 if (unlink(path) != 0) 81 goto failed; 82 /* FALLTHROUGH */ 83 case ENOENT: 84 if ((fd = server_start()) == -1) 85 goto failed; 86 break; 87 default: 88 goto failed; 89 } 90 } 91 92 setblocking(fd, 0); 93 return (fd); 94 95 failed: 96 close(fd); 97 return (-1); 98 } 99 100 /* Client main loop. */ 101 int 102 client_main(int argc, char **argv, int flags) 103 { 104 struct cmd *cmd; 105 struct cmd_list *cmdlist; 106 struct msg_command_data cmddata; 107 int cmdflags, fd; 108 pid_t ppid; 109 enum msgtype msg; 110 char *cause; 111 112 /* Set up the initial command. */ 113 cmdflags = 0; 114 if (shell_cmd != NULL) { 115 msg = MSG_SHELL; 116 cmdflags = CMD_STARTSERVER; 117 } else if (argc == 0) { 118 msg = MSG_COMMAND; 119 cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; 120 } else { 121 msg = MSG_COMMAND; 122 123 /* 124 * It sucks parsing the command string twice (in client and 125 * later in server) but it is necessary to get the start server 126 * flag. 127 */ 128 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { 129 log_warnx("%s", cause); 130 return (1); 131 } 132 cmdflags &= ~CMD_STARTSERVER; 133 TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { 134 if (cmd->entry->flags & CMD_STARTSERVER) 135 cmdflags |= CMD_STARTSERVER; 136 if (cmd->entry->flags & CMD_SENDENVIRON) 137 cmdflags |= CMD_SENDENVIRON; 138 if (cmd->entry->flags & CMD_CANTNEST) 139 cmdflags |= CMD_CANTNEST; 140 } 141 cmd_list_free(cmdlist); 142 } 143 144 /* 145 * Check if this could be a nested session, if the command can't nest: 146 * if the socket path matches $TMUX, this is probably the same server. 147 */ 148 if (shell_cmd == NULL && environ_path != NULL && 149 cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) { 150 log_warnx("sessions should be nested with care. " 151 "unset $TMUX to force."); 152 return (1); 153 } 154 155 /* Initialise the client socket and start the server. */ 156 fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); 157 if (fd == -1) { 158 log_warn("failed to connect to server"); 159 return (1); 160 } 161 162 /* Set process title, log and signals now this is the client. */ 163 #ifdef HAVE_SETPROCTITLE 164 setproctitle("client (%s)", socket_path); 165 #endif 166 logfile("client"); 167 168 /* Create imsg. */ 169 imsg_init(&client_ibuf, fd); 170 event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); 171 172 /* Establish signal handlers. */ 173 set_signals(client_signal); 174 175 /* Send initial environment. */ 176 if (cmdflags & CMD_SENDENVIRON) 177 client_send_environ(); 178 client_send_identify(flags); 179 180 /* Send first command. */ 181 if (msg == MSG_COMMAND) { 182 /* Fill in command line arguments. */ 183 cmddata.pid = environ_pid; 184 cmddata.idx = environ_idx; 185 186 /* Prepare command for server. */ 187 cmddata.argc = argc; 188 if (cmd_pack_argv( 189 argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { 190 log_warnx("command too long"); 191 return (1); 192 } 193 194 client_write_server(msg, &cmddata, sizeof cmddata); 195 } else if (msg == MSG_SHELL) 196 client_write_server(msg, NULL, 0); 197 198 /* Set the event and dispatch. */ 199 client_update_event(); 200 event_dispatch(); 201 202 /* Print the exit message, if any, and exit. */ 203 if (client_attached) { 204 if (client_exitmsg != NULL && !login_shell) 205 printf("[%s]\n", client_exitmsg); 206 207 ppid = getppid(); 208 if (client_exittype == MSG_DETACHKILL && ppid > 1) 209 kill(ppid, SIGHUP); 210 } 211 return (client_exitval); 212 } 213 214 /* Send identify message to server with the file descriptors. */ 215 void 216 client_send_identify(int flags) 217 { 218 struct msg_identify_data data; 219 char *term; 220 int fd; 221 222 data.flags = flags; 223 224 if (getcwd(data.cwd, sizeof data.cwd) == NULL) 225 *data.cwd = '\0'; 226 227 term = getenv("TERM"); 228 if (term == NULL || 229 strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) 230 *data.term = '\0'; 231 232 if ((fd = dup(STDIN_FILENO)) == -1) 233 fatal("dup failed"); 234 imsg_compose(&client_ibuf, 235 MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); 236 237 if ((fd = dup(STDOUT_FILENO)) == -1) 238 fatal("dup failed"); 239 imsg_compose(&client_ibuf, 240 MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0); 241 242 if ((fd = dup(STDERR_FILENO)) == -1) 243 fatal("dup failed"); 244 imsg_compose(&client_ibuf, 245 MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0); 246 } 247 248 /* Forward entire environment to server. */ 249 void 250 client_send_environ(void) 251 { 252 struct msg_environ_data data; 253 char **var; 254 255 for (var = environ; *var != NULL; var++) { 256 if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) 257 continue; 258 client_write_server(MSG_ENVIRON, &data, sizeof data); 259 } 260 } 261 262 /* Write a message to the server without a file descriptor. */ 263 void 264 client_write_server(enum msgtype type, void *buf, size_t len) 265 { 266 imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); 267 } 268 269 /* Update client event based on whether it needs to read or read and write. */ 270 void 271 client_update_event(void) 272 { 273 short events; 274 275 event_del(&client_event); 276 events = EV_READ; 277 if (client_ibuf.w.queued > 0) 278 events |= EV_WRITE; 279 event_set( 280 &client_event, client_ibuf.fd, events, client_callback, shell_cmd); 281 event_add(&client_event, NULL); 282 } 283 284 /* Callback to handle signals in the client. */ 285 /* ARGSUSED */ 286 void 287 client_signal(int sig, unused short events, unused void *data) 288 { 289 struct sigaction sigact; 290 int status; 291 292 if (!client_attached) { 293 switch (sig) { 294 case SIGCHLD: 295 waitpid(WAIT_ANY, &status, WNOHANG); 296 break; 297 case SIGTERM: 298 event_loopexit(NULL); 299 break; 300 } 301 } else { 302 switch (sig) { 303 case SIGHUP: 304 client_exitmsg = "lost tty"; 305 client_exitval = 1; 306 client_write_server(MSG_EXITING, NULL, 0); 307 break; 308 case SIGTERM: 309 client_exitmsg = "terminated"; 310 client_exitval = 1; 311 client_write_server(MSG_EXITING, NULL, 0); 312 break; 313 case SIGWINCH: 314 client_write_server(MSG_RESIZE, NULL, 0); 315 break; 316 case SIGCONT: 317 memset(&sigact, 0, sizeof sigact); 318 sigemptyset(&sigact.sa_mask); 319 sigact.sa_flags = SA_RESTART; 320 sigact.sa_handler = SIG_IGN; 321 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 322 fatal("sigaction failed"); 323 client_write_server(MSG_WAKEUP, NULL, 0); 324 break; 325 } 326 } 327 328 client_update_event(); 329 } 330 331 /* Callback for client imsg read events. */ 332 /* ARGSUSED */ 333 void 334 client_callback(unused int fd, short events, void *data) 335 { 336 ssize_t n; 337 int retval; 338 339 if (events & EV_READ) { 340 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) 341 goto lost_server; 342 if (client_attached) 343 retval = client_dispatch_attached(); 344 else 345 retval = client_dispatch_wait(data); 346 if (retval != 0) { 347 event_loopexit(NULL); 348 return; 349 } 350 } 351 352 if (events & EV_WRITE) { 353 if (msgbuf_write(&client_ibuf.w) < 0) 354 goto lost_server; 355 } 356 357 client_update_event(); 358 return; 359 360 lost_server: 361 client_exitmsg = "lost server"; 362 client_exitval = 1; 363 event_loopexit(NULL); 364 } 365 366 /* Dispatch imsgs when in wait state (before MSG_READY). */ 367 int 368 client_dispatch_wait(void *data) 369 { 370 struct imsg imsg; 371 ssize_t n, datalen; 372 struct msg_shell_data shelldata; 373 struct msg_exit_data exitdata; 374 const char *shellcmd = data; 375 376 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) 377 fatalx("imsg_read failed"); 378 379 for (;;) { 380 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 381 fatalx("imsg_get failed"); 382 if (n == 0) 383 return (0); 384 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 385 386 switch (imsg.hdr.type) { 387 case MSG_EXIT: 388 case MSG_SHUTDOWN: 389 if (datalen != sizeof exitdata) { 390 if (datalen != 0) 391 fatalx("bad MSG_EXIT size"); 392 } else { 393 memcpy(&exitdata, imsg.data, sizeof exitdata); 394 client_exitval = exitdata.retcode; 395 } 396 imsg_free(&imsg); 397 return (-1); 398 case MSG_READY: 399 if (datalen != 0) 400 fatalx("bad MSG_READY size"); 401 402 client_attached = 1; 403 break; 404 case MSG_VERSION: 405 if (datalen != 0) 406 fatalx("bad MSG_VERSION size"); 407 408 log_warnx("protocol version mismatch (client %u, " 409 "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); 410 client_exitval = 1; 411 412 imsg_free(&imsg); 413 return (-1); 414 case MSG_SHELL: 415 if (datalen != sizeof shelldata) 416 fatalx("bad MSG_SHELL size"); 417 memcpy(&shelldata, imsg.data, sizeof shelldata); 418 shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; 419 420 clear_signals(0); 421 422 shell_exec(shelldata.shell, shellcmd); 423 /* NOTREACHED */ 424 default: 425 fatalx("unexpected message"); 426 } 427 428 imsg_free(&imsg); 429 } 430 } 431 432 /* Dispatch imsgs in attached state (after MSG_READY). */ 433 /* ARGSUSED */ 434 int 435 client_dispatch_attached(void) 436 { 437 struct imsg imsg; 438 struct msg_lock_data lockdata; 439 struct sigaction sigact; 440 ssize_t n, datalen; 441 442 for (;;) { 443 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 444 fatalx("imsg_get failed"); 445 if (n == 0) 446 return (0); 447 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 448 449 log_debug("client got %d", imsg.hdr.type); 450 switch (imsg.hdr.type) { 451 case MSG_DETACHKILL: 452 case MSG_DETACH: 453 if (datalen != 0) 454 fatalx("bad MSG_DETACH size"); 455 456 client_exittype = imsg.hdr.type; 457 if (imsg.hdr.type == MSG_DETACHKILL) 458 client_exitmsg = "detached and SIGHUP"; 459 else 460 client_exitmsg = "detached"; 461 client_write_server(MSG_EXITING, NULL, 0); 462 break; 463 case MSG_EXIT: 464 if (datalen != 0 && 465 datalen != sizeof (struct msg_exit_data)) 466 fatalx("bad MSG_EXIT size"); 467 468 client_write_server(MSG_EXITING, NULL, 0); 469 client_exitmsg = "exited"; 470 break; 471 case MSG_EXITED: 472 if (datalen != 0) 473 fatalx("bad MSG_EXITED size"); 474 475 imsg_free(&imsg); 476 return (-1); 477 case MSG_SHUTDOWN: 478 if (datalen != 0) 479 fatalx("bad MSG_SHUTDOWN size"); 480 481 client_write_server(MSG_EXITING, NULL, 0); 482 client_exitmsg = "server exited"; 483 client_exitval = 1; 484 break; 485 case MSG_SUSPEND: 486 if (datalen != 0) 487 fatalx("bad MSG_SUSPEND size"); 488 489 memset(&sigact, 0, sizeof sigact); 490 sigemptyset(&sigact.sa_mask); 491 sigact.sa_flags = SA_RESTART; 492 sigact.sa_handler = SIG_DFL; 493 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 494 fatal("sigaction failed"); 495 kill(getpid(), SIGTSTP); 496 break; 497 case MSG_LOCK: 498 if (datalen != sizeof lockdata) 499 fatalx("bad MSG_LOCK size"); 500 memcpy(&lockdata, imsg.data, sizeof lockdata); 501 502 lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; 503 system(lockdata.cmd); 504 client_write_server(MSG_UNLOCK, NULL, 0); 505 break; 506 default: 507 fatalx("unexpected message"); 508 } 509 510 imsg_free(&imsg); 511 } 512 } 513