xref: /minix/external/bsd/tmux/dist/client.c (revision e3b78ef1)
1 /* $Id: client.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv 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/socket.h>
21 #include <sys/stat.h>
22 #include <sys/un.h>
23 #include <sys/wait.h>
24 
25 #include <errno.h>
26 #include <event.h>
27 #include <fcntl.h>
28 #include <pwd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include "tmux.h"
34 
35 struct imsgbuf	client_ibuf;
36 struct event	client_event;
37 const char     *client_exitmsg;
38 int		client_exitval;
39 enum msgtype	client_exittype;
40 int		client_attached;
41 
42 int		client_connect(char *, int);
43 void		client_send_identify(int);
44 void		client_send_environ(void);
45 void		client_write_server(enum msgtype, void *, size_t);
46 void		client_update_event(void);
47 void		client_signal(int, short, void *);
48 void		client_callback(int, short, void *);
49 int		client_dispatch_attached(void);
50 int		client_dispatch_wait(void *);
51 
52 /* Connect client to server. */
53 int
54 client_connect(char *path, int start_server)
55 {
56 	struct sockaddr_un	sa;
57 	size_t			size;
58 	int			fd;
59 
60 	memset(&sa, 0, sizeof sa);
61 	sa.sun_family = AF_UNIX;
62 	size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
63 	if (size >= sizeof sa.sun_path) {
64 		errno = ENAMETOOLONG;
65 		return (-1);
66 	}
67 
68 #ifndef __minix
69 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
70 #else
71 	if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
72 #endif
73 		fatal("socket failed");
74 
75 	if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
76 		if (!start_server)
77 			goto failed;
78 		switch (errno) {
79 		case ECONNREFUSED:
80 			if (unlink(path) != 0)
81 				goto failed;
82 			/* FALLTHROUGH */
83 		case ENOENT:
84 			if ((fd = server_start()) == -1)
85 				goto failed;
86 			break;
87 		default:
88 			goto failed;
89 		}
90 	}
91 
92 	setblocking(fd, 0);
93 	return (fd);
94 
95 failed:
96 	close(fd);
97 	return (-1);
98 }
99 
100 /* Client main loop. */
101 int
102 client_main(int argc, char **argv, int flags)
103 {
104 	struct cmd		*cmd;
105 	struct cmd_list		*cmdlist;
106 	struct msg_command_data	 cmddata;
107 	int			 cmdflags, fd;
108 	pid_t			 ppid;
109 	enum msgtype		 msg;
110 	char			*cause;
111 
112 	/* Set up the initial command. */
113 	cmdflags = 0;
114 	if (shell_cmd != NULL) {
115 		msg = MSG_SHELL;
116 		cmdflags = CMD_STARTSERVER;
117 	} else if (argc == 0) {
118 		msg = MSG_COMMAND;
119 		cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
120 	} else {
121 		msg = MSG_COMMAND;
122 
123 		/*
124 		 * It sucks parsing the command string twice (in client and
125 		 * later in server) but it is necessary to get the start server
126 		 * flag.
127 		 */
128 		if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
129 			log_warnx("%s", cause);
130 			return (1);
131 		}
132 		cmdflags &= ~CMD_STARTSERVER;
133 		TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
134 			if (cmd->entry->flags & CMD_STARTSERVER)
135 				cmdflags |= CMD_STARTSERVER;
136 			if (cmd->entry->flags & CMD_SENDENVIRON)
137 				cmdflags |= CMD_SENDENVIRON;
138 			if (cmd->entry->flags & CMD_CANTNEST)
139 				cmdflags |= CMD_CANTNEST;
140 		}
141 		cmd_list_free(cmdlist);
142 	}
143 
144 	/*
145 	 * Check if this could be a nested session, if the command can't nest:
146 	 * if the socket path matches $TMUX, this is probably the same server.
147 	 */
148 	if (shell_cmd == NULL && environ_path != NULL &&
149 	    cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
150 		log_warnx("sessions should be nested with care. "
151 		    "unset $TMUX to force.");
152 		return (1);
153 	}
154 
155 	/* Initialise the client socket and start the server. */
156 	fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
157 	if (fd == -1) {
158 		log_warn("failed to connect to server");
159 		return (1);
160 	}
161 
162 	/* Set process title, log and signals now this is the client. */
163 #ifdef HAVE_SETPROCTITLE
164 	setproctitle("client (%s)", socket_path);
165 #endif
166 	logfile("client");
167 
168 	/* Create imsg. */
169 	imsg_init(&client_ibuf, fd);
170 	event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
171 
172 	/* Establish signal handlers. */
173 	set_signals(client_signal);
174 
175 	/* Send initial environment. */
176 	if (cmdflags & CMD_SENDENVIRON)
177 		client_send_environ();
178 	client_send_identify(flags);
179 
180 	/* Send first command. */
181 	if (msg == MSG_COMMAND) {
182 		/* Fill in command line arguments. */
183 		cmddata.pid = environ_pid;
184 		cmddata.idx = environ_idx;
185 
186 		/* Prepare command for server. */
187 		cmddata.argc = argc;
188 		if (cmd_pack_argv(
189 		    argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
190 			log_warnx("command too long");
191 			return (1);
192 		}
193 
194 		client_write_server(msg, &cmddata, sizeof cmddata);
195 	} else if (msg == MSG_SHELL)
196 		client_write_server(msg, NULL, 0);
197 
198 	/* Set the event and dispatch. */
199 	client_update_event();
200 	event_dispatch();
201 
202 	/* Print the exit message, if any, and exit. */
203 	if (client_attached) {
204 		if (client_exitmsg != NULL && !login_shell)
205 			printf("[%s]\n", client_exitmsg);
206 
207 		ppid = getppid();
208 		if (client_exittype == MSG_DETACHKILL && ppid > 1)
209 			kill(ppid, SIGHUP);
210 	}
211 	return (client_exitval);
212 }
213 
214 /* Send identify message to server with the file descriptors. */
215 void
216 client_send_identify(int flags)
217 {
218 	struct msg_identify_data	data;
219 	char			       *term;
220 	int				fd;
221 
222 	data.flags = flags;
223 
224 	if (getcwd(data.cwd, sizeof data.cwd) == NULL)
225 		*data.cwd = '\0';
226 
227 	term = getenv("TERM");
228 	if (term == NULL ||
229 	    strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
230 		*data.term = '\0';
231 
232 	if ((fd = dup(STDIN_FILENO)) == -1)
233 		fatal("dup failed");
234 	imsg_compose(&client_ibuf,
235 	    MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
236 
237 	if ((fd = dup(STDOUT_FILENO)) == -1)
238 		fatal("dup failed");
239 	imsg_compose(&client_ibuf,
240 	    MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
241 
242 	if ((fd = dup(STDERR_FILENO)) == -1)
243 		fatal("dup failed");
244 	imsg_compose(&client_ibuf,
245 	    MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
246 }
247 
248 /* Forward entire environment to server. */
249 void
250 client_send_environ(void)
251 {
252 	struct msg_environ_data	data;
253 	char		      **var;
254 
255 	for (var = environ; *var != NULL; var++) {
256 		if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
257 			continue;
258 		client_write_server(MSG_ENVIRON, &data, sizeof data);
259 	}
260 }
261 
262 /* Write a message to the server without a file descriptor. */
263 void
264 client_write_server(enum msgtype type, void *buf, size_t len)
265 {
266 	imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
267 }
268 
269 /* Update client event based on whether it needs to read or read and write. */
270 void
271 client_update_event(void)
272 {
273 	short	events;
274 
275 	event_del(&client_event);
276 	events = EV_READ;
277 	if (client_ibuf.w.queued > 0)
278 		events |= EV_WRITE;
279 	event_set(
280 	    &client_event, client_ibuf.fd, events, client_callback, shell_cmd);
281 	event_add(&client_event, NULL);
282 }
283 
284 /* Callback to handle signals in the client. */
285 /* ARGSUSED */
286 void
287 client_signal(int sig, unused short events, unused void *data)
288 {
289 	struct sigaction sigact;
290 	int		 status;
291 
292 	if (!client_attached) {
293 		switch (sig) {
294 		case SIGCHLD:
295 			waitpid(WAIT_ANY, &status, WNOHANG);
296 			break;
297 		case SIGTERM:
298 			event_loopexit(NULL);
299 			break;
300 		}
301 	} else {
302 		switch (sig) {
303 		case SIGHUP:
304 			client_exitmsg = "lost tty";
305 			client_exitval = 1;
306 			client_write_server(MSG_EXITING, NULL, 0);
307 			break;
308 		case SIGTERM:
309 			client_exitmsg = "terminated";
310 			client_exitval = 1;
311 			client_write_server(MSG_EXITING, NULL, 0);
312 			break;
313 		case SIGWINCH:
314 			client_write_server(MSG_RESIZE, NULL, 0);
315 			break;
316 		case SIGCONT:
317 			memset(&sigact, 0, sizeof sigact);
318 			sigemptyset(&sigact.sa_mask);
319 			sigact.sa_flags = SA_RESTART;
320 			sigact.sa_handler = SIG_IGN;
321 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
322 				fatal("sigaction failed");
323 			client_write_server(MSG_WAKEUP, NULL, 0);
324 			break;
325 		}
326 	}
327 
328 	client_update_event();
329 }
330 
331 /* Callback for client imsg read events. */
332 /* ARGSUSED */
333 void
334 client_callback(unused int fd, short events, void *data)
335 {
336 	ssize_t	n;
337 	int	retval;
338 
339 	if (events & EV_READ) {
340 		if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
341 			goto lost_server;
342 		if (client_attached)
343 			retval = client_dispatch_attached();
344 		else
345 			retval = client_dispatch_wait(data);
346 		if (retval != 0) {
347 			event_loopexit(NULL);
348 			return;
349 		}
350 	}
351 
352 	if (events & EV_WRITE) {
353 		if (msgbuf_write(&client_ibuf.w) < 0)
354 			goto lost_server;
355 	}
356 
357 	client_update_event();
358 	return;
359 
360 lost_server:
361 	client_exitmsg = "lost server";
362 	client_exitval = 1;
363 	event_loopexit(NULL);
364 }
365 
366 /* Dispatch imsgs when in wait state (before MSG_READY). */
367 int
368 client_dispatch_wait(void *data)
369 {
370 	struct imsg		imsg;
371 	ssize_t			n, datalen;
372 	struct msg_shell_data	shelldata;
373 	struct msg_exit_data	exitdata;
374 	const char             *shellcmd = data;
375 
376 	if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
377 		fatalx("imsg_read failed");
378 
379 	for (;;) {
380 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
381 			fatalx("imsg_get failed");
382 		if (n == 0)
383 			return (0);
384 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
385 
386 		switch (imsg.hdr.type) {
387 		case MSG_EXIT:
388 		case MSG_SHUTDOWN:
389 			if (datalen != sizeof exitdata) {
390 				if (datalen != 0)
391 					fatalx("bad MSG_EXIT size");
392 			} else {
393 				memcpy(&exitdata, imsg.data, sizeof exitdata);
394 				client_exitval = exitdata.retcode;
395 			}
396 			imsg_free(&imsg);
397 			return (-1);
398 		case MSG_READY:
399 			if (datalen != 0)
400 				fatalx("bad MSG_READY size");
401 
402 			client_attached = 1;
403 			break;
404 		case MSG_VERSION:
405 			if (datalen != 0)
406 				fatalx("bad MSG_VERSION size");
407 
408 			log_warnx("protocol version mismatch (client %u, "
409 			    "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
410 			client_exitval = 1;
411 
412 			imsg_free(&imsg);
413 			return (-1);
414 		case MSG_SHELL:
415 			if (datalen != sizeof shelldata)
416 				fatalx("bad MSG_SHELL size");
417 			memcpy(&shelldata, imsg.data, sizeof shelldata);
418 			shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
419 
420 			clear_signals(0);
421 
422 			shell_exec(shelldata.shell, shellcmd);
423 			/* NOTREACHED */
424 		default:
425 			fatalx("unexpected message");
426 		}
427 
428 		imsg_free(&imsg);
429 	}
430 }
431 
432 /* Dispatch imsgs in attached state (after MSG_READY). */
433 /* ARGSUSED */
434 int
435 client_dispatch_attached(void)
436 {
437 	struct imsg		imsg;
438 	struct msg_lock_data	lockdata;
439 	struct sigaction	sigact;
440 	ssize_t			n, datalen;
441 
442 	for (;;) {
443 		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
444 			fatalx("imsg_get failed");
445 		if (n == 0)
446 			return (0);
447 		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
448 
449 		log_debug("client got %d", imsg.hdr.type);
450 		switch (imsg.hdr.type) {
451 		case MSG_DETACHKILL:
452 		case MSG_DETACH:
453 			if (datalen != 0)
454 				fatalx("bad MSG_DETACH size");
455 
456 			client_exittype = imsg.hdr.type;
457 			if (imsg.hdr.type == MSG_DETACHKILL)
458 				client_exitmsg = "detached and SIGHUP";
459 			else
460 				client_exitmsg = "detached";
461 			client_write_server(MSG_EXITING, NULL, 0);
462 			break;
463 		case MSG_EXIT:
464 			if (datalen != 0 &&
465 			    datalen != sizeof (struct msg_exit_data))
466 				fatalx("bad MSG_EXIT size");
467 
468 			client_write_server(MSG_EXITING, NULL, 0);
469 			client_exitmsg = "exited";
470 			break;
471 		case MSG_EXITED:
472 			if (datalen != 0)
473 				fatalx("bad MSG_EXITED size");
474 
475 			imsg_free(&imsg);
476 			return (-1);
477 		case MSG_SHUTDOWN:
478 			if (datalen != 0)
479 				fatalx("bad MSG_SHUTDOWN size");
480 
481 			client_write_server(MSG_EXITING, NULL, 0);
482 			client_exitmsg = "server exited";
483 			client_exitval = 1;
484 			break;
485 		case MSG_SUSPEND:
486 			if (datalen != 0)
487 				fatalx("bad MSG_SUSPEND size");
488 
489 			memset(&sigact, 0, sizeof sigact);
490 			sigemptyset(&sigact.sa_mask);
491 			sigact.sa_flags = SA_RESTART;
492 			sigact.sa_handler = SIG_DFL;
493 			if (sigaction(SIGTSTP, &sigact, NULL) != 0)
494 				fatal("sigaction failed");
495 			kill(getpid(), SIGTSTP);
496 			break;
497 		case MSG_LOCK:
498 			if (datalen != sizeof lockdata)
499 				fatalx("bad MSG_LOCK size");
500 			memcpy(&lockdata, imsg.data, sizeof lockdata);
501 
502 			lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
503 			system(lockdata.cmd);
504 			client_write_server(MSG_UNLOCK, NULL, 0);
505 			break;
506 		default:
507 			fatalx("unexpected message");
508 		}
509 
510 		imsg_free(&imsg);
511 	}
512 }
513