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