xref: /openbsd-src/usr.bin/tmux/client.c (revision ac9b4aacc1da35008afea06a5d23c2f2dea9b93e)
1 /* $OpenBSD: client.c,v 1.60 2012/09/03 08:48: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 		if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
192 			fprintf(stderr, "%s\n", cause);
193 			return (1);
194 		}
195 		cmdflags &= ~CMD_STARTSERVER;
196 		TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
197 			if (cmd->entry->flags & CMD_STARTSERVER)
198 				cmdflags |= CMD_STARTSERVER;
199 			if (cmd->entry->flags & CMD_SENDENVIRON)
200 				cmdflags |= CMD_SENDENVIRON;
201 			if (cmd->entry->flags & CMD_CANTNEST)
202 				cmdflags |= CMD_CANTNEST;
203 		}
204 		cmd_list_free(cmdlist);
205 	}
206 
207 	/*
208 	 * Check if this could be a nested session, if the command can't nest:
209 	 * if the socket path matches $TMUX, this is probably the same server.
210 	 */
211 	if (shell_cmd == NULL && environ_path != NULL &&
212 	    (cmdflags & CMD_CANTNEST) &&
213 	    strcmp(socket_path, environ_path) == 0) {
214 		fprintf(stderr, "sessions should be nested with care, "
215 		    "unset $TMUX to force\n");
216 		return (1);
217 	}
218 
219 	/* Initialise the client socket and start the server. */
220 	fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
221 	if (fd == -1) {
222 		fprintf(stderr, "failed to connect to server\n");
223 		return (1);
224 	}
225 
226 	/* Set process title, log and signals now this is the client. */
227 	setproctitle("client (%s)", socket_path);
228 	logfile("client");
229 
230 	/* Create imsg. */
231 	imsg_init(&client_ibuf, fd);
232 	event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
233 
234 	/* Create stdin handler. */
235 	setblocking(STDIN_FILENO, 0);
236 	event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
237 	    client_stdin_callback, NULL);
238 	if (flags & IDENTIFY_TERMIOS) {
239 		if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
240 			fprintf(stderr, "tcgetattr failed: %s\n",
241 			    strerror(errno));
242 			return (1);
243 		}
244 		cfmakeraw(&tio);
245 		tio.c_iflag = ICRNL|IXANY;
246 		tio.c_oflag = OPOST|ONLCR;
247 		tio.c_lflag = NOKERNINFO;
248 		tio.c_cflag = CREAD|CS8|HUPCL;
249 		tio.c_cc[VMIN] = 1;
250 		tio.c_cc[VTIME] = 0;
251 		cfsetispeed(&tio, cfgetispeed(&saved_tio));
252 		cfsetospeed(&tio, cfgetospeed(&saved_tio));
253 		tcsetattr(STDIN_FILENO, TCSANOW, &tio);
254 	}
255 
256 	/* Establish signal handlers. */
257 	set_signals(client_signal);
258 
259 	/* Send initial environment. */
260 	if (cmdflags & CMD_SENDENVIRON)
261 		client_send_environ();
262 	client_send_identify(flags);
263 
264 	/* Send first command. */
265 	if (msg == MSG_COMMAND) {
266 		/* Fill in command line arguments. */
267 		cmddata.pid = environ_pid;
268 		cmddata.idx = environ_idx;
269 
270 		/* Prepare command for server. */
271 		cmddata.argc = argc;
272 		if (cmd_pack_argv(
273 		    argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
274 			fprintf(stderr, "command too long\n");
275 			return (1);
276 		}
277 
278 		client_write_server(msg, &cmddata, sizeof cmddata);
279 	} else if (msg == MSG_SHELL)
280 		client_write_server(msg, NULL, 0);
281 
282 	/* Set the event and dispatch. */
283 	client_update_event();
284 	event_dispatch();
285 
286 	/* Print the exit message, if any, and exit. */
287 	if (client_attached) {
288 		if (client_exitreason != CLIENT_EXIT_NONE && !login_shell)
289 			printf("[%s]\n", client_exit_message());
290 
291 		ppid = getppid();
292 		if (client_exittype == MSG_DETACHKILL && ppid > 1)
293 			kill(ppid, SIGHUP);
294 	} else if (flags & IDENTIFY_TERMIOS)
295 		tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
296 	setblocking(STDIN_FILENO, 1);
297 	return (client_exitval);
298 }
299 
300 /* Send identify message to server with the file descriptors. */
301 void
302 client_send_identify(int flags)
303 {
304 	struct msg_identify_data	data;
305 	char			       *term;
306 	int				fd;
307 
308 	data.flags = flags;
309 
310 	if (getcwd(data.cwd, sizeof data.cwd) == NULL)
311 		*data.cwd = '\0';
312 
313 	term = getenv("TERM");
314 	if (term == NULL ||
315 	    strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
316 		*data.term = '\0';
317 
318 	if ((fd = dup(STDIN_FILENO)) == -1)
319 		fatal("dup failed");
320 	imsg_compose(&client_ibuf,
321 	    MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
322 	client_update_event();
323 }
324 
325 /* Forward entire environment to server. */
326 void
327 client_send_environ(void)
328 {
329 	struct msg_environ_data	data;
330 	char		      **var;
331 
332 	for (var = environ; *var != NULL; var++) {
333 		if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
334 			continue;
335 		client_write_server(MSG_ENVIRON, &data, sizeof data);
336 	}
337 }
338 
339 /* Write a message to the server without a file descriptor. */
340 void
341 client_write_server(enum msgtype type, void *buf, size_t len)
342 {
343 	imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
344 	client_update_event();
345 }
346 
347 /* Update client event based on whether it needs to read or read and write. */
348 void
349 client_update_event(void)
350 {
351 	short	events;
352 
353 	event_del(&client_event);
354 	events = EV_READ;
355 	if (client_ibuf.w.queued > 0)
356 		events |= EV_WRITE;
357 	event_set(
358 	    &client_event, client_ibuf.fd, events, client_callback, shell_cmd);
359 	event_add(&client_event, NULL);
360 }
361 
362 /* Callback to handle signals in the client. */
363 /* ARGSUSED */
364 void
365 client_signal(int sig, unused short events, unused void *data)
366 {
367 	struct sigaction sigact;
368 	int		 status;
369 
370 	if (!client_attached) {
371 		switch (sig) {
372 		case SIGCHLD:
373 			waitpid(WAIT_ANY, &status, WNOHANG);
374 			break;
375 		case SIGTERM:
376 			event_loopexit(NULL);
377 			break;
378 		}
379 	} else {
380 		switch (sig) {
381 		case SIGHUP:
382 			client_exitreason = CLIENT_EXIT_LOST_TTY;
383 			client_exitval = 1;
384 			client_write_server(MSG_EXITING, NULL, 0);
385 			break;
386 		case SIGTERM:
387 			client_exitreason = CLIENT_EXIT_TERMINATED;
388 			client_exitval = 1;
389 			client_write_server(MSG_EXITING, NULL, 0);
390 			break;
391 		case SIGWINCH:
392 			client_write_server(MSG_RESIZE, NULL, 0);
393 			break;
394 		case SIGCONT:
395 			memset(&sigact, 0, sizeof sigact);
396 			sigemptyset(&sigact.sa_mask);
397 			sigact.sa_flags = SA_RESTART;
398 			sigact.sa_handler = SIG_IGN;
399 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
400 				fatal("sigaction failed");
401 			client_write_server(MSG_WAKEUP, NULL, 0);
402 			break;
403 		}
404 	}
405 
406 	client_update_event();
407 }
408 
409 /* Callback for client imsg read events. */
410 /* ARGSUSED */
411 void
412 client_callback(unused int fd, short events, void *data)
413 {
414 	ssize_t	n;
415 	int	retval;
416 
417 	if (events & EV_READ) {
418 		if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
419 			goto lost_server;
420 		if (client_attached)
421 			retval = client_dispatch_attached();
422 		else
423 			retval = client_dispatch_wait(data);
424 		if (retval != 0) {
425 			event_loopexit(NULL);
426 			return;
427 		}
428 	}
429 
430 	if (events & EV_WRITE) {
431 		if (msgbuf_write(&client_ibuf.w) < 0)
432 			goto lost_server;
433 	}
434 
435 	client_update_event();
436 	return;
437 
438 lost_server:
439 	client_exitreason = CLIENT_EXIT_LOST_SERVER;
440 	client_exitval = 1;
441 	event_loopexit(NULL);
442 }
443 
444 /* Callback for client stdin read events. */
445 /* ARGSUSED */
446 void
447 client_stdin_callback(unused int fd, unused short events, unused void *data1)
448 {
449 	struct msg_stdin_data	data;
450 
451 	data.size = read(STDIN_FILENO, data.data, sizeof data.data);
452 	if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
453 		return;
454 
455 	client_write_server(MSG_STDIN, &data, sizeof data);
456 	if (data.size <= 0)
457 		event_del(&client_stdin);
458 	client_update_event();
459 }
460 
461 /* Force write to file descriptor. */
462 void
463 client_write(int fd, const char *data, size_t size)
464 {
465 	ssize_t	used;
466 
467 	while (size != 0) {
468 		used = write(fd, data, size);
469 		if (used == -1) {
470 			if (errno == EINTR || errno == EAGAIN)
471 				continue;
472 			break;
473 		}
474 		data += used;
475 		size -= used;
476 	}
477 }
478 
479 /* Dispatch imsgs when in wait state (before MSG_READY). */
480 int
481 client_dispatch_wait(void *data)
482 {
483 	struct imsg		imsg;
484 	ssize_t			n, datalen;
485 	struct msg_shell_data	shelldata;
486 	struct msg_exit_data	exitdata;
487 	struct msg_stdout_data	stdoutdata;
488 	struct msg_stderr_data	stderrdata;
489 	const char             *shellcmd = data;
490 
491 	for (;;) {
492 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
493 			fatalx("imsg_get failed");
494 		if (n == 0)
495 			return (0);
496 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
497 
498 		log_debug("got %d from server", imsg.hdr.type);
499 		switch (imsg.hdr.type) {
500 		case MSG_EXIT:
501 		case MSG_SHUTDOWN:
502 			if (datalen != sizeof exitdata) {
503 				if (datalen != 0)
504 					fatalx("bad MSG_EXIT size");
505 			} else {
506 				memcpy(&exitdata, imsg.data, sizeof exitdata);
507 				client_exitval = exitdata.retcode;
508 			}
509 			imsg_free(&imsg);
510 			return (-1);
511 		case MSG_READY:
512 			if (datalen != 0)
513 				fatalx("bad MSG_READY size");
514 
515 			event_del(&client_stdin);
516 			client_attached = 1;
517 			break;
518 		case MSG_STDIN:
519 			if (datalen != 0)
520 				fatalx("bad MSG_STDIN size");
521 
522 			event_add(&client_stdin, NULL);
523 			break;
524 		case MSG_STDOUT:
525 			if (datalen != sizeof stdoutdata)
526 				fatalx("bad MSG_STDOUT");
527 			memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
528 
529 			client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size);
530 			break;
531 		case MSG_STDERR:
532 			if (datalen != sizeof stderrdata)
533 				fatalx("bad MSG_STDERR");
534 			memcpy(&stderrdata, imsg.data, sizeof stderrdata);
535 
536 			client_write(STDERR_FILENO, stderrdata.data, stderrdata.size);
537 			break;
538 		case MSG_VERSION:
539 			if (datalen != 0)
540 				fatalx("bad MSG_VERSION size");
541 
542 			fprintf(stderr, "protocol version mismatch "
543 			    "(client %u, server %u)\n", PROTOCOL_VERSION,
544 			    imsg.hdr.peerid);
545 			client_exitval = 1;
546 
547 			imsg_free(&imsg);
548 			return (-1);
549 		case MSG_SHELL:
550 			if (datalen != sizeof shelldata)
551 				fatalx("bad MSG_SHELL size");
552 			memcpy(&shelldata, imsg.data, sizeof shelldata);
553 			shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
554 
555 			clear_signals(0);
556 
557 			shell_exec(shelldata.shell, shellcmd);
558 			/* NOTREACHED */
559 		case MSG_DETACH:
560 			client_write_server(MSG_EXITING, NULL, 0);
561 			break;
562 		case MSG_EXITED:
563 			imsg_free(&imsg);
564 			return (-1);
565 		default:
566 			fatalx("unexpected message");
567 		}
568 
569 		imsg_free(&imsg);
570 	}
571 }
572 
573 /* Dispatch imsgs in attached state (after MSG_READY). */
574 /* ARGSUSED */
575 int
576 client_dispatch_attached(void)
577 {
578 	struct imsg		imsg;
579 	struct msg_lock_data	lockdata;
580 	struct sigaction	sigact;
581 	ssize_t			n, datalen;
582 
583 	for (;;) {
584 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
585 			fatalx("imsg_get failed");
586 		if (n == 0)
587 			return (0);
588 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
589 
590 		log_debug("got %d from server", imsg.hdr.type);
591 		switch (imsg.hdr.type) {
592 		case MSG_DETACHKILL:
593 		case MSG_DETACH:
594 			if (datalen != 0)
595 				fatalx("bad MSG_DETACH size");
596 
597 			client_exittype = imsg.hdr.type;
598 			if (imsg.hdr.type == MSG_DETACHKILL)
599 				client_exitreason = CLIENT_EXIT_DETACHED_HUP;
600 			else
601 				client_exitreason = CLIENT_EXIT_DETACHED;
602 			client_write_server(MSG_EXITING, NULL, 0);
603 			break;
604 		case MSG_EXIT:
605 			if (datalen != 0 &&
606 			    datalen != sizeof (struct msg_exit_data))
607 				fatalx("bad MSG_EXIT size");
608 
609 			client_write_server(MSG_EXITING, NULL, 0);
610 			client_exitreason = CLIENT_EXIT_EXITED;
611 			break;
612 		case MSG_EXITED:
613 			if (datalen != 0)
614 				fatalx("bad MSG_EXITED size");
615 
616 			imsg_free(&imsg);
617 			return (-1);
618 		case MSG_SHUTDOWN:
619 			if (datalen != 0)
620 				fatalx("bad MSG_SHUTDOWN size");
621 
622 			client_write_server(MSG_EXITING, NULL, 0);
623 			client_exitreason = CLIENT_EXIT_SERVER_EXITED;
624 			client_exitval = 1;
625 			break;
626 		case MSG_SUSPEND:
627 			if (datalen != 0)
628 				fatalx("bad MSG_SUSPEND size");
629 
630 			memset(&sigact, 0, sizeof sigact);
631 			sigemptyset(&sigact.sa_mask);
632 			sigact.sa_flags = SA_RESTART;
633 			sigact.sa_handler = SIG_DFL;
634 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
635 				fatal("sigaction failed");
636 			kill(getpid(), SIGTSTP);
637 			break;
638 		case MSG_LOCK:
639 			if (datalen != sizeof lockdata)
640 				fatalx("bad MSG_LOCK size");
641 			memcpy(&lockdata, imsg.data, sizeof lockdata);
642 
643 			lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
644 			system(lockdata.cmd);
645 			client_write_server(MSG_UNLOCK, NULL, 0);
646 			break;
647 		default:
648 			fatalx("unexpected message");
649 		}
650 
651 		imsg_free(&imsg);
652 	}
653 }
654