1 /* $OpenBSD: client.c,v 1.93 2015/08/30 22:40:25 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/file.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 <signal.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include "tmux.h" 35 36 int client_flags; 37 struct imsgbuf client_ibuf; 38 struct event client_event; 39 struct event client_stdin; 40 enum { 41 CLIENT_EXIT_NONE, 42 CLIENT_EXIT_DETACHED, 43 CLIENT_EXIT_DETACHED_HUP, 44 CLIENT_EXIT_LOST_TTY, 45 CLIENT_EXIT_TERMINATED, 46 CLIENT_EXIT_LOST_SERVER, 47 CLIENT_EXIT_EXITED, 48 CLIENT_EXIT_SERVER_EXITED, 49 } client_exitreason = CLIENT_EXIT_NONE; 50 int client_exitval; 51 enum msgtype client_exittype; 52 const char *client_exitsession; 53 int client_attached; 54 55 __dead void client_exec(const char *); 56 int client_get_lock(char *); 57 int client_connect(struct event_base *, char *, int); 58 void client_send_identify(void); 59 int client_write_one(enum msgtype, int, const void *, size_t); 60 int client_write_server(enum msgtype, const void *, size_t); 61 void client_update_event(void); 62 void client_signal(int, short, void *); 63 void client_stdin_callback(int, short, void *); 64 void client_write(int, const char *, size_t); 65 void client_callback(int, short, void *); 66 int client_dispatch_attached(void); 67 int client_dispatch_wait(void); 68 const char *client_exit_message(void); 69 70 /* 71 * Get server create lock. If already held then server start is happening in 72 * another client, so block until the lock is released and return -1 to 73 * retry. Ignore other errors - just continue and start the server without the 74 * lock. 75 */ 76 int 77 client_get_lock(char *lockfile) 78 { 79 int lockfd; 80 81 if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) 82 fatal("open failed"); 83 log_debug("lock file is %s", lockfile); 84 85 if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { 86 log_debug("flock failed: %s", strerror(errno)); 87 if (errno != EAGAIN) 88 return (lockfd); 89 while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR) 90 /* nothing */; 91 close(lockfd); 92 return (-1); 93 } 94 log_debug("flock succeeded"); 95 96 return (lockfd); 97 } 98 99 /* Connect client to server. */ 100 int 101 client_connect(struct event_base *base, char *path, int start_server) 102 { 103 struct sockaddr_un sa; 104 size_t size; 105 int fd, lockfd = -1, locked = 0; 106 char *lockfile = NULL; 107 108 memset(&sa, 0, sizeof sa); 109 sa.sun_family = AF_UNIX; 110 size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); 111 if (size >= sizeof sa.sun_path) { 112 errno = ENAMETOOLONG; 113 return (-1); 114 } 115 log_debug("socket is %s", path); 116 117 retry: 118 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 119 fatal("socket failed"); 120 121 log_debug("trying connect"); 122 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { 123 log_debug("connect failed: %s", strerror(errno)); 124 if (errno != ECONNREFUSED && errno != ENOENT) 125 goto failed; 126 if (!start_server) 127 goto failed; 128 close(fd); 129 130 if (!locked) { 131 xasprintf(&lockfile, "%s.lock", path); 132 if ((lockfd = client_get_lock(lockfile)) == -1) { 133 log_debug("didn't get lock"); 134 free(lockfile); 135 goto retry; 136 } 137 log_debug("got lock"); 138 139 /* 140 * Always retry at least once, even if we got the lock, 141 * because another client could have taken the lock, 142 * started the server and released the lock between our 143 * connect() and flock(). 144 */ 145 locked = 1; 146 goto retry; 147 } 148 149 if (unlink(path) != 0 && errno != ENOENT) { 150 free(lockfile); 151 close(lockfd); 152 return (-1); 153 } 154 fd = server_start(base, lockfd, lockfile); 155 } 156 if (locked) { 157 free(lockfile); 158 close(lockfd); 159 } 160 161 setblocking(fd, 0); 162 return (fd); 163 164 failed: 165 close(fd); 166 return (-1); 167 } 168 169 /* Get exit string from reason number. */ 170 const char * 171 client_exit_message(void) 172 { 173 static char msg[256]; 174 175 switch (client_exitreason) { 176 case CLIENT_EXIT_NONE: 177 break; 178 case CLIENT_EXIT_DETACHED: 179 if (client_exitsession != NULL) { 180 xsnprintf(msg, sizeof msg, "detached " 181 "(from session %s)", client_exitsession); 182 return (msg); 183 } 184 return ("detached"); 185 case CLIENT_EXIT_DETACHED_HUP: 186 if (client_exitsession != NULL) { 187 xsnprintf(msg, sizeof msg, "detached and SIGHUP " 188 "(from session %s)", client_exitsession); 189 return (msg); 190 } 191 return ("detached and SIGHUP"); 192 case CLIENT_EXIT_LOST_TTY: 193 return ("lost tty"); 194 case CLIENT_EXIT_TERMINATED: 195 return ("terminated"); 196 case CLIENT_EXIT_LOST_SERVER: 197 return ("lost server"); 198 case CLIENT_EXIT_EXITED: 199 return ("exited"); 200 case CLIENT_EXIT_SERVER_EXITED: 201 return ("server exited"); 202 } 203 return ("unknown reason"); 204 } 205 206 /* Client main loop. */ 207 int 208 client_main(struct event_base *base, int argc, char **argv, int flags) 209 { 210 struct cmd *cmd; 211 struct cmd_list *cmdlist; 212 struct msg_command_data *data; 213 int cmdflags, fd, i; 214 pid_t ppid; 215 enum msgtype msg; 216 char *cause; 217 struct termios tio, saved_tio; 218 size_t size; 219 220 /* Save the flags. */ 221 client_flags = flags; 222 223 /* Set up the initial command. */ 224 cmdflags = 0; 225 if (shell_cmd != NULL) { 226 msg = MSG_SHELL; 227 cmdflags = CMD_STARTSERVER; 228 } else if (argc == 0) { 229 msg = MSG_COMMAND; 230 cmdflags = CMD_STARTSERVER; 231 } else { 232 msg = MSG_COMMAND; 233 234 /* 235 * It sucks parsing the command string twice (in client and 236 * later in server) but it is necessary to get the start server 237 * flag. 238 */ 239 cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause); 240 if (cmdlist == NULL) { 241 fprintf(stderr, "%s\n", cause); 242 return (1); 243 } 244 cmdflags &= ~CMD_STARTSERVER; 245 TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { 246 if (cmd->entry->flags & CMD_STARTSERVER) 247 cmdflags |= CMD_STARTSERVER; 248 } 249 cmd_list_free(cmdlist); 250 } 251 252 /* Set process title, log and signals now this is the client. */ 253 setproctitle("client (%s)", socket_path); 254 logfile("client"); 255 256 /* Establish signal handlers. */ 257 set_signals(client_signal); 258 259 /* Initialize the client socket and start the server. */ 260 fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER); 261 if (fd == -1) { 262 if (errno == ECONNREFUSED) { 263 fprintf(stderr, "no server running on %s\n", 264 socket_path); 265 } else { 266 fprintf(stderr, "error connecting to %s (%s)\n", 267 socket_path, strerror(errno)); 268 } 269 return (1); 270 } 271 272 /* Create imsg. */ 273 imsg_init(&client_ibuf, fd); 274 event_set(&client_event, fd, EV_READ, client_callback, NULL); 275 276 /* Create stdin handler. */ 277 setblocking(STDIN_FILENO, 0); 278 event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, 279 client_stdin_callback, NULL); 280 if (client_flags & CLIENT_CONTROLCONTROL) { 281 if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { 282 fprintf(stderr, "tcgetattr failed: %s\n", 283 strerror(errno)); 284 return (1); 285 } 286 cfmakeraw(&tio); 287 tio.c_iflag = ICRNL|IXANY; 288 tio.c_oflag = OPOST|ONLCR; 289 tio.c_lflag = NOKERNINFO; 290 tio.c_cflag = CREAD|CS8|HUPCL; 291 tio.c_cc[VMIN] = 1; 292 tio.c_cc[VTIME] = 0; 293 cfsetispeed(&tio, cfgetispeed(&saved_tio)); 294 cfsetospeed(&tio, cfgetospeed(&saved_tio)); 295 tcsetattr(STDIN_FILENO, TCSANOW, &tio); 296 } 297 298 /* Send identify messages. */ 299 client_send_identify(); 300 301 /* Send first command. */ 302 if (msg == MSG_COMMAND) { 303 /* How big is the command? */ 304 size = 0; 305 for (i = 0; i < argc; i++) 306 size += strlen(argv[i]) + 1; 307 data = xmalloc((sizeof *data) + size); 308 309 /* Prepare command for server. */ 310 data->argc = argc; 311 if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) { 312 fprintf(stderr, "command too long\n"); 313 free(data); 314 return (1); 315 } 316 size += sizeof *data; 317 318 /* Send the command. */ 319 if (client_write_server(msg, data, size) != 0) { 320 fprintf(stderr, "failed to send command\n"); 321 free(data); 322 return (1); 323 } 324 free(data); 325 } else if (msg == MSG_SHELL) 326 client_write_server(msg, NULL, 0); 327 328 /* Set the event and dispatch. */ 329 client_update_event(); 330 event_dispatch(); 331 332 /* Print the exit message, if any, and exit. */ 333 if (client_attached) { 334 if (client_exitreason != CLIENT_EXIT_NONE) 335 printf("[%s]\n", client_exit_message()); 336 337 ppid = getppid(); 338 if (client_exittype == MSG_DETACHKILL && ppid > 1) 339 kill(ppid, SIGHUP); 340 } else if (client_flags & CLIENT_CONTROLCONTROL) { 341 if (client_exitreason != CLIENT_EXIT_NONE) 342 printf("%%exit %s\n", client_exit_message()); 343 else 344 printf("%%exit\n"); 345 printf("\033\\"); 346 tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); 347 } 348 setblocking(STDIN_FILENO, 1); 349 return (client_exitval); 350 } 351 352 /* Send identify messages to server. */ 353 void 354 client_send_identify(void) 355 { 356 const char *s; 357 char **ss; 358 size_t sslen; 359 int fd, flags = client_flags; 360 pid_t pid; 361 362 client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); 363 364 if ((s = getenv("TERM")) == NULL) 365 s = ""; 366 client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); 367 368 if ((s = ttyname(STDIN_FILENO)) == NULL) 369 s = ""; 370 client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1); 371 372 if ((fd = open(".", O_RDONLY)) == -1) 373 fd = open("/", O_RDONLY); 374 client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0); 375 376 if ((fd = dup(STDIN_FILENO)) == -1) 377 fatal("dup failed"); 378 client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0); 379 380 pid = getpid(); 381 client_write_one(MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid); 382 383 for (ss = environ; *ss != NULL; ss++) { 384 sslen = strlen(*ss) + 1; 385 if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE) 386 client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, sslen); 387 } 388 389 client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0); 390 391 client_update_event(); 392 } 393 394 /* Helper to send one message. */ 395 int 396 client_write_one(enum msgtype type, int fd, const void *buf, size_t len) 397 { 398 int retval; 399 400 retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, 401 (void *)buf, len); 402 if (retval != 1) 403 return (-1); 404 return (0); 405 } 406 407 /* Write a message to the server without a file descriptor. */ 408 int 409 client_write_server(enum msgtype type, const void *buf, size_t len) 410 { 411 int retval; 412 413 retval = client_write_one(type, -1, buf, len); 414 if (retval == 0) 415 client_update_event(); 416 return (retval); 417 } 418 419 /* Update client event based on whether it needs to read or read and write. */ 420 void 421 client_update_event(void) 422 { 423 short events; 424 425 event_del(&client_event); 426 events = EV_READ; 427 if (client_ibuf.w.queued > 0) 428 events |= EV_WRITE; 429 event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); 430 event_add(&client_event, NULL); 431 } 432 433 /* Callback to handle signals in the client. */ 434 void 435 client_signal(int sig, unused short events, unused void *arg) 436 { 437 struct sigaction sigact; 438 int status; 439 440 if (sig == SIGCHLD) 441 waitpid(WAIT_ANY, &status, WNOHANG); 442 else if (!client_attached) { 443 if (sig == SIGTERM) 444 event_loopexit(NULL); 445 } else { 446 switch (sig) { 447 case SIGHUP: 448 client_exitreason = CLIENT_EXIT_LOST_TTY; 449 client_exitval = 1; 450 client_write_server(MSG_EXITING, NULL, 0); 451 break; 452 case SIGTERM: 453 client_exitreason = CLIENT_EXIT_TERMINATED; 454 client_exitval = 1; 455 client_write_server(MSG_EXITING, NULL, 0); 456 break; 457 case SIGWINCH: 458 client_write_server(MSG_RESIZE, NULL, 0); 459 break; 460 case SIGCONT: 461 memset(&sigact, 0, sizeof sigact); 462 sigemptyset(&sigact.sa_mask); 463 sigact.sa_flags = SA_RESTART; 464 sigact.sa_handler = SIG_IGN; 465 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 466 fatal("sigaction failed"); 467 client_write_server(MSG_WAKEUP, NULL, 0); 468 break; 469 } 470 } 471 472 client_update_event(); 473 } 474 475 /* Callback for client imsg read events. */ 476 void 477 client_callback(unused int fd, short events, unused void *arg) 478 { 479 ssize_t n; 480 int retval; 481 482 if (events & EV_READ) { 483 if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) 484 goto lost_server; 485 if (client_attached) 486 retval = client_dispatch_attached(); 487 else 488 retval = client_dispatch_wait(); 489 if (retval != 0) { 490 event_loopexit(NULL); 491 return; 492 } 493 } 494 495 if (events & EV_WRITE) { 496 if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN) 497 goto lost_server; 498 } 499 500 client_update_event(); 501 return; 502 503 lost_server: 504 client_exitreason = CLIENT_EXIT_LOST_SERVER; 505 client_exitval = 1; 506 event_loopexit(NULL); 507 } 508 509 /* Callback for client stdin read events. */ 510 void 511 client_stdin_callback(unused int fd, unused short events, unused void *arg) 512 { 513 struct msg_stdin_data data; 514 515 data.size = read(STDIN_FILENO, data.data, sizeof data.data); 516 if (data.size < 0 && (errno == EINTR || errno == EAGAIN)) 517 return; 518 519 client_write_server(MSG_STDIN, &data, sizeof data); 520 if (data.size <= 0) 521 event_del(&client_stdin); 522 client_update_event(); 523 } 524 525 /* Force write to file descriptor. */ 526 void 527 client_write(int fd, const char *data, size_t size) 528 { 529 ssize_t used; 530 531 while (size != 0) { 532 used = write(fd, data, size); 533 if (used == -1) { 534 if (errno == EINTR || errno == EAGAIN) 535 continue; 536 break; 537 } 538 data += used; 539 size -= used; 540 } 541 } 542 543 /* Run command in shell; used for -c. */ 544 __dead void 545 client_exec(const char *shell) 546 { 547 const char *name, *ptr; 548 char *argv0; 549 550 log_debug("shell %s, command %s", shell, shell_cmd); 551 552 ptr = strrchr(shell, '/'); 553 if (ptr != NULL && *(ptr + 1) != '\0') 554 name = ptr + 1; 555 else 556 name = shell; 557 if (client_flags & CLIENT_LOGIN) 558 xasprintf(&argv0, "-%s", name); 559 else 560 xasprintf(&argv0, "%s", name); 561 setenv("SHELL", shell, 1); 562 563 setblocking(STDIN_FILENO, 1); 564 setblocking(STDOUT_FILENO, 1); 565 setblocking(STDERR_FILENO, 1); 566 closefrom(STDERR_FILENO + 1); 567 568 execl(shell, argv0, "-c", shell_cmd, (char *) NULL); 569 fatal("execl failed"); 570 } 571 572 /* Dispatch imsgs when in wait state (before MSG_READY). */ 573 int 574 client_dispatch_wait(void) 575 { 576 struct imsg imsg; 577 char *data; 578 ssize_t n, datalen; 579 struct msg_stdout_data stdoutdata; 580 struct msg_stderr_data stderrdata; 581 int retval; 582 583 for (;;) { 584 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 585 fatalx("imsg_get failed"); 586 if (n == 0) 587 return (0); 588 589 data = imsg.data; 590 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 591 592 log_debug("got %u from server", imsg.hdr.type); 593 switch (imsg.hdr.type) { 594 case MSG_EXIT: 595 case MSG_SHUTDOWN: 596 if (datalen != sizeof retval && datalen != 0) 597 fatalx("bad MSG_EXIT size"); 598 if (datalen == sizeof retval) { 599 memcpy(&retval, data, sizeof retval); 600 client_exitval = retval; 601 } 602 imsg_free(&imsg); 603 return (-1); 604 case MSG_READY: 605 if (datalen != 0) 606 fatalx("bad MSG_READY size"); 607 608 event_del(&client_stdin); 609 client_attached = 1; 610 client_write_server(MSG_RESIZE, NULL, 0); 611 break; 612 case MSG_STDIN: 613 if (datalen != 0) 614 fatalx("bad MSG_STDIN size"); 615 616 event_add(&client_stdin, NULL); 617 break; 618 case MSG_STDOUT: 619 if (datalen != sizeof stdoutdata) 620 fatalx("bad MSG_STDOUT size"); 621 memcpy(&stdoutdata, data, sizeof stdoutdata); 622 623 client_write(STDOUT_FILENO, stdoutdata.data, 624 stdoutdata.size); 625 break; 626 case MSG_STDERR: 627 if (datalen != sizeof stderrdata) 628 fatalx("bad MSG_STDERR size"); 629 memcpy(&stderrdata, data, sizeof stderrdata); 630 631 client_write(STDERR_FILENO, stderrdata.data, 632 stderrdata.size); 633 break; 634 case MSG_VERSION: 635 if (datalen != 0) 636 fatalx("bad MSG_VERSION size"); 637 638 fprintf(stderr, "protocol version mismatch " 639 "(client %d, server %u)\n", PROTOCOL_VERSION, 640 imsg.hdr.peerid); 641 client_exitval = 1; 642 643 imsg_free(&imsg); 644 return (-1); 645 case MSG_SHELL: 646 if (datalen == 0 || data[datalen - 1] != '\0') 647 fatalx("bad MSG_SHELL string"); 648 649 clear_signals(0); 650 client_exec(data); 651 /* NOTREACHED */ 652 case MSG_DETACH: 653 case MSG_DETACHKILL: 654 client_write_server(MSG_EXITING, NULL, 0); 655 break; 656 case MSG_EXITED: 657 imsg_free(&imsg); 658 return (-1); 659 } 660 661 imsg_free(&imsg); 662 } 663 } 664 665 /* Dispatch imsgs in attached state (after MSG_READY). */ 666 int 667 client_dispatch_attached(void) 668 { 669 struct imsg imsg; 670 struct sigaction sigact; 671 char *data; 672 ssize_t n, datalen; 673 674 for (;;) { 675 if ((n = imsg_get(&client_ibuf, &imsg)) == -1) 676 fatalx("imsg_get failed"); 677 if (n == 0) 678 return (0); 679 680 data = imsg.data; 681 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 682 683 log_debug("got %u from server", imsg.hdr.type); 684 switch (imsg.hdr.type) { 685 case MSG_DETACH: 686 case MSG_DETACHKILL: 687 if (datalen == 0 || data[datalen - 1] != '\0') 688 fatalx("bad MSG_DETACH string"); 689 690 client_exitsession = xstrdup(data); 691 client_exittype = imsg.hdr.type; 692 if (imsg.hdr.type == MSG_DETACHKILL) 693 client_exitreason = CLIENT_EXIT_DETACHED_HUP; 694 else 695 client_exitreason = CLIENT_EXIT_DETACHED; 696 client_write_server(MSG_EXITING, NULL, 0); 697 break; 698 case MSG_EXIT: 699 if (datalen != 0 && datalen != sizeof (int)) 700 fatalx("bad MSG_EXIT size"); 701 702 client_write_server(MSG_EXITING, NULL, 0); 703 client_exitreason = CLIENT_EXIT_EXITED; 704 break; 705 case MSG_EXITED: 706 if (datalen != 0) 707 fatalx("bad MSG_EXITED size"); 708 709 imsg_free(&imsg); 710 return (-1); 711 case MSG_SHUTDOWN: 712 if (datalen != 0) 713 fatalx("bad MSG_SHUTDOWN size"); 714 715 client_write_server(MSG_EXITING, NULL, 0); 716 client_exitreason = CLIENT_EXIT_SERVER_EXITED; 717 client_exitval = 1; 718 break; 719 case MSG_SUSPEND: 720 if (datalen != 0) 721 fatalx("bad MSG_SUSPEND size"); 722 723 memset(&sigact, 0, sizeof sigact); 724 sigemptyset(&sigact.sa_mask); 725 sigact.sa_flags = SA_RESTART; 726 sigact.sa_handler = SIG_DFL; 727 if (sigaction(SIGTSTP, &sigact, NULL) != 0) 728 fatal("sigaction failed"); 729 kill(getpid(), SIGTSTP); 730 break; 731 case MSG_LOCK: 732 if (datalen == 0 || data[datalen - 1] != '\0') 733 fatalx("bad MSG_LOCK string"); 734 735 system(data); 736 client_write_server(MSG_UNLOCK, NULL, 0); 737 break; 738 } 739 740 imsg_free(&imsg); 741 } 742 } 743