client.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/file.h>
  19. #include <sys/socket.h>
  20. #include <sys/stat.h>
  21. #include <sys/un.h>
  22. #include <sys/wait.h>
  23. #include <errno.h>
  24. #include <event.h>
  25. #include <fcntl.h>
  26. #include <signal.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include "tmux.h"
  31. struct tmuxproc *client_proc;
  32. struct tmuxpeer *client_peer;
  33. int client_flags;
  34. struct event client_stdin;
  35. enum {
  36. CLIENT_EXIT_NONE,
  37. CLIENT_EXIT_DETACHED,
  38. CLIENT_EXIT_DETACHED_HUP,
  39. CLIENT_EXIT_LOST_TTY,
  40. CLIENT_EXIT_TERMINATED,
  41. CLIENT_EXIT_LOST_SERVER,
  42. CLIENT_EXIT_EXITED,
  43. CLIENT_EXIT_SERVER_EXITED,
  44. } client_exitreason = CLIENT_EXIT_NONE;
  45. int client_exitval;
  46. enum msgtype client_exittype;
  47. const char *client_exitsession;
  48. int client_attached;
  49. __dead void client_exec(const char *,const char *);
  50. int client_get_lock(char *);
  51. int client_connect(struct event_base *, const char *, int);
  52. void client_send_identify(const char *, const char *);
  53. void client_stdin_callback(int, short, void *);
  54. void client_write(int, const char *, size_t);
  55. void client_signal(int);
  56. void client_dispatch(struct imsg *, void *);
  57. void client_dispatch_attached(struct imsg *);
  58. void client_dispatch_wait(struct imsg *, const char *);
  59. const char *client_exit_message(void);
  60. /*
  61. * Get server create lock. If already held then server start is happening in
  62. * another client, so block until the lock is released and return -2 to
  63. * retry. Return -1 on failure to continue and start the server anyway.
  64. */
  65. int
  66. client_get_lock(char *lockfile)
  67. {
  68. int lockfd;
  69. log_debug("lock file is %s", lockfile);
  70. if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
  71. log_debug("open failed: %s", strerror(errno));
  72. return (-1);
  73. }
  74. if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
  75. log_debug("flock failed: %s", strerror(errno));
  76. if (errno != EAGAIN)
  77. return (lockfd);
  78. while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
  79. /* nothing */;
  80. close(lockfd);
  81. return (-2);
  82. }
  83. log_debug("flock succeeded");
  84. return (lockfd);
  85. }
  86. /* Connect client to server. */
  87. int
  88. client_connect(struct event_base *base, const char *path, int start_server)
  89. {
  90. struct sockaddr_un sa;
  91. size_t size;
  92. int fd, lockfd = -1, locked = 0;
  93. char *lockfile = NULL;
  94. memset(&sa, 0, sizeof sa);
  95. sa.sun_family = AF_UNIX;
  96. size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
  97. if (size >= sizeof sa.sun_path) {
  98. errno = ENAMETOOLONG;
  99. return (-1);
  100. }
  101. log_debug("socket is %s", path);
  102. retry:
  103. if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  104. return (-1);
  105. log_debug("trying connect");
  106. if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
  107. log_debug("connect failed: %s", strerror(errno));
  108. if (errno != ECONNREFUSED && errno != ENOENT)
  109. goto failed;
  110. if (!start_server)
  111. goto failed;
  112. close(fd);
  113. if (!locked) {
  114. xasprintf(&lockfile, "%s.lock", path);
  115. if ((lockfd = client_get_lock(lockfile)) < 0) {
  116. log_debug("didn't get lock (%d)", lockfd);
  117. free(lockfile);
  118. lockfile = NULL;
  119. if (lockfd == -2)
  120. goto retry;
  121. }
  122. log_debug("got lock (%d)", lockfd);
  123. /*
  124. * Always retry at least once, even if we got the lock,
  125. * because another client could have taken the lock,
  126. * started the server and released the lock between our
  127. * connect() and flock().
  128. */
  129. locked = 1;
  130. goto retry;
  131. }
  132. if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
  133. free(lockfile);
  134. close(lockfd);
  135. return (-1);
  136. }
  137. fd = server_start(base, lockfd, lockfile);
  138. }
  139. if (locked && lockfd >= 0) {
  140. free(lockfile);
  141. close(lockfd);
  142. }
  143. setblocking(fd, 0);
  144. return (fd);
  145. failed:
  146. if (locked) {
  147. free(lockfile);
  148. close(lockfd);
  149. }
  150. close(fd);
  151. return (-1);
  152. }
  153. /* Get exit string from reason number. */
  154. const char *
  155. client_exit_message(void)
  156. {
  157. static char msg[256];
  158. switch (client_exitreason) {
  159. case CLIENT_EXIT_NONE:
  160. break;
  161. case CLIENT_EXIT_DETACHED:
  162. if (client_exitsession != NULL) {
  163. xsnprintf(msg, sizeof msg, "detached "
  164. "(from session %s)", client_exitsession);
  165. return (msg);
  166. }
  167. return ("detached");
  168. case CLIENT_EXIT_DETACHED_HUP:
  169. if (client_exitsession != NULL) {
  170. xsnprintf(msg, sizeof msg, "detached and SIGHUP "
  171. "(from session %s)", client_exitsession);
  172. return (msg);
  173. }
  174. return ("detached and SIGHUP");
  175. case CLIENT_EXIT_LOST_TTY:
  176. return ("lost tty");
  177. case CLIENT_EXIT_TERMINATED:
  178. return ("terminated");
  179. case CLIENT_EXIT_LOST_SERVER:
  180. return ("lost server");
  181. case CLIENT_EXIT_EXITED:
  182. return ("exited");
  183. case CLIENT_EXIT_SERVER_EXITED:
  184. return ("server exited");
  185. }
  186. return ("unknown reason");
  187. }
  188. #ifdef TMATE
  189. extern const struct cmd_entry cmd_attach_session_entry;
  190. extern const struct cmd_entry cmd_new_session_entry;
  191. #endif
  192. /* Client main loop. */
  193. int
  194. client_main(struct event_base *base, int argc, char **argv, int flags,
  195. const char *shellcmd)
  196. {
  197. struct cmd *cmd;
  198. struct cmd_list *cmdlist;
  199. struct msg_command_data *data;
  200. int cmdflags, fd, i;
  201. const char *ttynam, *cwd;
  202. pid_t ppid;
  203. enum msgtype msg;
  204. char *cause, path[PATH_MAX];
  205. struct termios tio, saved_tio;
  206. size_t size;
  207. #ifdef TMATE
  208. int cant_nest = 0;
  209. #endif
  210. /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
  211. signal(SIGCHLD, SIG_IGN);
  212. /* Save the flags. */
  213. client_flags = flags;
  214. /* Set up the initial command. */
  215. cmdflags = 0;
  216. if (shellcmd != NULL) {
  217. msg = MSG_SHELL;
  218. cmdflags = CMD_STARTSERVER;
  219. } else if (argc == 0) {
  220. msg = MSG_COMMAND;
  221. cmdflags = CMD_STARTSERVER;
  222. #ifdef TMATE
  223. cant_nest = 1;
  224. #endif
  225. } else {
  226. msg = MSG_COMMAND;
  227. /*
  228. * It sucks parsing the command string twice (in client and
  229. * later in server) but it is necessary to get the start server
  230. * flag.
  231. */
  232. cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
  233. if (cmdlist == NULL) {
  234. fprintf(stderr, "%s\n", cause);
  235. return (1);
  236. }
  237. cmdflags &= ~CMD_STARTSERVER;
  238. TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
  239. if (cmd->entry->flags & CMD_STARTSERVER)
  240. cmdflags |= CMD_STARTSERVER;
  241. #ifdef TMATE
  242. if (cmd->entry == &cmd_attach_session_entry ||
  243. cmd->entry == &cmd_new_session_entry)
  244. cant_nest = 1;
  245. #endif
  246. }
  247. cmd_list_free(cmdlist);
  248. }
  249. #ifdef TMATE
  250. if (cant_nest && getenv("TMUX")) {
  251. fprintf(stderr, "sessions should be nested with care, "
  252. "unset $TMUX to force\n");
  253. return (1);
  254. }
  255. #endif
  256. /* Create client process structure (starts logging). */
  257. client_proc = proc_start("client", base, 0, client_signal);
  258. /* Initialize the client socket and start the server. */
  259. fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
  260. if (fd == -1) {
  261. if (errno == ECONNREFUSED) {
  262. fprintf(stderr, "no server running on %s\n",
  263. socket_path);
  264. } else {
  265. #ifdef TMATE
  266. if (errno == ENOENT)
  267. fprintf(stderr, "You must specify a socket name with -S. For example: \n"
  268. " tmate -S /tmp/tmate.sock new-session -d\n"
  269. " tmate -S /tmp/tmate.sock wait tmate-ready\n");
  270. else
  271. #endif
  272. fprintf(stderr, "error connecting to %s (%s)\n",
  273. socket_path, strerror(errno));
  274. }
  275. return (1);
  276. }
  277. client_peer = proc_add_peer(client_proc, fd, client_dispatch,
  278. (void *)shellcmd);
  279. /* Save these before pledge(). */
  280. if ((cwd = getcwd(path, sizeof path)) == NULL) {
  281. if ((cwd = find_home()) == NULL)
  282. cwd = "/";
  283. }
  284. if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
  285. ttynam = "";
  286. #ifdef __OpenBSD__
  287. /*
  288. * Drop privileges for client. "proc exec" is needed for -c and for
  289. * locking (which uses system(3)).
  290. *
  291. * "tty" is needed to restore termios(4) and also for some reason -CC
  292. * does not work properly without it (input is not recognised).
  293. *
  294. * "sendfd" is dropped later in client_dispatch_wait().
  295. */
  296. if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
  297. fatal("pledge failed");
  298. #endif
  299. /* Free stuff that is not used in the client. */
  300. options_free(global_options);
  301. options_free(global_s_options);
  302. options_free(global_w_options);
  303. environ_free(global_environ);
  304. /* Create stdin handler. */
  305. setblocking(STDIN_FILENO, 0);
  306. event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
  307. client_stdin_callback, NULL);
  308. if (client_flags & CLIENT_CONTROLCONTROL) {
  309. if (tcgetattr(STDIN_FILENO, &saved_tio) != 0)
  310. fatal("tcgetattr failed");
  311. cfmakeraw(&tio);
  312. tio.c_iflag = ICRNL|IXANY;
  313. tio.c_oflag = OPOST|ONLCR;
  314. #ifdef NOKERNINFO
  315. tio.c_lflag = NOKERNINFO;
  316. #endif
  317. tio.c_cflag = CREAD|CS8|HUPCL;
  318. tio.c_cc[VMIN] = 1;
  319. tio.c_cc[VTIME] = 0;
  320. cfsetispeed(&tio, cfgetispeed(&saved_tio));
  321. cfsetospeed(&tio, cfgetospeed(&saved_tio));
  322. tcsetattr(STDIN_FILENO, TCSANOW, &tio);
  323. }
  324. /* Send identify messages. */
  325. client_send_identify(ttynam, cwd);
  326. /* Send first command. */
  327. if (msg == MSG_COMMAND) {
  328. /* How big is the command? */
  329. size = 0;
  330. for (i = 0; i < argc; i++)
  331. size += strlen(argv[i]) + 1;
  332. data = xmalloc((sizeof *data) + size);
  333. /* Prepare command for server. */
  334. data->argc = argc;
  335. if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
  336. fprintf(stderr, "command too long\n");
  337. free(data);
  338. return (1);
  339. }
  340. size += sizeof *data;
  341. /* Send the command. */
  342. if (proc_send(client_peer, msg, -1, data, size) != 0) {
  343. fprintf(stderr, "failed to send command\n");
  344. free(data);
  345. return (1);
  346. }
  347. free(data);
  348. } else if (msg == MSG_SHELL)
  349. proc_send(client_peer, msg, -1, NULL, 0);
  350. /* Start main loop. */
  351. proc_loop(client_proc, NULL);
  352. /* Print the exit message, if any, and exit. */
  353. if (client_attached) {
  354. if (client_exitreason != CLIENT_EXIT_NONE)
  355. printf("[%s]\n", client_exit_message());
  356. ppid = getppid();
  357. if (client_exittype == MSG_DETACHKILL && ppid > 1)
  358. kill(ppid, SIGHUP);
  359. } else if (client_flags & CLIENT_CONTROLCONTROL) {
  360. if (client_exitreason != CLIENT_EXIT_NONE)
  361. printf("%%exit %s\n", client_exit_message());
  362. else
  363. printf("%%exit\n");
  364. printf("\033\\");
  365. tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
  366. } else if (client_exitreason != CLIENT_EXIT_NONE)
  367. fprintf(stderr, "%s\n", client_exit_message());
  368. setblocking(STDIN_FILENO, 1);
  369. return (client_exitval);
  370. }
  371. /* Send identify messages to server. */
  372. void
  373. client_send_identify(const char *ttynam, const char *cwd)
  374. {
  375. const char *s;
  376. char **ss;
  377. size_t sslen;
  378. int fd, flags = client_flags;
  379. pid_t pid;
  380. proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
  381. if ((s = getenv("TERM")) == NULL)
  382. s = "";
  383. proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
  384. proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
  385. strlen(ttynam) + 1);
  386. proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
  387. if ((fd = dup(STDIN_FILENO)) == -1)
  388. fatal("dup failed");
  389. proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
  390. pid = getpid();
  391. proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
  392. for (ss = environ; *ss != NULL; ss++) {
  393. sslen = strlen(*ss) + 1;
  394. if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
  395. continue;
  396. proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
  397. }
  398. proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
  399. }
  400. /* Callback for client stdin read events. */
  401. void
  402. client_stdin_callback(__unused int fd, __unused short events,
  403. __unused void *arg)
  404. {
  405. struct msg_stdin_data data;
  406. data.size = read(STDIN_FILENO, data.data, sizeof data.data);
  407. if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
  408. return;
  409. proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
  410. if (data.size <= 0)
  411. event_del(&client_stdin);
  412. }
  413. /* Force write to file descriptor. */
  414. void
  415. client_write(int fd, const char *data, size_t size)
  416. {
  417. ssize_t used;
  418. while (size != 0) {
  419. used = write(fd, data, size);
  420. if (used == -1) {
  421. if (errno == EINTR || errno == EAGAIN)
  422. continue;
  423. break;
  424. }
  425. data += used;
  426. size -= used;
  427. }
  428. }
  429. /* Run command in shell; used for -c. */
  430. __dead void
  431. client_exec(const char *shell, const char *shellcmd)
  432. {
  433. const char *name, *ptr;
  434. char *argv0;
  435. log_debug("shell %s, command %s", shell, shellcmd);
  436. ptr = strrchr(shell, '/');
  437. if (ptr != NULL && *(ptr + 1) != '\0')
  438. name = ptr + 1;
  439. else
  440. name = shell;
  441. if (client_flags & CLIENT_LOGIN)
  442. xasprintf(&argv0, "-%s", name);
  443. else
  444. xasprintf(&argv0, "%s", name);
  445. setenv("SHELL", shell, 1);
  446. setblocking(STDIN_FILENO, 1);
  447. setblocking(STDOUT_FILENO, 1);
  448. setblocking(STDERR_FILENO, 1);
  449. closefrom(STDERR_FILENO + 1);
  450. execl(shell, argv0, "-c", shellcmd, (char *) NULL);
  451. fatal("execl failed");
  452. }
  453. /* Callback to handle signals in the client. */
  454. void
  455. client_signal(int sig)
  456. {
  457. struct sigaction sigact;
  458. int status;
  459. if (sig == SIGCHLD)
  460. waitpid(WAIT_ANY, &status, WNOHANG);
  461. else if (!client_attached) {
  462. if (sig == SIGTERM)
  463. proc_exit(client_proc);
  464. } else {
  465. switch (sig) {
  466. case SIGHUP:
  467. client_exitreason = CLIENT_EXIT_LOST_TTY;
  468. client_exitval = 1;
  469. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  470. break;
  471. case SIGTERM:
  472. client_exitreason = CLIENT_EXIT_TERMINATED;
  473. client_exitval = 1;
  474. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  475. break;
  476. case SIGWINCH:
  477. proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
  478. break;
  479. case SIGCONT:
  480. memset(&sigact, 0, sizeof sigact);
  481. sigemptyset(&sigact.sa_mask);
  482. sigact.sa_flags = SA_RESTART;
  483. sigact.sa_handler = SIG_IGN;
  484. if (sigaction(SIGTSTP, &sigact, NULL) != 0)
  485. fatal("sigaction failed");
  486. proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
  487. break;
  488. }
  489. }
  490. }
  491. /* Callback for client read events. */
  492. void
  493. client_dispatch(struct imsg *imsg, void *arg)
  494. {
  495. if (imsg == NULL) {
  496. client_exitreason = CLIENT_EXIT_LOST_SERVER;
  497. client_exitval = 1;
  498. proc_exit(client_proc);
  499. return;
  500. }
  501. if (client_attached)
  502. client_dispatch_attached(imsg);
  503. else
  504. client_dispatch_wait(imsg, arg);
  505. }
  506. /* Dispatch imsgs when in wait state (before MSG_READY). */
  507. void
  508. client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
  509. {
  510. char *data;
  511. ssize_t datalen;
  512. struct msg_stdout_data stdoutdata;
  513. struct msg_stderr_data stderrdata;
  514. int retval;
  515. #ifdef __OpenBSD__
  516. static int pledge_applied;
  517. /*
  518. * "sendfd" is no longer required once all of the identify messages
  519. * have been sent. We know the server won't send us anything until that
  520. * point (because we don't ask it to), so we can drop "sendfd" once we
  521. * get the first message from the server.
  522. */
  523. if (!pledge_applied) {
  524. if (pledge("stdio unix proc exec tty", NULL) != 0)
  525. fatal("pledge failed");
  526. pledge_applied = 1;
  527. };
  528. #endif
  529. data = imsg->data;
  530. datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
  531. switch (imsg->hdr.type) {
  532. case MSG_EXIT:
  533. case MSG_SHUTDOWN:
  534. if (datalen != sizeof retval && datalen != 0)
  535. fatalx("bad MSG_EXIT size");
  536. if (datalen == sizeof retval) {
  537. memcpy(&retval, data, sizeof retval);
  538. client_exitval = retval;
  539. }
  540. proc_exit(client_proc);
  541. break;
  542. case MSG_READY:
  543. if (datalen != 0)
  544. fatalx("bad MSG_READY size");
  545. event_del(&client_stdin);
  546. client_attached = 1;
  547. proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
  548. break;
  549. case MSG_STDIN:
  550. if (datalen != 0)
  551. fatalx("bad MSG_STDIN size");
  552. event_add(&client_stdin, NULL);
  553. break;
  554. case MSG_STDOUT:
  555. if (datalen != sizeof stdoutdata)
  556. fatalx("bad MSG_STDOUT size");
  557. memcpy(&stdoutdata, data, sizeof stdoutdata);
  558. client_write(STDOUT_FILENO, stdoutdata.data,
  559. stdoutdata.size);
  560. break;
  561. case MSG_STDERR:
  562. if (datalen != sizeof stderrdata)
  563. fatalx("bad MSG_STDERR size");
  564. memcpy(&stderrdata, data, sizeof stderrdata);
  565. client_write(STDERR_FILENO, stderrdata.data,
  566. stderrdata.size);
  567. break;
  568. case MSG_VERSION:
  569. if (datalen != 0)
  570. fatalx("bad MSG_VERSION size");
  571. fprintf(stderr, "protocol version mismatch "
  572. "(client %d, server %u)\n", PROTOCOL_VERSION,
  573. imsg->hdr.peerid & 0xff);
  574. client_exitval = 1;
  575. proc_exit(client_proc);
  576. break;
  577. case MSG_SHELL:
  578. if (datalen == 0 || data[datalen - 1] != '\0')
  579. fatalx("bad MSG_SHELL string");
  580. clear_signals(0);
  581. client_exec(data, shellcmd);
  582. /* NOTREACHED */
  583. case MSG_DETACH:
  584. case MSG_DETACHKILL:
  585. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  586. break;
  587. case MSG_EXITED:
  588. proc_exit(client_proc);
  589. break;
  590. }
  591. }
  592. /* Dispatch imsgs in attached state (after MSG_READY). */
  593. void
  594. client_dispatch_attached(struct imsg *imsg)
  595. {
  596. struct sigaction sigact;
  597. char *data;
  598. ssize_t datalen;
  599. data = imsg->data;
  600. datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
  601. switch (imsg->hdr.type) {
  602. case MSG_DETACH:
  603. case MSG_DETACHKILL:
  604. if (datalen == 0 || data[datalen - 1] != '\0')
  605. fatalx("bad MSG_DETACH string");
  606. client_exitsession = xstrdup(data);
  607. client_exittype = imsg->hdr.type;
  608. if (imsg->hdr.type == MSG_DETACHKILL)
  609. client_exitreason = CLIENT_EXIT_DETACHED_HUP;
  610. else
  611. client_exitreason = CLIENT_EXIT_DETACHED;
  612. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  613. break;
  614. case MSG_EXIT:
  615. if (datalen != 0 && datalen != sizeof (int))
  616. fatalx("bad MSG_EXIT size");
  617. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  618. client_exitreason = CLIENT_EXIT_EXITED;
  619. break;
  620. case MSG_EXITED:
  621. if (datalen != 0)
  622. fatalx("bad MSG_EXITED size");
  623. proc_exit(client_proc);
  624. break;
  625. case MSG_SHUTDOWN:
  626. if (datalen != 0)
  627. fatalx("bad MSG_SHUTDOWN size");
  628. proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
  629. client_exitreason = CLIENT_EXIT_SERVER_EXITED;
  630. client_exitval = 1;
  631. break;
  632. case MSG_SUSPEND:
  633. if (datalen != 0)
  634. fatalx("bad MSG_SUSPEND size");
  635. memset(&sigact, 0, sizeof sigact);
  636. sigemptyset(&sigact.sa_mask);
  637. sigact.sa_flags = SA_RESTART;
  638. sigact.sa_handler = SIG_DFL;
  639. if (sigaction(SIGTSTP, &sigact, NULL) != 0)
  640. fatal("sigaction failed");
  641. kill(getpid(), SIGTSTP);
  642. break;
  643. case MSG_LOCK:
  644. if (datalen == 0 || data[datalen - 1] != '\0')
  645. fatalx("bad MSG_LOCK string");
  646. system(data);
  647. proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
  648. break;
  649. }
  650. }