xref: /openbsd-src/usr.bin/tmux/client.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /* $OpenBSD: client.c,v 1.58 2012/07/10 11:53:01 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 			log_warnx("%s", 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_add (&client_stdin, NULL);
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 		tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
297 	setblocking(STDIN_FILENO, 1);
298 	return (client_exitval);
299 }
300 
301 /* Send identify message to server with the file descriptors. */
302 void
303 client_send_identify(int flags)
304 {
305 	struct msg_identify_data	data;
306 	char			       *term;
307 	int				fd;
308 
309 	data.flags = flags;
310 
311 	if (getcwd(data.cwd, sizeof data.cwd) == NULL)
312 		*data.cwd = '\0';
313 
314 	term = getenv("TERM");
315 	if (term == NULL ||
316 	    strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
317 		*data.term = '\0';
318 
319 	if ((fd = dup(STDIN_FILENO)) == -1)
320 		fatal("dup failed");
321 	imsg_compose(&client_ibuf,
322 	    MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
323 	client_update_event();
324 }
325 
326 /* Forward entire environment to server. */
327 void
328 client_send_environ(void)
329 {
330 	struct msg_environ_data	data;
331 	char		      **var;
332 
333 	for (var = environ; *var != NULL; var++) {
334 		if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
335 			continue;
336 		client_write_server(MSG_ENVIRON, &data, sizeof data);
337 	}
338 }
339 
340 /* Write a message to the server without a file descriptor. */
341 void
342 client_write_server(enum msgtype type, void *buf, size_t len)
343 {
344 	imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
345 	client_update_event();
346 }
347 
348 /* Update client event based on whether it needs to read or read and write. */
349 void
350 client_update_event(void)
351 {
352 	short	events;
353 
354 	event_del(&client_event);
355 	events = EV_READ;
356 	if (client_ibuf.w.queued > 0)
357 		events |= EV_WRITE;
358 	event_set(
359 	    &client_event, client_ibuf.fd, events, client_callback, shell_cmd);
360 	event_add(&client_event, NULL);
361 }
362 
363 /* Callback to handle signals in the client. */
364 /* ARGSUSED */
365 void
366 client_signal(int sig, unused short events, unused void *data)
367 {
368 	struct sigaction sigact;
369 	int		 status;
370 
371 	if (!client_attached) {
372 		switch (sig) {
373 		case SIGCHLD:
374 			waitpid(WAIT_ANY, &status, WNOHANG);
375 			break;
376 		case SIGTERM:
377 			event_loopexit(NULL);
378 			break;
379 		}
380 	} else {
381 		switch (sig) {
382 		case SIGHUP:
383 			client_exitreason = CLIENT_EXIT_LOST_TTY;
384 			client_exitval = 1;
385 			client_write_server(MSG_EXITING, NULL, 0);
386 			break;
387 		case SIGTERM:
388 			client_exitreason = CLIENT_EXIT_TERMINATED;
389 			client_exitval = 1;
390 			client_write_server(MSG_EXITING, NULL, 0);
391 			break;
392 		case SIGWINCH:
393 			client_write_server(MSG_RESIZE, NULL, 0);
394 			break;
395 		case SIGCONT:
396 			memset(&sigact, 0, sizeof sigact);
397 			sigemptyset(&sigact.sa_mask);
398 			sigact.sa_flags = SA_RESTART;
399 			sigact.sa_handler = SIG_IGN;
400 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
401 				fatal("sigaction failed");
402 			client_write_server(MSG_WAKEUP, NULL, 0);
403 			break;
404 		}
405 	}
406 
407 	client_update_event();
408 }
409 
410 /* Callback for client imsg read events. */
411 /* ARGSUSED */
412 void
413 client_callback(unused int fd, short events, void *data)
414 {
415 	ssize_t	n;
416 	int	retval;
417 
418 	if (events & EV_READ) {
419 		if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
420 			goto lost_server;
421 		if (client_attached)
422 			retval = client_dispatch_attached();
423 		else
424 			retval = client_dispatch_wait(data);
425 		if (retval != 0) {
426 			event_loopexit(NULL);
427 			return;
428 		}
429 	}
430 
431 	if (events & EV_WRITE) {
432 		if (msgbuf_write(&client_ibuf.w) < 0)
433 			goto lost_server;
434 	}
435 
436 	client_update_event();
437 	return;
438 
439 lost_server:
440 	client_exitreason = CLIENT_EXIT_LOST_SERVER;
441 	client_exitval = 1;
442 	event_loopexit(NULL);
443 }
444 
445 /* Callback for client stdin read events. */
446 /* ARGSUSED */
447 void
448 client_stdin_callback(unused int fd, unused short events, unused void *data1)
449 {
450 	struct msg_stdin_data	data;
451 
452 	data.size = read(STDIN_FILENO, data.data, sizeof data.data);
453 	if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
454 		return;
455 
456 	client_write_server(MSG_STDIN, &data, sizeof data);
457 	if (data.size <= 0)
458 		event_del(&client_stdin);
459 	client_update_event();
460 }
461 
462 /* Force write to file descriptor. */
463 void
464 client_write(int fd, const char *data, size_t size)
465 {
466 	ssize_t	used;
467 
468 	while (size != 0) {
469 		used = write(fd, data, size);
470 		if (used == -1) {
471 			if (errno == EINTR || errno == EAGAIN)
472 				continue;
473 			break;
474 		}
475 		data += used;
476 		size -= used;
477 	}
478 }
479 
480 /* Dispatch imsgs when in wait state (before MSG_READY). */
481 int
482 client_dispatch_wait(void *data)
483 {
484 	struct imsg		imsg;
485 	ssize_t			n, datalen;
486 	struct msg_shell_data	shelldata;
487 	struct msg_exit_data	exitdata;
488 	struct msg_stdout_data	stdoutdata;
489 	struct msg_stderr_data	stderrdata;
490 	const char             *shellcmd = data;
491 
492 	for (;;) {
493 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
494 			fatalx("imsg_get failed");
495 		if (n == 0)
496 			return (0);
497 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
498 
499 		log_debug("got %d from server", imsg.hdr.type);
500 		switch (imsg.hdr.type) {
501 		case MSG_EXIT:
502 		case MSG_SHUTDOWN:
503 			if (datalen != sizeof exitdata) {
504 				if (datalen != 0)
505 					fatalx("bad MSG_EXIT size");
506 			} else {
507 				memcpy(&exitdata, imsg.data, sizeof exitdata);
508 				client_exitval = exitdata.retcode;
509 			}
510 			imsg_free(&imsg);
511 			return (-1);
512 		case MSG_READY:
513 			if (datalen != 0)
514 				fatalx("bad MSG_READY size");
515 
516 			event_del(&client_stdin);
517 			client_attached = 1;
518 			break;
519 		case MSG_STDOUT:
520 			if (datalen != sizeof stdoutdata)
521 				fatalx("bad MSG_STDOUT");
522 			memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
523 
524 			client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size);
525 			break;
526 		case MSG_STDERR:
527 			if (datalen != sizeof stderrdata)
528 				fatalx("bad MSG_STDERR");
529 			memcpy(&stderrdata, imsg.data, sizeof stderrdata);
530 
531 			client_write(STDERR_FILENO, stderrdata.data, stderrdata.size);
532 			break;
533 		case MSG_VERSION:
534 			if (datalen != 0)
535 				fatalx("bad MSG_VERSION size");
536 
537 			fprintf(stderr, "protocol version mismatch "
538 			    "(client %u, server %u)\n", PROTOCOL_VERSION,
539 			    imsg.hdr.peerid);
540 			client_exitval = 1;
541 
542 			imsg_free(&imsg);
543 			return (-1);
544 		case MSG_SHELL:
545 			if (datalen != sizeof shelldata)
546 				fatalx("bad MSG_SHELL size");
547 			memcpy(&shelldata, imsg.data, sizeof shelldata);
548 			shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
549 
550 			clear_signals(0);
551 
552 			shell_exec(shelldata.shell, shellcmd);
553 			/* NOTREACHED */
554 		case MSG_DETACH:
555 			client_write_server(MSG_EXITING, NULL, 0);
556 			break;
557 		case MSG_EXITED:
558 			imsg_free(&imsg);
559 			return (-1);
560 		default:
561 			fatalx("unexpected message");
562 		}
563 
564 		imsg_free(&imsg);
565 	}
566 }
567 
568 /* Dispatch imsgs in attached state (after MSG_READY). */
569 /* ARGSUSED */
570 int
571 client_dispatch_attached(void)
572 {
573 	struct imsg		imsg;
574 	struct msg_lock_data	lockdata;
575 	struct sigaction	sigact;
576 	ssize_t			n, datalen;
577 
578 	for (;;) {
579 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
580 			fatalx("imsg_get failed");
581 		if (n == 0)
582 			return (0);
583 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
584 
585 		log_debug("got %d from server", imsg.hdr.type);
586 		switch (imsg.hdr.type) {
587 		case MSG_DETACHKILL:
588 		case MSG_DETACH:
589 			if (datalen != 0)
590 				fatalx("bad MSG_DETACH size");
591 
592 			client_exittype = imsg.hdr.type;
593 			if (imsg.hdr.type == MSG_DETACHKILL)
594 				client_exitreason = CLIENT_EXIT_DETACHED_HUP;
595 			else
596 				client_exitreason = CLIENT_EXIT_DETACHED;
597 			client_write_server(MSG_EXITING, NULL, 0);
598 			break;
599 		case MSG_EXIT:
600 			if (datalen != 0 &&
601 			    datalen != sizeof (struct msg_exit_data))
602 				fatalx("bad MSG_EXIT size");
603 
604 			client_write_server(MSG_EXITING, NULL, 0);
605 			client_exitreason = CLIENT_EXIT_EXITED;
606 			break;
607 		case MSG_EXITED:
608 			if (datalen != 0)
609 				fatalx("bad MSG_EXITED size");
610 
611 			imsg_free(&imsg);
612 			return (-1);
613 		case MSG_SHUTDOWN:
614 			if (datalen != 0)
615 				fatalx("bad MSG_SHUTDOWN size");
616 
617 			client_write_server(MSG_EXITING, NULL, 0);
618 			client_exitreason = CLIENT_EXIT_SERVER_EXITED;
619 			client_exitval = 1;
620 			break;
621 		case MSG_SUSPEND:
622 			if (datalen != 0)
623 				fatalx("bad MSG_SUSPEND size");
624 
625 			memset(&sigact, 0, sizeof sigact);
626 			sigemptyset(&sigact.sa_mask);
627 			sigact.sa_flags = SA_RESTART;
628 			sigact.sa_handler = SIG_DFL;
629 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
630 				fatal("sigaction failed");
631 			kill(getpid(), SIGTSTP);
632 			break;
633 		case MSG_LOCK:
634 			if (datalen != sizeof lockdata)
635 				fatalx("bad MSG_LOCK size");
636 			memcpy(&lockdata, imsg.data, sizeof lockdata);
637 
638 			lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
639 			system(lockdata.cmd);
640 			client_write_server(MSG_UNLOCK, NULL, 0);
641 			break;
642 		default:
643 			fatalx("unexpected message");
644 		}
645 
646 		imsg_free(&imsg);
647 	}
648 }
649