Annotation of src/usr.bin/tmux/client.c, Revision 1.93
1.93 ! nicm 1: /* $OpenBSD: client.c,v 1.92 2015/08/30 22:19:07 nicm Exp $ */
1.1 nicm 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>
1.51 nicm 20: #include <sys/file.h>
1.1 nicm 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>
1.30 nicm 27: #include <event.h>
1.80 nicm 28: #include <fcntl.h>
1.85 nicm 29: #include <signal.h>
1.1 nicm 30: #include <stdlib.h>
31: #include <string.h>
32: #include <unistd.h>
33:
34: #include "tmux.h"
35:
1.93 ! nicm 36: int client_flags;
1.25 nicm 37: struct imsgbuf client_ibuf;
1.30 nicm 38: struct event client_event;
1.54 nicm 39: struct event client_stdin;
1.52 nicm 40: enum {
41: CLIENT_EXIT_NONE,
42: CLIENT_EXIT_DETACHED,
43: CLIENT_EXIT_DETACHED_HUP,
44: CLIENT_EXIT_LOST_TTY,
45: CLIENT_EXIT_TERMINATED,
46: CLIENT_EXIT_LOST_SERVER,
47: CLIENT_EXIT_EXITED,
48: CLIENT_EXIT_SERVER_EXITED,
49: } client_exitreason = CLIENT_EXIT_NONE;
1.32 nicm 50: int client_exitval;
1.48 nicm 51: enum msgtype client_exittype;
1.73 nicm 52: const char *client_exitsession;
1.46 nicm 53: int client_attached;
1.1 nicm 54:
1.93 ! nicm 55: __dead void client_exec(const char *);
1.49 nicm 56: int client_get_lock(char *);
1.92 nicm 57: int client_connect(struct event_base *, char *, int);
1.93 ! nicm 58: void client_send_identify(void);
1.70 nicm 59: int client_write_one(enum msgtype, int, const void *, size_t);
60: int client_write_server(enum msgtype, const void *, size_t);
1.31 nicm 61: void client_update_event(void);
1.30 nicm 62: void client_signal(int, short, void *);
1.54 nicm 63: void client_stdin_callback(int, short, void *);
1.57 nicm 64: void client_write(int, const char *, size_t);
1.30 nicm 65: void client_callback(int, short, void *);
1.46 nicm 66: int client_dispatch_attached(void);
1.93 ! nicm 67: int client_dispatch_wait(void);
1.53 nicm 68: const char *client_exit_message(void);
1.25 nicm 69:
1.49 nicm 70: /*
71: * Get server create lock. If already held then server start is happening in
72: * another client, so block until the lock is released and return -1 to
73: * retry. Ignore other errors - just continue and start the server without the
74: * lock.
75: */
76: int
77: client_get_lock(char *lockfile)
78: {
79: int lockfd;
80:
81: if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
82: fatal("open failed");
1.82 nicm 83: log_debug("lock file is %s", lockfile);
1.49 nicm 84:
1.82 nicm 85: if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
86: log_debug("flock failed: %s", strerror(errno));
87: if (errno != EAGAIN)
88: return (lockfd);
89: while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
1.49 nicm 90: /* nothing */;
91: close(lockfd);
92: return (-1);
93: }
1.82 nicm 94: log_debug("flock succeeded");
1.49 nicm 95:
96: return (lockfd);
97: }
98:
1.46 nicm 99: /* Connect client to server. */
100: int
1.92 nicm 101: client_connect(struct event_base *base, char *path, int start_server)
1.1 nicm 102: {
1.26 nicm 103: struct sockaddr_un sa;
104: size_t size;
1.82 nicm 105: int fd, lockfd = -1, locked = 0;
106: char *lockfile = NULL;
1.1 nicm 107:
108: memset(&sa, 0, sizeof sa);
109: sa.sun_family = AF_UNIX;
110: size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
111: if (size >= sizeof sa.sun_path) {
112: errno = ENAMETOOLONG;
1.46 nicm 113: return (-1);
1.1 nicm 114: }
1.82 nicm 115: log_debug("socket is %s", path);
1.1 nicm 116:
1.49 nicm 117: retry:
1.10 nicm 118: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
1.18 nicm 119: fatal("socket failed");
1.1 nicm 120:
1.82 nicm 121: log_debug("trying connect");
1.10 nicm 122: if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
1.82 nicm 123: log_debug("connect failed: %s", strerror(errno));
1.49 nicm 124: if (errno != ECONNREFUSED && errno != ENOENT)
125: goto failed;
1.46 nicm 126: if (!start_server)
127: goto failed;
1.49 nicm 128: close(fd);
129:
1.82 nicm 130: if (!locked) {
131: xasprintf(&lockfile, "%s.lock", path);
132: if ((lockfd = client_get_lock(lockfile)) == -1) {
133: log_debug("didn't get lock");
134: free(lockfile);
135: goto retry;
136: }
137: log_debug("got lock");
138:
139: /*
140: * Always retry at least once, even if we got the lock,
141: * because another client could have taken the lock,
142: * started the server and released the lock between our
143: * connect() and flock().
144: */
145: locked = 1;
1.49 nicm 146: goto retry;
1.78 nicm 147: }
1.82 nicm 148:
1.78 nicm 149: if (unlink(path) != 0 && errno != ENOENT) {
150: free(lockfile);
151: close(lockfd);
1.49 nicm 152: return (-1);
1.78 nicm 153: }
1.92 nicm 154: fd = server_start(base, lockfd, lockfile);
1.82 nicm 155: }
156: if (locked) {
1.58 nicm 157: free(lockfile);
1.49 nicm 158: close(lockfd);
1.1 nicm 159: }
160:
1.47 nicm 161: setblocking(fd, 0);
1.46 nicm 162: return (fd);
163:
164: failed:
165: close(fd);
166: return (-1);
167: }
168:
1.52 nicm 169: /* Get exit string from reason number. */
170: const char *
171: client_exit_message(void)
172: {
1.73 nicm 173: static char msg[256];
174:
1.52 nicm 175: switch (client_exitreason) {
176: case CLIENT_EXIT_NONE:
177: break;
178: case CLIENT_EXIT_DETACHED:
1.73 nicm 179: if (client_exitsession != NULL) {
180: xsnprintf(msg, sizeof msg, "detached "
181: "(from session %s)", client_exitsession);
182: return (msg);
183: }
1.52 nicm 184: return ("detached");
185: case CLIENT_EXIT_DETACHED_HUP:
1.73 nicm 186: if (client_exitsession != NULL) {
187: xsnprintf(msg, sizeof msg, "detached and SIGHUP "
188: "(from session %s)", client_exitsession);
189: return (msg);
190: }
1.52 nicm 191: return ("detached and SIGHUP");
192: case CLIENT_EXIT_LOST_TTY:
193: return ("lost tty");
194: case CLIENT_EXIT_TERMINATED:
195: return ("terminated");
196: case CLIENT_EXIT_LOST_SERVER:
197: return ("lost server");
198: case CLIENT_EXIT_EXITED:
199: return ("exited");
200: case CLIENT_EXIT_SERVER_EXITED:
201: return ("server exited");
202: }
203: return ("unknown reason");
204: }
205:
1.46 nicm 206: /* Client main loop. */
207: int
1.92 nicm 208: client_main(struct event_base *base, int argc, char **argv, int flags)
1.46 nicm 209: {
210: struct cmd *cmd;
211: struct cmd_list *cmdlist;
1.70 nicm 212: struct msg_command_data *data;
213: int cmdflags, fd, i;
1.48 nicm 214: pid_t ppid;
1.46 nicm 215: enum msgtype msg;
216: char *cause;
1.56 nicm 217: struct termios tio, saved_tio;
1.70 nicm 218: size_t size;
1.46 nicm 219:
1.93 ! nicm 220: /* Save the flags. */
! 221: client_flags = flags;
! 222:
1.46 nicm 223: /* Set up the initial command. */
224: cmdflags = 0;
225: if (shell_cmd != NULL) {
226: msg = MSG_SHELL;
227: cmdflags = CMD_STARTSERVER;
228: } else if (argc == 0) {
229: msg = MSG_COMMAND;
1.89 nicm 230: cmdflags = CMD_STARTSERVER;
1.46 nicm 231: } else {
232: msg = MSG_COMMAND;
233:
234: /*
235: * It sucks parsing the command string twice (in client and
236: * later in server) but it is necessary to get the start server
237: * flag.
238: */
1.62 nicm 239: cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
240: if (cmdlist == NULL) {
1.59 nicm 241: fprintf(stderr, "%s\n", cause);
1.46 nicm 242: return (1);
243: }
244: cmdflags &= ~CMD_STARTSERVER;
245: TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
246: if (cmd->entry->flags & CMD_STARTSERVER)
247: cmdflags |= CMD_STARTSERVER;
248: }
249: cmd_list_free(cmdlist);
250: }
251:
1.82 nicm 252: /* Set process title, log and signals now this is the client. */
253: setproctitle("client (%s)", socket_path);
254: logfile("client");
255:
1.88 nicm 256: /* Establish signal handlers. */
257: set_signals(client_signal);
258:
1.82 nicm 259: /* Initialize the client socket and start the server. */
1.92 nicm 260: fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
1.46 nicm 261: if (fd == -1) {
1.87 nicm 262: if (errno == ECONNREFUSED) {
263: fprintf(stderr, "no server running on %s\n",
264: socket_path);
265: } else {
266: fprintf(stderr, "error connecting to %s (%s)\n",
267: socket_path, strerror(errno));
268: }
1.46 nicm 269: return (1);
270: }
271:
272: /* Create imsg. */
1.25 nicm 273: imsg_init(&client_ibuf, fd);
1.93 ! nicm 274: event_set(&client_event, fd, EV_READ, client_callback, NULL);
1.46 nicm 275:
1.54 nicm 276: /* Create stdin handler. */
277: setblocking(STDIN_FILENO, 0);
278: event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
279: client_stdin_callback, NULL);
1.93 ! nicm 280: if (client_flags & CLIENT_CONTROLCONTROL) {
1.56 nicm 281: if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
282: fprintf(stderr, "tcgetattr failed: %s\n",
283: strerror(errno));
284: return (1);
285: }
286: cfmakeraw(&tio);
287: tio.c_iflag = ICRNL|IXANY;
288: tio.c_oflag = OPOST|ONLCR;
289: tio.c_lflag = NOKERNINFO;
290: tio.c_cflag = CREAD|CS8|HUPCL;
291: tio.c_cc[VMIN] = 1;
292: tio.c_cc[VTIME] = 0;
293: cfsetispeed(&tio, cfgetispeed(&saved_tio));
294: cfsetospeed(&tio, cfgetospeed(&saved_tio));
295: tcsetattr(STDIN_FILENO, TCSANOW, &tio);
296: }
1.1 nicm 297:
1.71 nicm 298: /* Send identify messages. */
1.93 ! nicm 299: client_send_identify();
1.1 nicm 300:
1.46 nicm 301: /* Send first command. */
302: if (msg == MSG_COMMAND) {
1.70 nicm 303: /* How big is the command? */
304: size = 0;
305: for (i = 0; i < argc; i++)
306: size += strlen(argv[i]) + 1;
307: data = xmalloc((sizeof *data) + size);
1.46 nicm 308:
309: /* Prepare command for server. */
1.70 nicm 310: data->argc = argc;
1.83 nicm 311: if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
1.55 nicm 312: fprintf(stderr, "command too long\n");
1.70 nicm 313: free(data);
1.46 nicm 314: return (1);
315: }
1.70 nicm 316: size += sizeof *data;
1.46 nicm 317:
1.70 nicm 318: /* Send the command. */
319: if (client_write_server(msg, data, size) != 0) {
320: fprintf(stderr, "failed to send command\n");
321: free(data);
322: return (1);
323: }
324: free(data);
1.46 nicm 325: } else if (msg == MSG_SHELL)
326: client_write_server(msg, NULL, 0);
1.1 nicm 327:
1.46 nicm 328: /* Set the event and dispatch. */
329: client_update_event();
330: event_dispatch();
331:
332: /* Print the exit message, if any, and exit. */
1.48 nicm 333: if (client_attached) {
1.93 ! nicm 334: if (client_exitreason != CLIENT_EXIT_NONE)
1.52 nicm 335: printf("[%s]\n", client_exit_message());
1.48 nicm 336:
337: ppid = getppid();
338: if (client_exittype == MSG_DETACHKILL && ppid > 1)
339: kill(ppid, SIGHUP);
1.93 ! nicm 340: } else if (client_flags & CLIENT_CONTROLCONTROL) {
1.68 nicm 341: if (client_exitreason != CLIENT_EXIT_NONE)
342: printf("%%exit %s\n", client_exit_message());
343: else
344: printf("%%exit\n");
345: printf("\033\\");
1.56 nicm 346: tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
1.63 nicm 347: }
1.54 nicm 348: setblocking(STDIN_FILENO, 1);
1.46 nicm 349: return (client_exitval);
1.1 nicm 350: }
351:
1.71 nicm 352: /* Send identify messages to server. */
1.11 nicm 353: void
1.93 ! nicm 354: client_send_identify(void)
1.26 nicm 355: {
1.90 nicm 356: const char *s;
1.71 nicm 357: char **ss;
1.91 nicm 358: size_t sslen;
1.93 ! nicm 359: int fd, flags = client_flags;
1.90 nicm 360: pid_t pid;
1.71 nicm 361:
362: client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
363:
364: if ((s = getenv("TERM")) == NULL)
365: s = "";
366: client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
367:
368: if ((s = ttyname(STDIN_FILENO)) == NULL)
369: s = "";
370: client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1);
371:
372: if ((fd = open(".", O_RDONLY)) == -1)
373: fd = open("/", O_RDONLY);
374: client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0);
1.26 nicm 375:
1.50 nicm 376: if ((fd = dup(STDIN_FILENO)) == -1)
377: fatal("dup failed");
1.71 nicm 378: client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0);
1.90 nicm 379:
380: pid = getpid();
381: client_write_one(MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
1.26 nicm 382:
1.91 nicm 383: for (ss = environ; *ss != NULL; ss++) {
384: sslen = strlen(*ss) + 1;
385: if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
386: client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
387: }
1.75 nicm 388:
1.71 nicm 389: client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0);
1.11 nicm 390:
1.71 nicm 391: client_update_event();
1.11 nicm 392: }
393:
1.70 nicm 394: /* Helper to send one message. */
395: int
396: client_write_one(enum msgtype type, int fd, const void *buf, size_t len)
397: {
398: int retval;
399:
400: retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd,
1.83 nicm 401: (void *)buf, len);
1.70 nicm 402: if (retval != 1)
403: return (-1);
404: return (0);
405: }
406:
1.46 nicm 407: /* Write a message to the server without a file descriptor. */
1.70 nicm 408: int
409: client_write_server(enum msgtype type, const void *buf, size_t len)
1.25 nicm 410: {
1.70 nicm 411: int retval;
412:
413: retval = client_write_one(type, -1, buf, len);
414: if (retval == 0)
415: client_update_event();
416: return (retval);
1.25 nicm 417: }
418:
1.46 nicm 419: /* Update client event based on whether it needs to read or read and write. */
1.31 nicm 420: void
421: client_update_event(void)
422: {
423: short events;
424:
425: event_del(&client_event);
426: events = EV_READ;
427: if (client_ibuf.w.queued > 0)
428: events |= EV_WRITE;
1.93 ! nicm 429: event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
1.31 nicm 430: event_add(&client_event, NULL);
431: }
432:
1.46 nicm 433: /* Callback to handle signals in the client. */
1.30 nicm 434: void
1.93 ! nicm 435: client_signal(int sig, unused short events, unused void *arg)
1.30 nicm 436: {
1.46 nicm 437: struct sigaction sigact;
438: int status;
1.30 nicm 439:
1.84 nicm 440: if (sig == SIGCHLD)
441: waitpid(WAIT_ANY, &status, WNOHANG);
442: else if (!client_attached) {
443: if (sig == SIGTERM)
1.46 nicm 444: event_loopexit(NULL);
445: } else {
446: switch (sig) {
447: case SIGHUP:
1.52 nicm 448: client_exitreason = CLIENT_EXIT_LOST_TTY;
1.46 nicm 449: client_exitval = 1;
450: client_write_server(MSG_EXITING, NULL, 0);
451: break;
452: case SIGTERM:
1.52 nicm 453: client_exitreason = CLIENT_EXIT_TERMINATED;
1.46 nicm 454: client_exitval = 1;
455: client_write_server(MSG_EXITING, NULL, 0);
456: break;
457: case SIGWINCH:
458: client_write_server(MSG_RESIZE, NULL, 0);
459: break;
460: case SIGCONT:
461: memset(&sigact, 0, sizeof sigact);
462: sigemptyset(&sigact.sa_mask);
463: sigact.sa_flags = SA_RESTART;
464: sigact.sa_handler = SIG_IGN;
465: if (sigaction(SIGTSTP, &sigact, NULL) != 0)
466: fatal("sigaction failed");
467: client_write_server(MSG_WAKEUP, NULL, 0);
468: break;
469: }
1.30 nicm 470: }
471:
1.31 nicm 472: client_update_event();
1.30 nicm 473: }
474:
1.46 nicm 475: /* Callback for client imsg read events. */
1.30 nicm 476: void
1.93 ! nicm 477: client_callback(unused int fd, short events, unused void *arg)
1.30 nicm 478: {
1.33 nicm 479: ssize_t n;
1.46 nicm 480: int retval;
1.30 nicm 481:
482: if (events & EV_READ) {
483: if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
484: goto lost_server;
1.46 nicm 485: if (client_attached)
486: retval = client_dispatch_attached();
487: else
1.93 ! nicm 488: retval = client_dispatch_wait();
1.46 nicm 489: if (retval != 0) {
1.30 nicm 490: event_loopexit(NULL);
491: return;
1.35 nicm 492: }
1.30 nicm 493: }
1.35 nicm 494:
1.30 nicm 495: if (events & EV_WRITE) {
1.81 krw 496: if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN)
1.30 nicm 497: goto lost_server;
498: }
499:
1.31 nicm 500: client_update_event();
1.30 nicm 501: return;
502:
503: lost_server:
1.52 nicm 504: client_exitreason = CLIENT_EXIT_LOST_SERVER;
1.32 nicm 505: client_exitval = 1;
1.30 nicm 506: event_loopexit(NULL);
507: }
508:
1.54 nicm 509: /* Callback for client stdin read events. */
510: void
1.93 ! nicm 511: client_stdin_callback(unused int fd, unused short events, unused void *arg)
1.54 nicm 512: {
513: struct msg_stdin_data data;
514:
515: data.size = read(STDIN_FILENO, data.data, sizeof data.data);
516: if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
517: return;
518:
519: client_write_server(MSG_STDIN, &data, sizeof data);
520: if (data.size <= 0)
521: event_del(&client_stdin);
522: client_update_event();
523: }
524:
1.57 nicm 525: /* Force write to file descriptor. */
526: void
527: client_write(int fd, const char *data, size_t size)
528: {
529: ssize_t used;
530:
531: while (size != 0) {
532: used = write(fd, data, size);
533: if (used == -1) {
534: if (errno == EINTR || errno == EAGAIN)
535: continue;
536: break;
537: }
538: data += used;
539: size -= used;
540: }
541: }
542:
1.93 ! nicm 543: /* Run command in shell; used for -c. */
! 544: __dead void
! 545: client_exec(const char *shell)
! 546: {
! 547: const char *name, *ptr;
! 548: char *argv0;
! 549:
! 550: log_debug("shell %s, command %s", shell, shell_cmd);
! 551:
! 552: ptr = strrchr(shell, '/');
! 553: if (ptr != NULL && *(ptr + 1) != '\0')
! 554: name = ptr + 1;
! 555: else
! 556: name = shell;
! 557: if (client_flags & CLIENT_LOGIN)
! 558: xasprintf(&argv0, "-%s", name);
! 559: else
! 560: xasprintf(&argv0, "%s", name);
! 561: setenv("SHELL", shell, 1);
! 562:
! 563: setblocking(STDIN_FILENO, 1);
! 564: setblocking(STDOUT_FILENO, 1);
! 565: setblocking(STDERR_FILENO, 1);
! 566: closefrom(STDERR_FILENO + 1);
! 567:
! 568: execl(shell, argv0, "-c", shell_cmd, (char *) NULL);
! 569: fatal("execl failed");
! 570: }
! 571:
1.46 nicm 572: /* Dispatch imsgs when in wait state (before MSG_READY). */
573: int
1.93 ! nicm 574: client_dispatch_wait(void)
1.46 nicm 575: {
1.69 nicm 576: struct imsg imsg;
577: char *data;
578: ssize_t n, datalen;
579: struct msg_stdout_data stdoutdata;
580: struct msg_stderr_data stderrdata;
581: int retval;
1.46 nicm 582:
583: for (;;) {
584: if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
585: fatalx("imsg_get failed");
586: if (n == 0)
587: return (0);
1.69 nicm 588:
589: data = imsg.data;
1.46 nicm 590: datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
591:
1.86 nicm 592: log_debug("got %u from server", imsg.hdr.type);
1.46 nicm 593: switch (imsg.hdr.type) {
594: case MSG_EXIT:
595: case MSG_SHUTDOWN:
1.69 nicm 596: if (datalen != sizeof retval && datalen != 0)
597: fatalx("bad MSG_EXIT size");
598: if (datalen == sizeof retval) {
599: memcpy(&retval, data, sizeof retval);
600: client_exitval = retval;
1.46 nicm 601: }
602: imsg_free(&imsg);
603: return (-1);
604: case MSG_READY:
605: if (datalen != 0)
606: fatalx("bad MSG_READY size");
607:
1.54 nicm 608: event_del(&client_stdin);
1.46 nicm 609: client_attached = 1;
1.65 nicm 610: client_write_server(MSG_RESIZE, NULL, 0);
1.60 nicm 611: break;
612: case MSG_STDIN:
613: if (datalen != 0)
614: fatalx("bad MSG_STDIN size");
615:
616: event_add(&client_stdin, NULL);
1.46 nicm 617: break;
1.54 nicm 618: case MSG_STDOUT:
619: if (datalen != sizeof stdoutdata)
1.69 nicm 620: fatalx("bad MSG_STDOUT size");
621: memcpy(&stdoutdata, data, sizeof stdoutdata);
1.54 nicm 622:
1.70 nicm 623: client_write(STDOUT_FILENO, stdoutdata.data,
624: stdoutdata.size);
1.54 nicm 625: break;
626: case MSG_STDERR:
627: if (datalen != sizeof stderrdata)
1.69 nicm 628: fatalx("bad MSG_STDERR size");
629: memcpy(&stderrdata, data, sizeof stderrdata);
1.54 nicm 630:
1.70 nicm 631: client_write(STDERR_FILENO, stderrdata.data,
632: stderrdata.size);
1.54 nicm 633: break;
1.46 nicm 634: case MSG_VERSION:
635: if (datalen != 0)
636: fatalx("bad MSG_VERSION size");
637:
1.54 nicm 638: fprintf(stderr, "protocol version mismatch "
1.86 nicm 639: "(client %d, server %u)\n", PROTOCOL_VERSION,
1.54 nicm 640: imsg.hdr.peerid);
1.46 nicm 641: client_exitval = 1;
642:
643: imsg_free(&imsg);
644: return (-1);
645: case MSG_SHELL:
1.72 nicm 646: if (datalen == 0 || data[datalen - 1] != '\0')
1.69 nicm 647: fatalx("bad MSG_SHELL string");
1.46 nicm 648:
649: clear_signals(0);
1.93 ! nicm 650: client_exec(data);
1.46 nicm 651: /* NOTREACHED */
1.56 nicm 652: case MSG_DETACH:
1.73 nicm 653: case MSG_DETACHKILL:
1.56 nicm 654: client_write_server(MSG_EXITING, NULL, 0);
655: break;
656: case MSG_EXITED:
657: imsg_free(&imsg);
658: return (-1);
1.46 nicm 659: }
660:
661: imsg_free(&imsg);
662: }
663: }
664:
665: /* Dispatch imsgs in attached state (after MSG_READY). */
1.9 nicm 666: int
1.46 nicm 667: client_dispatch_attached(void)
1.9 nicm 668: {
1.69 nicm 669: struct imsg imsg;
670: struct sigaction sigact;
671: char *data;
672: ssize_t n, datalen;
1.9 nicm 673:
674: for (;;) {
1.25 nicm 675: if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
1.12 nicm 676: fatalx("imsg_get failed");
677: if (n == 0)
1.9 nicm 678: return (0);
1.69 nicm 679:
680: data = imsg.data;
1.12 nicm 681: datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1.9 nicm 682:
1.86 nicm 683: log_debug("got %u from server", imsg.hdr.type);
1.12 nicm 684: switch (imsg.hdr.type) {
1.73 nicm 685: case MSG_DETACH:
1.48 nicm 686: case MSG_DETACHKILL:
1.73 nicm 687: if (datalen == 0 || data[datalen - 1] != '\0')
688: fatalx("bad MSG_DETACH string");
1.9 nicm 689:
1.73 nicm 690: client_exitsession = xstrdup(data);
1.48 nicm 691: client_exittype = imsg.hdr.type;
692: if (imsg.hdr.type == MSG_DETACHKILL)
1.52 nicm 693: client_exitreason = CLIENT_EXIT_DETACHED_HUP;
1.48 nicm 694: else
1.52 nicm 695: client_exitreason = CLIENT_EXIT_DETACHED;
1.25 nicm 696: client_write_server(MSG_EXITING, NULL, 0);
1.9 nicm 697: break;
698: case MSG_EXIT:
1.69 nicm 699: if (datalen != 0 && datalen != sizeof (int))
1.9 nicm 700: fatalx("bad MSG_EXIT size");
1.12 nicm 701:
1.25 nicm 702: client_write_server(MSG_EXITING, NULL, 0);
1.52 nicm 703: client_exitreason = CLIENT_EXIT_EXITED;
1.9 nicm 704: break;
705: case MSG_EXITED:
1.12 nicm 706: if (datalen != 0)
1.9 nicm 707: fatalx("bad MSG_EXITED size");
708:
1.12 nicm 709: imsg_free(&imsg);
1.9 nicm 710: return (-1);
711: case MSG_SHUTDOWN:
1.12 nicm 712: if (datalen != 0)
1.9 nicm 713: fatalx("bad MSG_SHUTDOWN size");
714:
1.25 nicm 715: client_write_server(MSG_EXITING, NULL, 0);
1.52 nicm 716: client_exitreason = CLIENT_EXIT_SERVER_EXITED;
1.32 nicm 717: client_exitval = 1;
1.9 nicm 718: break;
719: case MSG_SUSPEND:
1.12 nicm 720: if (datalen != 0)
1.9 nicm 721: fatalx("bad MSG_SUSPEND size");
722:
1.30 nicm 723: memset(&sigact, 0, sizeof sigact);
724: sigemptyset(&sigact.sa_mask);
725: sigact.sa_flags = SA_RESTART;
726: sigact.sa_handler = SIG_DFL;
727: if (sigaction(SIGTSTP, &sigact, NULL) != 0)
728: fatal("sigaction failed");
729: kill(getpid(), SIGTSTP);
1.21 nicm 730: break;
731: case MSG_LOCK:
1.72 nicm 732: if (datalen == 0 || data[datalen - 1] != '\0')
1.69 nicm 733: fatalx("bad MSG_LOCK string");
1.35 nicm 734:
1.69 nicm 735: system(data);
1.25 nicm 736: client_write_server(MSG_UNLOCK, NULL, 0);
1.9 nicm 737: break;
738: }
1.12 nicm 739:
740: imsg_free(&imsg);
1.9 nicm 741: }
1.1 nicm 742: }