Annotation of src/usr.bin/tmux/client.c, Revision 1.20
1.20 ! nicm 1: /* $OpenBSD: client.c,v 1.19 2009/09/23 06:05:02 nicm Exp $ */
1.1 nicm 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/ioctl.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 <fcntl.h>
28: #include <pwd.h>
29: #include <stdlib.h>
30: #include <string.h>
31: #include <syslog.h>
32: #include <unistd.h>
33:
34: #include "tmux.h"
35:
1.11 nicm 36: void client_send_environ(struct client_ctx *);
1.1 nicm 37:
38: int
1.4 nicm 39: client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags)
1.1 nicm 40: {
41: struct sockaddr_un sa;
42: struct stat sb;
43: struct msg_identify_data data;
44: struct winsize ws;
45: size_t size;
1.14 nicm 46: int fd, fd2, mode;
1.19 nicm 47: char *term;
1.2 nicm 48: char rpathbuf[MAXPATHLEN];
49:
50: if (realpath(path, rpathbuf) == NULL)
51: strlcpy(rpathbuf, path, sizeof rpathbuf);
52: setproctitle("client (%s)", rpathbuf);
1.1 nicm 53:
54: if (lstat(path, &sb) != 0) {
1.4 nicm 55: if (cmdflags & CMD_STARTSERVER && errno == ENOENT) {
1.10 nicm 56: if ((fd = server_start(path)) == -1)
1.1 nicm 57: goto start_failed;
58: goto server_started;
59: }
60: goto not_found;
61: }
62: if (!S_ISSOCK(sb.st_mode)) {
63: errno = ENOTSOCK;
64: goto not_found;
65: }
66:
67: memset(&sa, 0, sizeof sa);
68: sa.sun_family = AF_UNIX;
69: size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
70: if (size >= sizeof sa.sun_path) {
71: errno = ENAMETOOLONG;
72: goto not_found;
73: }
74:
1.10 nicm 75: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
1.18 nicm 76: fatal("socket failed");
1.1 nicm 77:
1.10 nicm 78: if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
1.1 nicm 79: if (errno == ECONNREFUSED) {
1.4 nicm 80: if (unlink(path) != 0 || !(cmdflags & CMD_STARTSERVER))
1.1 nicm 81: goto not_found;
1.10 nicm 82: if ((fd = server_start(path)) == -1)
1.1 nicm 83: goto start_failed;
84: goto server_started;
85: }
86: goto not_found;
87: }
88:
89: server_started:
1.10 nicm 90: if ((mode = fcntl(fd, F_GETFL)) == -1)
1.1 nicm 91: fatal("fcntl failed");
1.10 nicm 92: if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
1.1 nicm 93: fatal("fcntl failed");
1.12 nicm 94: imsg_init(&cctx->ibuf, fd);
1.1 nicm 95:
1.11 nicm 96: if (cmdflags & CMD_SENDENVIRON)
97: client_send_environ(cctx);
1.1 nicm 98: if (isatty(STDIN_FILENO)) {
99: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
100: fatal("ioctl(TIOCGWINSZ)");
101: data.flags = flags;
1.7 nicm 102:
1.1 nicm 103: if (getcwd(data.cwd, sizeof data.cwd) == NULL)
104: *data.cwd = '\0';
105:
1.7 nicm 106: *data.term = '\0';
107: if ((term = getenv("TERM")) != NULL) {
108: if (strlcpy(data.term,
109: term, sizeof data.term) >= sizeof data.term)
110: *data.term = '\0';
111: }
112:
1.19 nicm 113: if ((fd2 = dup(STDIN_FILENO)) == -1)
114: fatal("dup failed");
1.13 nicm 115: imsg_compose(&cctx->ibuf, MSG_IDENTIFY,
1.14 nicm 116: PROTOCOL_VERSION, -1, fd2, &data, sizeof data);
1.1 nicm 117: }
118:
119: return (0);
120:
121: start_failed:
122: log_warnx("server failed to start");
123: return (1);
124:
125: not_found:
126: log_warn("server not found");
127: return (1);
128: }
129:
1.11 nicm 130: void
131: client_send_environ(struct client_ctx *cctx)
132: {
133: char **var;
134: struct msg_environ_data data;
135:
136: for (var = environ; *var != NULL; var++) {
137: if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
138: continue;
139: client_write_server(cctx, MSG_ENVIRON, &data, sizeof data);
140: }
141: }
142:
1.1 nicm 143: int
144: client_main(struct client_ctx *cctx)
145: {
146: struct pollfd pfd;
1.17 nicm 147: int n, nfds;
1.1 nicm 148:
149: siginit();
150:
151: logfile("client");
152:
1.17 nicm 153: /*
154: * imsg_read in the first client poll loop (before the terminal has
155: * been initialiased) may have read messages into the buffer after the
156: * MSG_READY switched to here. Process anything outstanding now so poll
157: * doesn't hang waiting for messages that have already arrived.
158: */
159: if (client_msg_dispatch(cctx) != 0)
160: goto out;
161:
1.8 nicm 162: for (;;) {
163: if (sigterm)
164: client_write_server(cctx, MSG_EXITING, NULL, 0);
1.1 nicm 165: if (sigchld) {
166: waitpid(WAIT_ANY, NULL, WNOHANG);
167: sigchld = 0;
168: }
1.20 ! nicm 169: if (sigwinch) {
! 170: client_write_server(cctx, MSG_RESIZE, NULL, 0);
! 171: sigwinch = 0;
! 172: }
1.1 nicm 173: if (sigcont) {
174: siginit();
175: client_write_server(cctx, MSG_WAKEUP, NULL, 0);
176: sigcont = 0;
177: }
178:
1.12 nicm 179: pfd.fd = cctx->ibuf.fd;
1.1 nicm 180: pfd.events = POLLIN;
1.12 nicm 181: if (cctx->ibuf.w.queued > 0)
1.1 nicm 182: pfd.events |= POLLOUT;
183:
1.12 nicm 184: if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
1.1 nicm 185: if (errno == EAGAIN || errno == EINTR)
186: continue;
187: fatal("poll failed");
188: }
1.12 nicm 189: if (nfds == 0)
190: continue;
191:
192: if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
193: fatalx("socket error");
1.1 nicm 194:
1.12 nicm 195: if (pfd.revents & POLLIN) {
1.17 nicm 196: if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
197: cctx->exittype = CCTX_DIED;
198: break;
199: }
1.12 nicm 200: if (client_msg_dispatch(cctx) != 0)
201: break;
1.5 nicm 202: }
1.9 nicm 203:
1.12 nicm 204: if (pfd.revents & POLLOUT) {
205: if (msgbuf_write(&cctx->ibuf.w) < 0) {
206: cctx->exittype = CCTX_DIED;
207: break;
208: }
209: }
1.1 nicm 210: }
1.17 nicm 211:
212: out:
1.1 nicm 213: if (sigterm) {
214: printf("[terminated]\n");
215: return (1);
216: }
1.5 nicm 217: switch (cctx->exittype) {
218: case CCTX_DIED:
219: printf("[lost server]\n");
220: return (0);
221: case CCTX_SHUTDOWN:
1.1 nicm 222: printf("[server exited]\n");
223: return (0);
1.5 nicm 224: case CCTX_EXIT:
1.16 nicm 225: if (cctx->errstr != NULL) {
226: printf("[error: %s]\n", cctx->errstr);
227: return (1);
228: }
1.1 nicm 229: printf("[exited]\n");
230: return (0);
1.5 nicm 231: case CCTX_DETACH:
1.1 nicm 232: printf("[detached]\n");
233: return (0);
1.5 nicm 234: default:
1.16 nicm 235: printf("[unknown error]\n");
1.5 nicm 236: return (1);
1.1 nicm 237: }
1.9 nicm 238: }
239:
240: int
241: client_msg_dispatch(struct client_ctx *cctx)
242: {
1.12 nicm 243: struct imsg imsg;
1.9 nicm 244: struct msg_print_data printdata;
1.12 nicm 245: ssize_t n, datalen;
1.9 nicm 246:
247: for (;;) {
1.12 nicm 248: if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
249: fatalx("imsg_get failed");
250: if (n == 0)
1.9 nicm 251: return (0);
1.12 nicm 252: datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1.9 nicm 253:
1.12 nicm 254: switch (imsg.hdr.type) {
1.9 nicm 255: case MSG_DETACH:
1.12 nicm 256: if (datalen != 0)
1.9 nicm 257: fatalx("bad MSG_DETACH size");
258:
259: client_write_server(cctx, MSG_EXITING, NULL, 0);
260: cctx->exittype = CCTX_DETACH;
261: break;
262: case MSG_ERROR:
1.12 nicm 263: if (datalen != sizeof printdata)
264: fatalx("bad MSG_ERROR size");
265: memcpy(&printdata, imsg.data, sizeof printdata);
1.11 nicm 266:
1.9 nicm 267: printdata.msg[(sizeof printdata.msg) - 1] = '\0';
1.16 nicm 268: /* Error string used after exit message from server. */
1.9 nicm 269: cctx->errstr = xstrdup(printdata.msg);
1.12 nicm 270: imsg_free(&imsg);
1.9 nicm 271: return (-1);
272: case MSG_EXIT:
1.12 nicm 273: if (datalen != 0)
1.9 nicm 274: fatalx("bad MSG_EXIT size");
1.12 nicm 275:
1.9 nicm 276: client_write_server(cctx, MSG_EXITING, NULL, 0);
277: cctx->exittype = CCTX_EXIT;
278: break;
279: case MSG_EXITED:
1.12 nicm 280: if (datalen != 0)
1.9 nicm 281: fatalx("bad MSG_EXITED size");
282:
1.12 nicm 283: imsg_free(&imsg);
1.9 nicm 284: return (-1);
285: case MSG_SHUTDOWN:
1.12 nicm 286: if (datalen != 0)
1.9 nicm 287: fatalx("bad MSG_SHUTDOWN size");
288:
289: client_write_server(cctx, MSG_EXITING, NULL, 0);
290: cctx->exittype = CCTX_SHUTDOWN;
291: break;
292: case MSG_SUSPEND:
1.12 nicm 293: if (datalen != 0)
1.9 nicm 294: fatalx("bad MSG_SUSPEND size");
295:
296: client_suspend();
297: break;
298: default:
299: fatalx("unexpected message");
300: }
1.12 nicm 301:
302: imsg_free(&imsg);
1.9 nicm 303: }
1.1 nicm 304: }