xref: /openbsd-src/usr.bin/tmux/client.c (revision 48950c12d106c85f315112191a0228d7b83b9510)
1 /* $OpenBSD: client.c,v 1.65 2013/03/25 11:38:57 nicm 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/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 <pwd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "tmux.h"
35 
36 struct imsgbuf	client_ibuf;
37 struct event	client_event;
38 struct event	client_stdin;
39 enum {
40 	CLIENT_EXIT_NONE,
41 	CLIENT_EXIT_DETACHED,
42 	CLIENT_EXIT_DETACHED_HUP,
43 	CLIENT_EXIT_LOST_TTY,
44 	CLIENT_EXIT_TERMINATED,
45 	CLIENT_EXIT_LOST_SERVER,
46 	CLIENT_EXIT_EXITED,
47 	CLIENT_EXIT_SERVER_EXITED,
48 } client_exitreason = CLIENT_EXIT_NONE;
49 int		client_exitval;
50 enum msgtype	client_exittype;
51 int		client_attached;
52 
53 int		client_get_lock(char *);
54 int		client_connect(char *, int);
55 void		client_send_identify(int);
56 void		client_send_environ(void);
57 void		client_write_server(enum msgtype, void *, size_t);
58 void		client_update_event(void);
59 void		client_signal(int, short, void *);
60 void		client_stdin_callback(int, short, void *);
61 void		client_write(int, const char *, size_t);
62 void		client_callback(int, short, void *);
63 int		client_dispatch_attached(void);
64 int		client_dispatch_wait(void *);
65 const char     *client_exit_message(void);
66 
67 /*
68  * Get server create lock. If already held then server start is happening in
69  * another client, so block until the lock is released and return -1 to
70  * retry. Ignore other errors - just continue and start the server without the
71  * lock.
72  */
73 int
74 client_get_lock(char *lockfile)
75 {
76 	int lockfd;
77 
78 	if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
79 		fatal("open failed");
80 
81 	if (flock(lockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
82 		while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
83 			/* nothing */;
84 		close(lockfd);
85 		return (-1);
86 	}
87 
88 	return (lockfd);
89 }
90 
91 /* Connect client to server. */
92 int
93 client_connect(char *path, int start_server)
94 {
95 	struct sockaddr_un	sa;
96 	size_t			size;
97 	int			fd, lockfd;
98 	char		       *lockfile;
99 
100 	memset(&sa, 0, sizeof sa);
101 	sa.sun_family = AF_UNIX;
102 	size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
103 	if (size >= sizeof sa.sun_path) {
104 		errno = ENAMETOOLONG;
105 		return (-1);
106 	}
107 
108 retry:
109 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
110 		fatal("socket failed");
111 
112 	if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
113 		if (errno != ECONNREFUSED && errno != ENOENT)
114 			goto failed;
115 		if (!start_server)
116 			goto failed;
117 		close(fd);
118 
119 		xasprintf(&lockfile, "%s.lock", path);
120 		if ((lockfd = client_get_lock(lockfile)) == -1)
121 			goto retry;
122 		if (unlink(path) != 0 && errno != ENOENT)
123 			return (-1);
124 		fd = server_start(lockfd, lockfile);
125 		free(lockfile);
126 		close(lockfd);
127 	}
128 
129 	setblocking(fd, 0);
130 	return (fd);
131 
132 failed:
133 	close(fd);
134 	return (-1);
135 }
136 
137 /* Get exit string from reason number. */
138 const char *
139 client_exit_message(void)
140 {
141 	switch (client_exitreason) {
142 	case CLIENT_EXIT_NONE:
143 		break;
144 	case CLIENT_EXIT_DETACHED:
145 		return ("detached");
146 	case CLIENT_EXIT_DETACHED_HUP:
147 		return ("detached and SIGHUP");
148 	case CLIENT_EXIT_LOST_TTY:
149 		return ("lost tty");
150 	case CLIENT_EXIT_TERMINATED:
151 		return ("terminated");
152 	case CLIENT_EXIT_LOST_SERVER:
153 		return ("lost server");
154 	case CLIENT_EXIT_EXITED:
155 		return ("exited");
156 	case CLIENT_EXIT_SERVER_EXITED:
157 		return ("server exited");
158 	}
159 	return ("unknown reason");
160 }
161 
162 /* Client main loop. */
163 int
164 client_main(int argc, char **argv, int flags)
165 {
166 	struct cmd		*cmd;
167 	struct cmd_list		*cmdlist;
168 	struct msg_command_data	 cmddata;
169 	int			 cmdflags, fd;
170 	pid_t			 ppid;
171 	enum msgtype		 msg;
172 	char			*cause;
173 	struct termios		 tio, saved_tio;
174 
175 	/* Set up the initial command. */
176 	cmdflags = 0;
177 	if (shell_cmd != NULL) {
178 		msg = MSG_SHELL;
179 		cmdflags = CMD_STARTSERVER;
180 	} else if (argc == 0) {
181 		msg = MSG_COMMAND;
182 		cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
183 	} else {
184 		msg = MSG_COMMAND;
185 
186 		/*
187 		 * It sucks parsing the command string twice (in client and
188 		 * later in server) but it is necessary to get the start server
189 		 * flag.
190 		 */
191 		cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
192 		if (cmdlist == NULL) {
193 			fprintf(stderr, "%s\n", cause);
194 			return (1);
195 		}
196 		cmdflags &= ~CMD_STARTSERVER;
197 		TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
198 			if (cmd->entry->flags & CMD_STARTSERVER)
199 				cmdflags |= CMD_STARTSERVER;
200 			if (cmd->entry->flags & CMD_SENDENVIRON)
201 				cmdflags |= CMD_SENDENVIRON;
202 			if (cmd->entry->flags & CMD_CANTNEST)
203 				cmdflags |= CMD_CANTNEST;
204 		}
205 		cmd_list_free(cmdlist);
206 	}
207 
208 	/*
209 	 * Check if this could be a nested session, if the command can't nest:
210 	 * if the socket path matches $TMUX, this is probably the same server.
211 	 */
212 	if (shell_cmd == NULL && environ_path != NULL &&
213 	    (cmdflags & CMD_CANTNEST) &&
214 	    strcmp(socket_path, environ_path) == 0) {
215 		fprintf(stderr, "sessions should be nested with care, "
216 		    "unset $TMUX to force\n");
217 		return (1);
218 	}
219 
220 	/* Initialise the client socket and start the server. */
221 	fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
222 	if (fd == -1) {
223 		fprintf(stderr, "failed to connect to server\n");
224 		return (1);
225 	}
226 
227 	/* Set process title, log and signals now this is the client. */
228 	setproctitle("client (%s)", socket_path);
229 	logfile("client");
230 
231 	/* Create imsg. */
232 	imsg_init(&client_ibuf, fd);
233 	event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
234 
235 	/* Create stdin handler. */
236 	setblocking(STDIN_FILENO, 0);
237 	event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
238 	    client_stdin_callback, NULL);
239 	if (flags & IDENTIFY_TERMIOS) {
240 		if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
241 			fprintf(stderr, "tcgetattr failed: %s\n",
242 			    strerror(errno));
243 			return (1);
244 		}
245 		cfmakeraw(&tio);
246 		tio.c_iflag = ICRNL|IXANY;
247 		tio.c_oflag = OPOST|ONLCR;
248 		tio.c_lflag = NOKERNINFO;
249 		tio.c_cflag = CREAD|CS8|HUPCL;
250 		tio.c_cc[VMIN] = 1;
251 		tio.c_cc[VTIME] = 0;
252 		cfsetispeed(&tio, cfgetispeed(&saved_tio));
253 		cfsetospeed(&tio, cfgetospeed(&saved_tio));
254 		tcsetattr(STDIN_FILENO, TCSANOW, &tio);
255 	}
256 
257 	/* Establish signal handlers. */
258 	set_signals(client_signal);
259 
260 	/* Send initial environment. */
261 	if (cmdflags & CMD_SENDENVIRON)
262 		client_send_environ();
263 	client_send_identify(flags);
264 
265 	/* Send first command. */
266 	if (msg == MSG_COMMAND) {
267 		/* Fill in command line arguments. */
268 		cmddata.pid = environ_pid;
269 		cmddata.session_id = environ_session_id;
270 
271 		/* Prepare command for server. */
272 		cmddata.argc = argc;
273 		if (cmd_pack_argv(
274 		    argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
275 			fprintf(stderr, "command too long\n");
276 			return (1);
277 		}
278 
279 		client_write_server(msg, &cmddata, sizeof cmddata);
280 	} else if (msg == MSG_SHELL)
281 		client_write_server(msg, NULL, 0);
282 
283 	/* Set the event and dispatch. */
284 	client_update_event();
285 	event_dispatch();
286 
287 	/* Print the exit message, if any, and exit. */
288 	if (client_attached) {
289 		if (client_exitreason != CLIENT_EXIT_NONE && !login_shell)
290 			printf("[%s]\n", client_exit_message());
291 
292 		ppid = getppid();
293 		if (client_exittype == MSG_DETACHKILL && ppid > 1)
294 			kill(ppid, SIGHUP);
295 	} else if (flags & IDENTIFY_TERMIOS) {
296 		if (flags & IDENTIFY_CONTROL) {
297 			if (client_exitreason != CLIENT_EXIT_NONE)
298 			    printf("%%exit %s\n", client_exit_message());
299 			else
300 			    printf("%%exit\n");
301 			printf("\033\\");
302 		}
303 		tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
304 	}
305 	setblocking(STDIN_FILENO, 1);
306 	return (client_exitval);
307 }
308 
309 /* Send identify message to server with the file descriptors. */
310 void
311 client_send_identify(int flags)
312 {
313 	struct msg_identify_data	data;
314 	char			       *term;
315 	int				fd;
316 
317 	data.flags = flags;
318 
319 	if (getcwd(data.cwd, sizeof data.cwd) == NULL)
320 		*data.cwd = '\0';
321 
322 	term = getenv("TERM");
323 	if (term == NULL ||
324 	    strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
325 		*data.term = '\0';
326 
327 	if ((fd = dup(STDIN_FILENO)) == -1)
328 		fatal("dup failed");
329 	imsg_compose(&client_ibuf,
330 	    MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
331 	client_update_event();
332 }
333 
334 /* Forward entire environment to server. */
335 void
336 client_send_environ(void)
337 {
338 	struct msg_environ_data	data;
339 	char		      **var;
340 
341 	for (var = environ; *var != NULL; var++) {
342 		if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
343 			continue;
344 		client_write_server(MSG_ENVIRON, &data, sizeof data);
345 	}
346 }
347 
348 /* Write a message to the server without a file descriptor. */
349 void
350 client_write_server(enum msgtype type, void *buf, size_t len)
351 {
352 	imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
353 	client_update_event();
354 }
355 
356 /* Update client event based on whether it needs to read or read and write. */
357 void
358 client_update_event(void)
359 {
360 	short	events;
361 
362 	event_del(&client_event);
363 	events = EV_READ;
364 	if (client_ibuf.w.queued > 0)
365 		events |= EV_WRITE;
366 	event_set(
367 	    &client_event, client_ibuf.fd, events, client_callback, shell_cmd);
368 	event_add(&client_event, NULL);
369 }
370 
371 /* Callback to handle signals in the client. */
372 void
373 client_signal(int sig, unused short events, unused void *data)
374 {
375 	struct sigaction sigact;
376 	int		 status;
377 
378 	if (!client_attached) {
379 		switch (sig) {
380 		case SIGCHLD:
381 			waitpid(WAIT_ANY, &status, WNOHANG);
382 			break;
383 		case SIGTERM:
384 			event_loopexit(NULL);
385 			break;
386 		}
387 	} else {
388 		switch (sig) {
389 		case SIGHUP:
390 			client_exitreason = CLIENT_EXIT_LOST_TTY;
391 			client_exitval = 1;
392 			client_write_server(MSG_EXITING, NULL, 0);
393 			break;
394 		case SIGTERM:
395 			client_exitreason = CLIENT_EXIT_TERMINATED;
396 			client_exitval = 1;
397 			client_write_server(MSG_EXITING, NULL, 0);
398 			break;
399 		case SIGWINCH:
400 			client_write_server(MSG_RESIZE, NULL, 0);
401 			break;
402 		case SIGCONT:
403 			memset(&sigact, 0, sizeof sigact);
404 			sigemptyset(&sigact.sa_mask);
405 			sigact.sa_flags = SA_RESTART;
406 			sigact.sa_handler = SIG_IGN;
407 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
408 				fatal("sigaction failed");
409 			client_write_server(MSG_WAKEUP, NULL, 0);
410 			break;
411 		}
412 	}
413 
414 	client_update_event();
415 }
416 
417 /* Callback for client imsg read events. */
418 void
419 client_callback(unused int fd, short events, void *data)
420 {
421 	ssize_t	n;
422 	int	retval;
423 
424 	if (events & EV_READ) {
425 		if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
426 			goto lost_server;
427 		if (client_attached)
428 			retval = client_dispatch_attached();
429 		else
430 			retval = client_dispatch_wait(data);
431 		if (retval != 0) {
432 			event_loopexit(NULL);
433 			return;
434 		}
435 	}
436 
437 	if (events & EV_WRITE) {
438 		if (msgbuf_write(&client_ibuf.w) < 0)
439 			goto lost_server;
440 	}
441 
442 	client_update_event();
443 	return;
444 
445 lost_server:
446 	client_exitreason = CLIENT_EXIT_LOST_SERVER;
447 	client_exitval = 1;
448 	event_loopexit(NULL);
449 }
450 
451 /* Callback for client stdin read events. */
452 void
453 client_stdin_callback(unused int fd, unused short events, unused void *data1)
454 {
455 	struct msg_stdin_data	data;
456 
457 	data.size = read(STDIN_FILENO, data.data, sizeof data.data);
458 	if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
459 		return;
460 
461 	client_write_server(MSG_STDIN, &data, sizeof data);
462 	if (data.size <= 0)
463 		event_del(&client_stdin);
464 	client_update_event();
465 }
466 
467 /* Force write to file descriptor. */
468 void
469 client_write(int fd, const char *data, size_t size)
470 {
471 	ssize_t	used;
472 
473 	while (size != 0) {
474 		used = write(fd, data, size);
475 		if (used == -1) {
476 			if (errno == EINTR || errno == EAGAIN)
477 				continue;
478 			break;
479 		}
480 		data += used;
481 		size -= used;
482 	}
483 }
484 
485 /* Dispatch imsgs when in wait state (before MSG_READY). */
486 int
487 client_dispatch_wait(void *data)
488 {
489 	struct imsg		imsg;
490 	ssize_t			n, datalen;
491 	struct msg_shell_data	shelldata;
492 	struct msg_exit_data	exitdata;
493 	struct msg_stdout_data	stdoutdata;
494 	struct msg_stderr_data	stderrdata;
495 	const char             *shellcmd = data;
496 
497 	for (;;) {
498 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
499 			fatalx("imsg_get failed");
500 		if (n == 0)
501 			return (0);
502 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
503 
504 		log_debug("got %d from server", imsg.hdr.type);
505 		switch (imsg.hdr.type) {
506 		case MSG_EXIT:
507 		case MSG_SHUTDOWN:
508 			if (datalen != sizeof exitdata) {
509 				if (datalen != 0)
510 					fatalx("bad MSG_EXIT size");
511 			} else {
512 				memcpy(&exitdata, imsg.data, sizeof exitdata);
513 				client_exitval = exitdata.retcode;
514 			}
515 			imsg_free(&imsg);
516 			return (-1);
517 		case MSG_READY:
518 			if (datalen != 0)
519 				fatalx("bad MSG_READY size");
520 
521 			event_del(&client_stdin);
522 			client_attached = 1;
523 			client_write_server(MSG_RESIZE, NULL, 0);
524 			break;
525 		case MSG_STDIN:
526 			if (datalen != 0)
527 				fatalx("bad MSG_STDIN size");
528 
529 			event_add(&client_stdin, NULL);
530 			break;
531 		case MSG_STDOUT:
532 			if (datalen != sizeof stdoutdata)
533 				fatalx("bad MSG_STDOUT");
534 			memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
535 
536 			client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size);
537 			break;
538 		case MSG_STDERR:
539 			if (datalen != sizeof stderrdata)
540 				fatalx("bad MSG_STDERR");
541 			memcpy(&stderrdata, imsg.data, sizeof stderrdata);
542 
543 			client_write(STDERR_FILENO, stderrdata.data, stderrdata.size);
544 			break;
545 		case MSG_VERSION:
546 			if (datalen != 0)
547 				fatalx("bad MSG_VERSION size");
548 
549 			fprintf(stderr, "protocol version mismatch "
550 			    "(client %u, server %u)\n", PROTOCOL_VERSION,
551 			    imsg.hdr.peerid);
552 			client_exitval = 1;
553 
554 			imsg_free(&imsg);
555 			return (-1);
556 		case MSG_SHELL:
557 			if (datalen != sizeof shelldata)
558 				fatalx("bad MSG_SHELL size");
559 			memcpy(&shelldata, imsg.data, sizeof shelldata);
560 			shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
561 
562 			clear_signals(0);
563 
564 			shell_exec(shelldata.shell, shellcmd);
565 			/* NOTREACHED */
566 		case MSG_DETACH:
567 			client_write_server(MSG_EXITING, NULL, 0);
568 			break;
569 		case MSG_EXITED:
570 			imsg_free(&imsg);
571 			return (-1);
572 		default:
573 			fatalx("unexpected message");
574 		}
575 
576 		imsg_free(&imsg);
577 	}
578 }
579 
580 /* Dispatch imsgs in attached state (after MSG_READY). */
581 int
582 client_dispatch_attached(void)
583 {
584 	struct imsg		imsg;
585 	struct msg_lock_data	lockdata;
586 	struct sigaction	sigact;
587 	ssize_t			n, datalen;
588 
589 	for (;;) {
590 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
591 			fatalx("imsg_get failed");
592 		if (n == 0)
593 			return (0);
594 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
595 
596 		log_debug("got %d from server", imsg.hdr.type);
597 		switch (imsg.hdr.type) {
598 		case MSG_DETACHKILL:
599 		case MSG_DETACH:
600 			if (datalen != 0)
601 				fatalx("bad MSG_DETACH size");
602 
603 			client_exittype = imsg.hdr.type;
604 			if (imsg.hdr.type == MSG_DETACHKILL)
605 				client_exitreason = CLIENT_EXIT_DETACHED_HUP;
606 			else
607 				client_exitreason = CLIENT_EXIT_DETACHED;
608 			client_write_server(MSG_EXITING, NULL, 0);
609 			break;
610 		case MSG_EXIT:
611 			if (datalen != 0 &&
612 			    datalen != sizeof (struct msg_exit_data))
613 				fatalx("bad MSG_EXIT size");
614 
615 			client_write_server(MSG_EXITING, NULL, 0);
616 			client_exitreason = CLIENT_EXIT_EXITED;
617 			break;
618 		case MSG_EXITED:
619 			if (datalen != 0)
620 				fatalx("bad MSG_EXITED size");
621 
622 			imsg_free(&imsg);
623 			return (-1);
624 		case MSG_SHUTDOWN:
625 			if (datalen != 0)
626 				fatalx("bad MSG_SHUTDOWN size");
627 
628 			client_write_server(MSG_EXITING, NULL, 0);
629 			client_exitreason = CLIENT_EXIT_SERVER_EXITED;
630 			client_exitval = 1;
631 			break;
632 		case MSG_SUSPEND:
633 			if (datalen != 0)
634 				fatalx("bad MSG_SUSPEND size");
635 
636 			memset(&sigact, 0, sizeof sigact);
637 			sigemptyset(&sigact.sa_mask);
638 			sigact.sa_flags = SA_RESTART;
639 			sigact.sa_handler = SIG_DFL;
640 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
641 				fatal("sigaction failed");
642 			kill(getpid(), SIGTSTP);
643 			break;
644 		case MSG_LOCK:
645 			if (datalen != sizeof lockdata)
646 				fatalx("bad MSG_LOCK size");
647 			memcpy(&lockdata, imsg.data, sizeof lockdata);
648 
649 			lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
650 			system(lockdata.cmd);
651 			client_write_server(MSG_UNLOCK, NULL, 0);
652 			break;
653 		default:
654 			fatalx("unexpected message");
655 		}
656 
657 		imsg_free(&imsg);
658 	}
659 }
660