1 /* $OpenBSD: client.c,v 1.33 2009/11/13 18:07:52 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/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 <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> 34 35 #include "tmux.h" 36 37 struct imsgbuf client_ibuf; 38 struct event client_event; 39 const char *client_exitmsg; 40 int client_exitval; 41 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); 49 50 struct imsgbuf * 51 client_init(char *path, int cmdflags, int flags) 52 { 53 struct sockaddr_un sa; 54 size_t size; 55 int fd, mode; 56 char rpathbuf[MAXPATHLEN]; 57 58 if (realpath(path, rpathbuf) == NULL) 59 strlcpy(rpathbuf, path, sizeof rpathbuf); 60 setproctitle("client (%s)", rpathbuf); 61 62 memset(&sa, 0, sizeof sa); 63 sa.sun_family = AF_UNIX; 64 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); 65 if (size >= sizeof sa.sun_path) { 66 errno = ENAMETOOLONG; 67 goto not_found; 68 } 69 70 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 71 fatal("socket failed"); 72 73 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { 74 if (!(cmdflags & CMD_STARTSERVER)) 75 goto not_found; 76 switch (errno) { 77 case ECONNREFUSED: 78 if (unlink(path) != 0) 79 goto not_found; 80 /* FALLTHROUGH */ 81 case ENOENT: 82 if ((fd = server_start(path)) == -1) 83 goto start_failed; 84 goto server_started; 85 } 86 goto not_found; 87 } 88 89 server_started: 90 if ((mode = fcntl(fd, F_GETFL)) == -1) 91 fatal("fcntl failed"); 92 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) 93 fatal("fcntl failed"); 94 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 95 fatal("fcntl failed"); 96 imsg_init(&client_ibuf, fd); 97 98 if (cmdflags & CMD_SENDENVIRON) 99 client_send_environ(); 100 if (isatty(STDIN_FILENO)) 101 client_send_identify(flags); 102 103 return (&client_ibuf); 104 105 start_failed: 106 log_warnx("server failed to start"); 107 return (NULL); 108 109 not_found: 110 log_warn("server not found"); 111 return (NULL); 112 } 113 114 void 115 client_send_identify(int flags) 116 { 117 struct msg_identify_data data; 118 struct winsize ws; 119 char *term; 120 int fd; 121 122 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) 123 fatal("ioctl(TIOCGWINSZ)"); 124 data.flags = flags; 125 126 if (getcwd(data.cwd, sizeof data.cwd) == NULL) 127 *data.cwd = '\0'; 128 129 term = getenv("TERM"); 130 if (term == NULL || 131 strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) 132 *data.term = '\0'; 133 134 if ((fd = dup(STDIN_FILENO)) == -1) 135 fatal("dup failed"); 136 imsg_compose(&client_ibuf, 137 MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); 138 } 139 140 void 141 client_send_environ(void) 142 { 143 struct msg_environ_data data; 144 char **var; 145 146 for (var = environ; *var != NULL; var++) { 147 if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) 148 continue; 149 client_write_server(MSG_ENVIRON, &data, sizeof data); 150 } 151 } 152 153 void 154 client_write_server(enum msgtype type, void *buf, size_t len) 155 { 156 imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); 157 } 158 159 void 160 client_update_event(void) 161 { 162 short events; 163 164 event_del(&client_event); 165 events = EV_READ; 166 if (client_ibuf.w.queued > 0) 167 events |= EV_WRITE; 168 event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); 169 event_add(&client_event, NULL); 170 } 171 172 __dead void 173 client_main(void) 174 { 175 struct event ev_sigcont, ev_sigterm, ev_sigwinch; 176 struct sigaction sigact; 177 178 logfile("client"); 179 180 /* Note: event_init() has already been called. */ 181 182 /* Set up signals. */ 183 memset(&sigact, 0, sizeof sigact); 184 sigemptyset(&sigact.sa_mask); 185 sigact.sa_flags = SA_RESTART; 186 sigact.sa_handler = SIG_IGN; 187 if (sigaction(SIGINT, &sigact, NULL) != 0) 188 fatal("sigaction failed"); 189 if (sigaction(SIGPIPE, &sigact, NULL) != 0) 190 fatal("sigaction failed"); 191 if (sigaction(SIGUSR1, &sigact, NULL) != 0) 192 fatal("sigaction failed"); 193 if (sigaction(SIGUSR2, &sigact, NULL) != 0) 194 fatal("sigaction failed"); 195 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 196 fatal("sigaction failed"); 197 198 signal_set(&ev_sigcont, SIGCONT, client_signal, NULL); 199 signal_add(&ev_sigcont, NULL); 200 signal_set(&ev_sigterm, SIGTERM, client_signal, NULL); 201 signal_add(&ev_sigterm, NULL); 202 signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL); 203 signal_add(&ev_sigwinch, NULL); 204 205 /* 206 * imsg_read in the first client poll loop (before the terminal has 207 * been initialised) may have read messages into the buffer after the 208 * MSG_READY switched to here. Process anything outstanding now to 209 * avoid hanging waiting for messages that have already arrived. 210 */ 211 if (client_dispatch() != 0) 212 goto out; 213 214 /* Set the event and dispatch. */ 215 client_update_event(); 216 event_dispatch(); 217 218 out: 219 /* Print the exit message, if any, and exit. */ 220 if (client_exitmsg != NULL && !login_shell) 221 printf("[%s]\n", client_exitmsg); 222 exit(client_exitval); 223 } 224 225 void 226 client_signal(int sig, unused short events, unused void *data) 227 { 228 struct sigaction sigact; 229 230 switch (sig) { 231 case SIGTERM: 232 client_exitmsg = "terminated"; 233 client_exitval = 1; 234 client_write_server(MSG_EXITING, NULL, 0); 235 break; 236 case SIGWINCH: 237 client_write_server(MSG_RESIZE, NULL, 0); 238 break; 239 case SIGCONT: 240 memset(&sigact, 0, sizeof sigact); 241 sigemptyset(&sigact.sa_mask); 242 sigact.sa_flags = SA_RESTART; 243 sigact.sa_handler = SIG_IGN; 244 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 245 fatal("sigaction failed"); 246 client_write_server(MSG_WAKEUP, NULL, 0); 247 break; 248 } 249 250 client_update_event(); 251 } 252 253 void 254 client_callback(unused int fd, short events, unused void *data) 255 { 256 ssize_t n; 257 258 if (events & EV_READ) { 259 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) 260 goto lost_server; 261 if (client_dispatch() != 0) { 262 event_loopexit(NULL); 263 return; 264 } 265 } 266 267 if (events & EV_WRITE) { 268 if (msgbuf_write(&client_ibuf.w) < 0) 269 goto lost_server; 270 } 271 272 client_update_event(); 273 return; 274 275 lost_server: 276 client_exitmsg = "lost server"; 277 client_exitval = 1; 278 event_loopexit(NULL); 279 } 280 281 int 282 client_dispatch(void) 283 { 284 struct imsg imsg; 285 struct msg_lock_data lockdata; 286 struct sigaction sigact; 287 ssize_t n, datalen; 288 289 for (;;) { 290 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 291 fatalx("imsg_get failed"); 292 if (n == 0) 293 return (0); 294 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 295 296 log_debug("client got %d", imsg.hdr.type); 297 switch (imsg.hdr.type) { 298 case MSG_DETACH: 299 if (datalen != 0) 300 fatalx("bad MSG_DETACH size"); 301 302 client_write_server(MSG_EXITING, NULL, 0); 303 client_exitmsg = "detached"; 304 break; 305 case MSG_EXIT: 306 if (datalen != 0) 307 fatalx("bad MSG_EXIT size"); 308 309 client_write_server(MSG_EXITING, NULL, 0); 310 client_exitmsg = "exited"; 311 break; 312 case MSG_EXITED: 313 if (datalen != 0) 314 fatalx("bad MSG_EXITED size"); 315 316 imsg_free(&imsg); 317 return (-1); 318 case MSG_SHUTDOWN: 319 if (datalen != 0) 320 fatalx("bad MSG_SHUTDOWN size"); 321 322 client_write_server(MSG_EXITING, NULL, 0); 323 client_exitmsg = "server exited"; 324 client_exitval = 1; 325 break; 326 case MSG_SUSPEND: 327 if (datalen != 0) 328 fatalx("bad MSG_SUSPEND size"); 329 330 memset(&sigact, 0, sizeof sigact); 331 sigemptyset(&sigact.sa_mask); 332 sigact.sa_flags = SA_RESTART; 333 sigact.sa_handler = SIG_DFL; 334 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 335 fatal("sigaction failed"); 336 kill(getpid(), SIGTSTP); 337 break; 338 case MSG_LOCK: 339 if (datalen != sizeof lockdata) 340 fatalx("bad MSG_LOCK size"); 341 memcpy(&lockdata, imsg.data, sizeof lockdata); 342 343 lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; 344 system(lockdata.cmd); 345 client_write_server(MSG_UNLOCK, NULL, 0); 346 break; 347 default: 348 fatalx("unexpected message"); 349 } 350 351 imsg_free(&imsg); 352 } 353 } 354