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