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