This commit was manufactured by cvs2svn to create tag 'TMUX_1_2'.
[tmux.git] / client.c
blob4ac68243648b8ff28c7f9f8f44fec90abd20becb
1 /* $Id: client.c,v 1.90 2009-12-04 22:14:47 tcunha Exp $ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/un.h>
24 #include <sys/wait.h>
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 <syslog.h>
33 #include <unistd.h>
35 #include "tmux.h"
37 struct imsgbuf client_ibuf;
38 struct event client_event;
39 const char *client_exitmsg;
40 int client_exitval;
42 void client_send_identify(int);
43 void client_send_environ(void);
44 void client_write_server(enum msgtype, void *, size_t);
45 void client_update_event(void);
46 void client_signal(int, short, void *);
47 void client_callback(int, short, void *);
48 int client_dispatch(void);
50 struct imsgbuf *
51 client_init(char *path, int cmdflags, int flags)
53 struct sockaddr_un sa;
54 size_t size;
55 int fd, mode;
56 #ifdef HAVE_SETPROCTITLE
57 char rpathbuf[MAXPATHLEN];
58 #endif
60 #ifdef HAVE_SETPROCTITLE
61 if (realpath(path, rpathbuf) == NULL)
62 strlcpy(rpathbuf, path, sizeof rpathbuf);
63 setproctitle("client (%s)", rpathbuf);
64 #endif
66 memset(&sa, 0, sizeof sa);
67 sa.sun_family = AF_UNIX;
68 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
69 if (size >= sizeof sa.sun_path) {
70 errno = ENAMETOOLONG;
71 goto not_found;
74 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
75 fatal("socket failed");
77 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
78 if (!(cmdflags & CMD_STARTSERVER))
79 goto not_found;
80 switch (errno) {
81 case ECONNREFUSED:
82 if (unlink(path) != 0)
83 goto not_found;
84 /* FALLTHROUGH */
85 case ENOENT:
86 if ((fd = server_start(path)) == -1)
87 goto start_failed;
88 goto server_started;
90 goto not_found;
93 server_started:
94 if ((mode = fcntl(fd, F_GETFL)) == -1)
95 fatal("fcntl failed");
96 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
97 fatal("fcntl failed");
98 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
99 fatal("fcntl failed");
100 imsg_init(&client_ibuf, fd);
102 if (cmdflags & CMD_SENDENVIRON)
103 client_send_environ();
104 if (isatty(STDIN_FILENO))
105 client_send_identify(flags);
107 return (&client_ibuf);
109 start_failed:
110 log_warnx("server failed to start");
111 return (NULL);
113 not_found:
114 log_warn("server not found");
115 return (NULL);
118 void
119 client_send_identify(int flags)
121 struct msg_identify_data data;
122 struct winsize ws;
123 char *term;
124 int fd;
126 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
127 fatal("ioctl(TIOCGWINSZ)");
128 data.flags = flags;
130 if (getcwd(data.cwd, sizeof data.cwd) == NULL)
131 *data.cwd = '\0';
133 term = getenv("TERM");
134 if (term == NULL ||
135 strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
136 *data.term = '\0';
138 if ((fd = dup(STDIN_FILENO)) == -1)
139 fatal("dup failed");
140 imsg_compose(&client_ibuf,
141 MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
144 void
145 client_send_environ(void)
147 struct msg_environ_data data;
148 char **var;
150 for (var = environ; *var != NULL; var++) {
151 if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
152 continue;
153 client_write_server(MSG_ENVIRON, &data, sizeof data);
157 void
158 client_write_server(enum msgtype type, void *buf, size_t len)
160 imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
163 void
164 client_update_event(void)
166 short events;
168 event_del(&client_event);
169 events = EV_READ;
170 if (client_ibuf.w.queued > 0)
171 events |= EV_WRITE;
172 event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
173 event_add(&client_event, NULL);
176 __dead void
177 client_main(void)
179 struct event ev_sigcont, ev_sigterm, ev_sigwinch;
180 struct sigaction sigact;
182 logfile("client");
184 /* Note: event_init() has already been called. */
186 /* Set up signals. */
187 memset(&sigact, 0, sizeof sigact);
188 sigemptyset(&sigact.sa_mask);
189 sigact.sa_flags = SA_RESTART;
190 sigact.sa_handler = SIG_IGN;
191 if (sigaction(SIGINT, &sigact, NULL) != 0)
192 fatal("sigaction failed");
193 if (sigaction(SIGPIPE, &sigact, NULL) != 0)
194 fatal("sigaction failed");
195 if (sigaction(SIGUSR1, &sigact, NULL) != 0)
196 fatal("sigaction failed");
197 if (sigaction(SIGUSR2, &sigact, NULL) != 0)
198 fatal("sigaction failed");
199 if (sigaction(SIGTSTP, &sigact, NULL) != 0)
200 fatal("sigaction failed");
202 signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
203 signal_add(&ev_sigcont, NULL);
204 signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
205 signal_add(&ev_sigterm, NULL);
206 signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
207 signal_add(&ev_sigwinch, NULL);
210 * imsg_read in the first client poll loop (before the terminal has
211 * been initialised) may have read messages into the buffer after the
212 * MSG_READY switched to here. Process anything outstanding now to
213 * avoid hanging waiting for messages that have already arrived.
215 if (client_dispatch() != 0)
216 goto out;
218 /* Set the event and dispatch. */
219 client_update_event();
220 event_dispatch();
222 out:
223 /* Print the exit message, if any, and exit. */
224 if (client_exitmsg != NULL && !login_shell)
225 printf("[%s]\n", client_exitmsg);
226 exit(client_exitval);
229 /* ARGSUSED */
230 void
231 client_signal(int sig, unused short events, unused void *data)
233 struct sigaction sigact;
235 switch (sig) {
236 case SIGTERM:
237 client_exitmsg = "terminated";
238 client_exitval = 1;
239 client_write_server(MSG_EXITING, NULL, 0);
240 break;
241 case SIGWINCH:
242 client_write_server(MSG_RESIZE, NULL, 0);
243 break;
244 case SIGCONT:
245 memset(&sigact, 0, sizeof sigact);
246 sigemptyset(&sigact.sa_mask);
247 sigact.sa_flags = SA_RESTART;
248 sigact.sa_handler = SIG_IGN;
249 if (sigaction(SIGTSTP, &sigact, NULL) != 0)
250 fatal("sigaction failed");
251 client_write_server(MSG_WAKEUP, NULL, 0);
252 break;
255 client_update_event();
258 /* ARGSUSED */
259 void
260 client_callback(unused int fd, short events, unused void *data)
262 ssize_t n;
264 if (events & EV_READ) {
265 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
266 goto lost_server;
267 if (client_dispatch() != 0) {
268 event_loopexit(NULL);
269 return;
273 if (events & EV_WRITE) {
274 if (msgbuf_write(&client_ibuf.w) < 0)
275 goto lost_server;
278 client_update_event();
279 return;
281 lost_server:
282 client_exitmsg = "lost server";
283 client_exitval = 1;
284 event_loopexit(NULL);
288 client_dispatch(void)
290 struct imsg imsg;
291 struct msg_lock_data lockdata;
292 struct sigaction sigact;
293 ssize_t n, datalen;
295 for (;;) {
296 if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
297 fatalx("imsg_get failed");
298 if (n == 0)
299 return (0);
300 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
302 log_debug("client got %d", imsg.hdr.type);
303 switch (imsg.hdr.type) {
304 case MSG_DETACH:
305 if (datalen != 0)
306 fatalx("bad MSG_DETACH size");
308 client_write_server(MSG_EXITING, NULL, 0);
309 client_exitmsg = "detached";
310 break;
311 case MSG_EXIT:
312 if (datalen != 0)
313 fatalx("bad MSG_EXIT size");
315 client_write_server(MSG_EXITING, NULL, 0);
316 client_exitmsg = "exited";
317 break;
318 case MSG_EXITED:
319 if (datalen != 0)
320 fatalx("bad MSG_EXITED size");
322 imsg_free(&imsg);
323 return (-1);
324 case MSG_SHUTDOWN:
325 if (datalen != 0)
326 fatalx("bad MSG_SHUTDOWN size");
328 client_write_server(MSG_EXITING, NULL, 0);
329 client_exitmsg = "server exited";
330 client_exitval = 1;
331 break;
332 case MSG_SUSPEND:
333 if (datalen != 0)
334 fatalx("bad MSG_SUSPEND size");
336 memset(&sigact, 0, sizeof sigact);
337 sigemptyset(&sigact.sa_mask);
338 sigact.sa_flags = SA_RESTART;
339 sigact.sa_handler = SIG_DFL;
340 if (sigaction(SIGTSTP, &sigact, NULL) != 0)
341 fatal("sigaction failed");
342 kill(getpid(), SIGTSTP);
343 break;
344 case MSG_LOCK:
345 if (datalen != sizeof lockdata)
346 fatalx("bad MSG_LOCK size");
347 memcpy(&lockdata, imsg.data, sizeof lockdata);
349 lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
350 system(lockdata.cmd);
351 client_write_server(MSG_UNLOCK, NULL, 0);
352 break;
353 default:
354 fatalx("unexpected message");
357 imsg_free(&imsg);