xref: /netbsd-src/external/bsd/tmux/dist/client.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* $OpenBSD$ */
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/file.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 <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "tmux.h"
35 
36 int		client_flags;
37 struct imsgbuf	client_ibuf;
38 struct event	client_event;
39 struct event	client_stdin;
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;
50 int		client_exitval;
51 enum msgtype	client_exittype;
52 const char     *client_exitsession;
53 int		client_attached;
54 
55 __dead void	client_exec(const char *);
56 int		client_get_lock(char *);
57 int		client_connect(struct event_base *, char *, int);
58 void		client_send_identify(const char *, int);
59 int		client_write_one(enum msgtype, int, const void *, size_t);
60 int		client_write_server(enum msgtype, const void *, size_t);
61 void		client_update_event(void);
62 void		client_signal(int, short, void *);
63 void		client_stdin_callback(int, short, void *);
64 void		client_write(int, const char *, size_t);
65 void		client_callback(int, short, void *);
66 int		client_dispatch_attached(void);
67 int		client_dispatch_wait(void);
68 const char     *client_exit_message(void);
69 
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");
83 	log_debug("lock file is %s", lockfile);
84 
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)
90 			/* nothing */;
91 		close(lockfd);
92 		return (-1);
93 	}
94 	log_debug("flock succeeded");
95 
96 	return (lockfd);
97 }
98 
99 /* Connect client to server. */
100 int
101 client_connect(struct event_base *base, char *path, int start_server)
102 {
103 	struct sockaddr_un	sa;
104 	size_t			size;
105 	int			fd, lockfd = -1, locked = 0;
106 	char		       *lockfile = NULL;
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;
113 		return (-1);
114 	}
115 	log_debug("socket is %s", path);
116 
117 retry:
118 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
119 		fatal("socket failed");
120 
121 	log_debug("trying connect");
122 	if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
123 		log_debug("connect failed: %s", strerror(errno));
124 		if (errno != ECONNREFUSED && errno != ENOENT)
125 			goto failed;
126 		if (!start_server)
127 			goto failed;
128 		close(fd);
129 
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;
146 			goto retry;
147 		}
148 
149 		if (unlink(path) != 0 && errno != ENOENT) {
150 			free(lockfile);
151 			close(lockfd);
152 			return (-1);
153 		}
154 		fd = server_start(base, lockfd, lockfile);
155 	}
156 
157 	if (locked) {
158 		free(lockfile);
159 		close(lockfd);
160 	}
161 	setblocking(fd, 0);
162 	return (fd);
163 
164 failed:
165 	if (locked) {
166 		free(lockfile);
167 		close(lockfd);
168 	}
169 	close(fd);
170 	return (-1);
171 }
172 
173 /* Get exit string from reason number. */
174 const char *
175 client_exit_message(void)
176 {
177 	static char msg[256];
178 
179 	switch (client_exitreason) {
180 	case CLIENT_EXIT_NONE:
181 		break;
182 	case CLIENT_EXIT_DETACHED:
183 		if (client_exitsession != NULL) {
184 			xsnprintf(msg, sizeof msg, "detached "
185 			    "(from session %s)", client_exitsession);
186 			return (msg);
187 		}
188 		return ("detached");
189 	case CLIENT_EXIT_DETACHED_HUP:
190 		if (client_exitsession != NULL) {
191 			xsnprintf(msg, sizeof msg, "detached and SIGHUP "
192 			    "(from session %s)", client_exitsession);
193 			return (msg);
194 		}
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 
210 /* Client main loop. */
211 int
212 client_main(struct event_base *base, int argc, char **argv, int flags)
213 {
214 	struct cmd		*cmd;
215 	struct cmd_list		*cmdlist;
216 	struct msg_command_data	*data;
217 	int			 cmdflags, fd, i, cwd;
218 	const char*              ttynam;
219 	pid_t			 ppid;
220 	enum msgtype		 msg;
221 	char			*cause;
222 	struct termios		 tio, saved_tio;
223 	size_t			 size;
224 
225 	/* Save the flags. */
226 	client_flags = flags;
227 
228 	/* Set up the initial command. */
229 	cmdflags = 0;
230 	if (shell_cmd != NULL) {
231 		msg = MSG_SHELL;
232 		cmdflags = CMD_STARTSERVER;
233 	} else if (argc == 0) {
234 		msg = MSG_COMMAND;
235 		cmdflags = CMD_STARTSERVER;
236 	} else {
237 		msg = MSG_COMMAND;
238 
239 		/*
240 		 * It sucks parsing the command string twice (in client and
241 		 * later in server) but it is necessary to get the start server
242 		 * flag.
243 		 */
244 		cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
245 		if (cmdlist == NULL) {
246 			fprintf(stderr, "%s\n", cause);
247 			return (1);
248 		}
249 		cmdflags &= ~CMD_STARTSERVER;
250 		TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
251 			if (cmd->entry->flags & CMD_STARTSERVER)
252 				cmdflags |= CMD_STARTSERVER;
253 		}
254 		cmd_list_free(cmdlist);
255 	}
256 
257 	/* Establish signal handlers. */
258 	set_signals(client_signal);
259 
260 	/* Initialize the client socket and start the server. */
261 	fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
262 	if (fd == -1) {
263 		if (errno == ECONNREFUSED) {
264 			fprintf(stderr, "no server running on %s\n",
265 			    socket_path);
266 		} else {
267 			fprintf(stderr, "error connecting to %s (%s)\n",
268 			    socket_path, strerror(errno));
269 		}
270 		return (1);
271 	}
272 
273 	/* Save these before pledge(). */
274 	if ((cwd = open(".", O_RDONLY)) == -1)
275 		cwd = open("/", O_RDONLY);
276 	if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
277 		ttynam = "";
278 
279 #ifdef __OpenBSD__
280 	/*
281 	 * Drop privileges for client. "proc exec" is needed for -c and for
282 	 * locking (which uses system(3)).
283 	 *
284 	 * "tty" is needed to restore termios(4) and also for some reason -CC
285 	 * does not work properly without it (input is not recognised).
286 	 *
287 	 * "sendfd" is dropped later in client_dispatch_wait().
288 	 */
289 	if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
290 		fatal("pledge failed");
291 #endif
292 
293 	/* Free stuff that is not used in the client. */
294 	options_free(&global_options);
295 	options_free(&global_s_options);
296 	options_free(&global_w_options);
297 	environ_free(&global_environ);
298 
299 	/* Set process title, log and signals now this is the client. */
300 #ifdef HAVE_SETPROCTITLE
301 	setproctitle("client (%s)", socket_path);
302 #endif
303 	logfile("client");
304 
305 	/* Create imsg. */
306 	imsg_init(&client_ibuf, fd);
307 	event_set(&client_event, fd, EV_READ, client_callback, NULL);
308 
309 	/* Create stdin handler. */
310 	setblocking(STDIN_FILENO, 0);
311 	event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
312 	    client_stdin_callback, NULL);
313 	if (client_flags & CLIENT_CONTROLCONTROL) {
314 		if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
315 			fprintf(stderr, "tcgetattr failed: %s\n",
316 			    strerror(errno));
317 			return (1);
318 		}
319 		cfmakeraw(&tio);
320 		tio.c_iflag = ICRNL|IXANY;
321 		tio.c_oflag = OPOST|ONLCR;
322 #ifdef NOKERNINFO
323 		tio.c_lflag = NOKERNINFO;
324 #endif
325 		tio.c_cflag = CREAD|CS8|HUPCL;
326 		tio.c_cc[VMIN] = 1;
327 		tio.c_cc[VTIME] = 0;
328 		cfsetispeed(&tio, cfgetispeed(&saved_tio));
329 		cfsetospeed(&tio, cfgetospeed(&saved_tio));
330 		tcsetattr(STDIN_FILENO, TCSANOW, &tio);
331 	}
332 
333 	/* Send identify messages. */
334 	client_send_identify(ttynam, cwd); /* closes cwd */
335 
336 	/* Send first command. */
337 	if (msg == MSG_COMMAND) {
338 		/* How big is the command? */
339 		size = 0;
340 		for (i = 0; i < argc; i++)
341 			size += strlen(argv[i]) + 1;
342 		data = xmalloc((sizeof *data) + size);
343 
344 		/* Prepare command for server. */
345 		data->argc = argc;
346 		if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
347 			fprintf(stderr, "command too long\n");
348 			free(data);
349 			return (1);
350 		}
351 		size += sizeof *data;
352 
353 		/* Send the command. */
354 		if (client_write_server(msg, data, size) != 0) {
355 			fprintf(stderr, "failed to send command\n");
356 			free(data);
357 			return (1);
358 		}
359 		free(data);
360 	} else if (msg == MSG_SHELL)
361 		client_write_server(msg, NULL, 0);
362 
363 	/* Set the event and dispatch. */
364 	client_update_event();
365 	event_dispatch();
366 
367 	/* Print the exit message, if any, and exit. */
368 	if (client_attached) {
369 		if (client_exitreason != CLIENT_EXIT_NONE)
370 			printf("[%s]\n", client_exit_message());
371 
372 		ppid = getppid();
373 		if (client_exittype == MSG_DETACHKILL && ppid > 1)
374 			kill(ppid, SIGHUP);
375 	} else if (client_flags & CLIENT_CONTROLCONTROL) {
376 		if (client_exitreason != CLIENT_EXIT_NONE)
377 			printf("%%exit %s\n", client_exit_message());
378 		else
379 			printf("%%exit\n");
380 		printf("\033\\");
381 		tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
382 	}
383 	setblocking(STDIN_FILENO, 1);
384 	return (client_exitval);
385 }
386 
387 /* Send identify messages to server. */
388 void
389 client_send_identify(const char *ttynam, int cwd)
390 {
391 	const char	 *s;
392 	char		**ss;
393 	size_t		  sslen;
394 	int		  fd, flags = client_flags;
395 	pid_t		  pid;
396 
397 	client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
398 
399 	if ((s = getenv("TERM")) == NULL)
400 		s = "";
401 	client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
402 
403 	client_write_one(MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1);
404 	client_write_one(MSG_IDENTIFY_CWD, cwd, NULL, 0);
405 
406 	if ((fd = dup(STDIN_FILENO)) == -1)
407 		fatal("dup failed");
408 	client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0);
409 
410 	pid = getpid();
411 	client_write_one(MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
412 
413 	for (ss = environ; *ss != NULL; ss++) {
414 		sslen = strlen(*ss) + 1;
415 		if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
416 			client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
417 	}
418 
419 	client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0);
420 }
421 
422 /* Helper to send one message. */
423 int
424 client_write_one(enum msgtype type, int fd, const void *buf, size_t len)
425 {
426 	int	retval;
427 
428 	retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd,
429 	    __UNCONST(buf), len);
430 	if (retval != 1)
431 		return (-1);
432 	return (0);
433 }
434 
435 /* Write a message to the server without a file descriptor. */
436 int
437 client_write_server(enum msgtype type, const void *buf, size_t len)
438 {
439 	int	retval;
440 
441 	retval = client_write_one(type, -1, buf, len);
442 	if (retval == 0)
443 		client_update_event();
444 	return (retval);
445 }
446 
447 /* Update client event based on whether it needs to read or read and write. */
448 void
449 client_update_event(void)
450 {
451 	short	events;
452 
453 	event_del(&client_event);
454 	events = EV_READ;
455 	if (client_ibuf.w.queued > 0)
456 		events |= EV_WRITE;
457 	event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
458 	event_add(&client_event, NULL);
459 }
460 
461 /* Callback to handle signals in the client. */
462 void
463 client_signal(int sig, unused short events, unused void *arg)
464 {
465 	struct sigaction sigact;
466 	int		 status;
467 
468 	if (sig == SIGCHLD)
469 		waitpid(WAIT_ANY, &status, WNOHANG);
470 	else if (!client_attached) {
471 		if (sig == SIGTERM)
472 			event_loopexit(NULL);
473 	} else {
474 		switch (sig) {
475 		case SIGHUP:
476 			client_exitreason = CLIENT_EXIT_LOST_TTY;
477 			client_exitval = 1;
478 			client_write_server(MSG_EXITING, NULL, 0);
479 			break;
480 		case SIGTERM:
481 			client_exitreason = CLIENT_EXIT_TERMINATED;
482 			client_exitval = 1;
483 			client_write_server(MSG_EXITING, NULL, 0);
484 			break;
485 		case SIGWINCH:
486 			client_write_server(MSG_RESIZE, NULL, 0);
487 			break;
488 		case SIGCONT:
489 			memset(&sigact, 0, sizeof sigact);
490 			sigemptyset(&sigact.sa_mask);
491 			sigact.sa_flags = SA_RESTART;
492 			sigact.sa_handler = SIG_IGN;
493 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
494 				fatal("sigaction failed");
495 			client_write_server(MSG_WAKEUP, NULL, 0);
496 			break;
497 		}
498 	}
499 
500 	client_update_event();
501 }
502 
503 /* Callback for client imsg read events. */
504 void
505 client_callback(unused int fd, short events, unused void *arg)
506 {
507 	ssize_t	n;
508 	int	retval;
509 
510 	if (events & EV_READ) {
511 		if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
512 			goto lost_server;
513 		if (client_attached)
514 			retval = client_dispatch_attached();
515 		else
516 			retval = client_dispatch_wait();
517 		if (retval != 0) {
518 			event_loopexit(NULL);
519 			return;
520 		}
521 	}
522 
523 	if (events & EV_WRITE) {
524 		if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN)
525 			goto lost_server;
526 	}
527 
528 	client_update_event();
529 	return;
530 
531 lost_server:
532 	client_exitreason = CLIENT_EXIT_LOST_SERVER;
533 	client_exitval = 1;
534 	event_loopexit(NULL);
535 }
536 
537 /* Callback for client stdin read events. */
538 void
539 client_stdin_callback(unused int fd, unused short events, unused void *arg)
540 {
541 	struct msg_stdin_data	data;
542 
543 	data.size = read(STDIN_FILENO, data.data, sizeof data.data);
544 	if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
545 		return;
546 
547 	client_write_server(MSG_STDIN, &data, sizeof data);
548 	if (data.size <= 0)
549 		event_del(&client_stdin);
550 	client_update_event();
551 }
552 
553 /* Force write to file descriptor. */
554 void
555 client_write(int fd, const char *data, size_t size)
556 {
557 	ssize_t	used;
558 
559 	while (size != 0) {
560 		used = write(fd, data, size);
561 		if (used == -1) {
562 			if (errno == EINTR || errno == EAGAIN)
563 				continue;
564 			break;
565 		}
566 		data += used;
567 		size -= used;
568 	}
569 }
570 
571 /* Run command in shell; used for -c. */
572 __dead void
573 client_exec(const char *shell)
574 {
575 	const char	*name, *ptr;
576 	char		*argv0;
577 
578 	log_debug("shell %s, command %s", shell, shell_cmd);
579 
580 	ptr = strrchr(shell, '/');
581 	if (ptr != NULL && *(ptr + 1) != '\0')
582 		name = ptr + 1;
583 	else
584 		name = shell;
585 	if (client_flags & CLIENT_LOGIN)
586 		xasprintf(&argv0, "-%s", name);
587 	else
588 		xasprintf(&argv0, "%s", name);
589 	setenv("SHELL", shell, 1);
590 
591 	setblocking(STDIN_FILENO, 1);
592 	setblocking(STDOUT_FILENO, 1);
593 	setblocking(STDERR_FILENO, 1);
594 	closefrom(STDERR_FILENO + 1);
595 
596 	execl(shell, argv0, "-c", shell_cmd, (char *) NULL);
597 	fatal("execl failed");
598 }
599 
600 /* Dispatch imsgs when in wait state (before MSG_READY). */
601 int
602 client_dispatch_wait(void)
603 {
604 	struct imsg		 imsg;
605 	char			*data;
606 	ssize_t			 n, datalen;
607 	struct msg_stdout_data	 stdoutdata;
608 	struct msg_stderr_data	 stderrdata;
609 	int			 retval;
610 #ifdef __OpenBSD__
611 	static int		 pledge_applied;
612 
613 	/*
614 	 * "sendfd" is no longer required once all of the identify messages
615 	 * have been sent. We know the server won't send us anything until that
616 	 * point (because we don't ask it to), so we can drop "sendfd" once we
617 	 * get the first message from the server.
618 	 */
619 	if (!pledge_applied) {
620 		if (pledge("stdio unix proc exec tty", NULL) != 0)
621 			fatal("pledge failed");
622 		pledge_applied = 1;
623 	};
624 #endif
625 
626 	for (;;) {
627 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
628 			fatalx("imsg_get failed");
629 		if (n == 0)
630 			return (0);
631 
632 		data = imsg.data;
633 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
634 
635 		log_debug("got %u from server", imsg.hdr.type);
636 		switch (imsg.hdr.type) {
637 		case MSG_EXIT:
638 		case MSG_SHUTDOWN:
639 			if (datalen != sizeof retval && datalen != 0)
640 				fatalx("bad MSG_EXIT size");
641 			if (datalen == sizeof retval) {
642 				memcpy(&retval, data, sizeof retval);
643 				client_exitval = retval;
644 			}
645 			imsg_free(&imsg);
646 			return (-1);
647 		case MSG_READY:
648 			if (datalen != 0)
649 				fatalx("bad MSG_READY size");
650 
651 			event_del(&client_stdin);
652 			client_attached = 1;
653 			client_write_server(MSG_RESIZE, NULL, 0);
654 			break;
655 		case MSG_STDIN:
656 			if (datalen != 0)
657 				fatalx("bad MSG_STDIN size");
658 
659 			event_add(&client_stdin, NULL);
660 			break;
661 		case MSG_STDOUT:
662 			if (datalen != sizeof stdoutdata)
663 				fatalx("bad MSG_STDOUT size");
664 			memcpy(&stdoutdata, data, sizeof stdoutdata);
665 
666 			client_write(STDOUT_FILENO, stdoutdata.data,
667 			    stdoutdata.size);
668 			break;
669 		case MSG_STDERR:
670 			if (datalen != sizeof stderrdata)
671 				fatalx("bad MSG_STDERR size");
672 			memcpy(&stderrdata, data, sizeof stderrdata);
673 
674 			client_write(STDERR_FILENO, stderrdata.data,
675 			    stderrdata.size);
676 			break;
677 		case MSG_VERSION:
678 			if (datalen != 0)
679 				fatalx("bad MSG_VERSION size");
680 
681 			fprintf(stderr, "protocol version mismatch "
682 			    "(client %d, server %u)\n", PROTOCOL_VERSION,
683 			    imsg.hdr.peerid);
684 			client_exitval = 1;
685 
686 			imsg_free(&imsg);
687 			return (-1);
688 		case MSG_SHELL:
689 			if (datalen == 0 || data[datalen - 1] != '\0')
690 				fatalx("bad MSG_SHELL string");
691 
692 			clear_signals(0);
693 			client_exec(data);
694 			/* NOTREACHED */
695 		case MSG_DETACH:
696 		case MSG_DETACHKILL:
697 			client_write_server(MSG_EXITING, NULL, 0);
698 			break;
699 		case MSG_EXITED:
700 			imsg_free(&imsg);
701 			return (-1);
702 		}
703 
704 		imsg_free(&imsg);
705 	}
706 }
707 
708 /* Dispatch imsgs in attached state (after MSG_READY). */
709 int
710 client_dispatch_attached(void)
711 {
712 	struct imsg		 imsg;
713 	struct sigaction	 sigact;
714 	char			*data;
715 	ssize_t			 n, datalen;
716 
717 	for (;;) {
718 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
719 			fatalx("imsg_get failed");
720 		if (n == 0)
721 			return (0);
722 
723 		data = imsg.data;
724 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
725 
726 		log_debug("got %u from server", imsg.hdr.type);
727 		switch (imsg.hdr.type) {
728 		case MSG_DETACH:
729 		case MSG_DETACHKILL:
730 			if (datalen == 0 || data[datalen - 1] != '\0')
731 				fatalx("bad MSG_DETACH string");
732 
733 			client_exitsession = xstrdup(data);
734 			client_exittype = imsg.hdr.type;
735 			if (imsg.hdr.type == MSG_DETACHKILL)
736 				client_exitreason = CLIENT_EXIT_DETACHED_HUP;
737 			else
738 				client_exitreason = CLIENT_EXIT_DETACHED;
739 			client_write_server(MSG_EXITING, NULL, 0);
740 			break;
741 		case MSG_EXIT:
742 			if (datalen != 0 && datalen != sizeof (int))
743 				fatalx("bad MSG_EXIT size");
744 
745 			client_write_server(MSG_EXITING, NULL, 0);
746 			client_exitreason = CLIENT_EXIT_EXITED;
747 			break;
748 		case MSG_EXITED:
749 			if (datalen != 0)
750 				fatalx("bad MSG_EXITED size");
751 
752 			imsg_free(&imsg);
753 			return (-1);
754 		case MSG_SHUTDOWN:
755 			if (datalen != 0)
756 				fatalx("bad MSG_SHUTDOWN size");
757 
758 			client_write_server(MSG_EXITING, NULL, 0);
759 			client_exitreason = CLIENT_EXIT_SERVER_EXITED;
760 			client_exitval = 1;
761 			break;
762 		case MSG_SUSPEND:
763 			if (datalen != 0)
764 				fatalx("bad MSG_SUSPEND size");
765 
766 			memset(&sigact, 0, sizeof sigact);
767 			sigemptyset(&sigact.sa_mask);
768 			sigact.sa_flags = SA_RESTART;
769 			sigact.sa_handler = SIG_DFL;
770 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
771 				fatal("sigaction failed");
772 			kill(getpid(), SIGTSTP);
773 			break;
774 		case MSG_LOCK:
775 			if (datalen == 0 || data[datalen - 1] != '\0')
776 				fatalx("bad MSG_LOCK string");
777 
778 			system(data);
779 			client_write_server(MSG_UNLOCK, NULL, 0);
780 			break;
781 		}
782 
783 		imsg_free(&imsg);
784 	}
785 }
786