Coverage Report

Created: 2026-07-16 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/client.c
Line
Count
Source
1
/* $OpenBSD: client.c,v 1.166 2026/07/10 15:45:11 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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/socket.h>
21
#include <sys/uio.h>
22
#include <sys/un.h>
23
#include <sys/wait.h>
24
#include <sys/file.h>
25
26
#include <errno.h>
27
#include <fcntl.h>
28
#include <signal.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
33
#include "tmux.h"
34
35
static struct tmuxproc  *client_proc;
36
static struct tmuxpeer  *client_peer;
37
static uint64_t    client_flags;
38
static int     client_suspended;
39
static enum {
40
  CLIENT_EXIT_NONE,
41
  CLIENT_EXIT_DETACHED,
42
  CLIENT_EXIT_DETACHED_HUP,
43
  CLIENT_EXIT_LOST_TTY,
44
  CLIENT_EXIT_TERMINATED,
45
  CLIENT_EXIT_LOST_SERVER,
46
  CLIENT_EXIT_EXITED,
47
  CLIENT_EXIT_SERVER_EXITED,
48
  CLIENT_EXIT_MESSAGE_PROVIDED
49
} client_exitreason = CLIENT_EXIT_NONE;
50
static int     client_exitflag;
51
static int     client_exitval;
52
static enum msgtype  client_exittype;
53
static const char *client_exitsession;
54
static char   *client_exitmessage;
55
static const char *client_execshell;
56
static const char *client_execcmd;
57
static int     client_attached;
58
static struct client_files client_files = RB_INITIALIZER(&client_files);
59
60
static __dead void   client_exec(const char *,const char *);
61
static int     client_get_lock(char *);
62
static int     client_connect(struct event_base *, const char *,
63
           uint64_t);
64
static void    client_send_identify(const char *, const char *,
65
           char **, u_int, const char *, int);
66
static void    client_signal(int);
67
static void    client_dispatch(struct imsg *, void *);
68
static void    client_dispatch_attached(struct imsg *);
69
static void    client_dispatch_wait(struct imsg *);
70
static const char *client_exit_message(void);
71
72
/*
73
 * Get server create lock. If already held then server start is happening in
74
 * another client, so block until the lock is released and return -2 to
75
 * retry. Return -1 on failure to continue and start the server anyway.
76
 */
77
static int
78
client_get_lock(char *lockfile)
79
0
{
80
0
  int lockfd;
81
82
0
  log_debug("lock file is %s", lockfile);
83
84
0
  if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
85
0
    log_debug("open failed: %s", strerror(errno));
86
0
    return (-1);
87
0
  }
88
89
0
  if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
90
0
    log_debug("flock failed: %s", strerror(errno));
91
0
    if (errno != EAGAIN)
92
0
      return (lockfd);
93
0
    while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
94
0
      /* nothing */;
95
0
    close(lockfd);
96
0
    return (-2);
97
0
  }
98
0
  log_debug("flock succeeded");
99
100
0
  return (lockfd);
101
0
}
102
103
/* Connect client to server. */
104
static int
105
client_connect(struct event_base *base, const char *path, uint64_t flags)
106
0
{
107
0
  struct sockaddr_un  sa;
108
0
  size_t      size;
109
0
  int     fd, lockfd = -1, locked = 0;
110
0
  char           *lockfile = NULL;
111
112
0
  memset(&sa, 0, sizeof sa);
113
0
  sa.sun_family = AF_UNIX;
114
0
  size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
115
0
  if (size >= sizeof sa.sun_path) {
116
0
    errno = ENAMETOOLONG;
117
0
    return (-1);
118
0
  }
119
0
  log_debug("socket is %s", path);
120
121
0
retry:
122
0
  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
123
0
    return (-1);
124
125
0
  log_debug("trying connect");
126
0
  if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
127
0
    log_debug("connect failed: %s", strerror(errno));
128
0
    if (errno != ECONNREFUSED && errno != ENOENT)
129
0
      goto failed;
130
0
    if (flags & CLIENT_NOSTARTSERVER)
131
0
      goto failed;
132
0
    if (~flags & CLIENT_STARTSERVER)
133
0
      goto failed;
134
0
    close(fd);
135
136
0
    if (!locked) {
137
0
      xasprintf(&lockfile, "%s.lock", path);
138
0
      if ((lockfd = client_get_lock(lockfile)) < 0) {
139
0
        log_debug("didn't get lock (%d)", lockfd);
140
141
0
        free(lockfile);
142
0
        lockfile = NULL;
143
144
0
        if (lockfd == -2)
145
0
          goto retry;
146
0
      }
147
0
      log_debug("got lock (%d)", lockfd);
148
149
      /*
150
       * Always retry at least once, even if we got the lock,
151
       * because another client could have taken the lock,
152
       * started the server and released the lock between our
153
       * connect() and flock().
154
       */
155
0
      locked = 1;
156
0
      goto retry;
157
0
    }
158
159
0
    if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
160
0
      free(lockfile);
161
0
      close(lockfd);
162
0
      return (-1);
163
0
    }
164
0
    fd = server_start(client_proc, flags, base, lockfd, lockfile);
165
0
  }
166
167
0
  if (locked && lockfd >= 0) {
168
0
    free(lockfile);
169
0
    close(lockfd);
170
0
  }
171
0
  setblocking(fd, 0);
172
0
  return (fd);
173
174
0
failed:
175
0
  if (locked) {
176
0
    free(lockfile);
177
0
    close(lockfd);
178
0
  }
179
0
  close(fd);
180
0
  return (-1);
181
0
}
182
183
/* Get exit string from reason number. */
184
const char *
185
client_exit_message(void)
186
0
{
187
0
  static char msg[256];
188
189
0
  switch (client_exitreason) {
190
0
  case CLIENT_EXIT_NONE:
191
0
    break;
192
0
  case CLIENT_EXIT_DETACHED:
193
0
    if (client_exitsession != NULL) {
194
0
      xsnprintf(msg, sizeof msg, "detached "
195
0
          "(from session %s)", client_exitsession);
196
0
      return (msg);
197
0
    }
198
0
    return ("detached");
199
0
  case CLIENT_EXIT_DETACHED_HUP:
200
0
    if (client_exitsession != NULL) {
201
0
      xsnprintf(msg, sizeof msg, "detached and SIGHUP "
202
0
          "(from session %s)", client_exitsession);
203
0
      return (msg);
204
0
    }
205
0
    return ("detached and SIGHUP");
206
0
  case CLIENT_EXIT_LOST_TTY:
207
0
    return ("lost tty");
208
0
  case CLIENT_EXIT_TERMINATED:
209
0
    return ("terminated");
210
0
  case CLIENT_EXIT_LOST_SERVER:
211
0
    return ("server exited unexpectedly");
212
0
  case CLIENT_EXIT_EXITED:
213
0
    return ("exited");
214
0
  case CLIENT_EXIT_SERVER_EXITED:
215
0
    return ("server exited");
216
0
  case CLIENT_EXIT_MESSAGE_PROVIDED:
217
0
    return (client_exitmessage);
218
0
  }
219
0
  return ("unknown reason");
220
0
}
221
222
/* Exit if all streams flushed. */
223
static void
224
client_exit(void)
225
0
{
226
0
  if (!file_write_left(&client_files))
227
0
    proc_exit(client_proc);
228
0
}
229
230
/* Client main loop. */
231
int
232
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
233
    int feat)
234
0
{
235
0
  struct cmd_parse_result *pr;
236
0
  struct msg_command  *data;
237
0
  int      fd, i;
238
0
  const char    *ttynam, *termname, *cwd;
239
0
  pid_t      ppid;
240
0
  enum msgtype     msg;
241
0
  struct termios     tio, saved_tio;
242
0
  size_t       size;
243
0
  char      **caps = NULL, *cause;
244
0
  u_int      ncaps = 0;
245
0
  struct args_value *values;
246
247
  /* Set up the initial command. */
248
0
  if (shell_command != NULL) {
249
0
    msg = MSG_SHELL;
250
0
    flags |= CLIENT_STARTSERVER;
251
0
  } else if (argc == 0) {
252
0
    msg = MSG_COMMAND;
253
0
    flags |= CLIENT_STARTSERVER;
254
0
  } else {
255
0
    msg = MSG_COMMAND;
256
257
    /*
258
     * It's annoying parsing the command string twice (in client
259
     * and later in server) but it is necessary to get the start
260
     * server flag.
261
     */
262
0
    values = args_from_vector(argc, argv);
263
0
    pr = cmd_parse_from_arguments(values, argc, NULL);
264
0
    if (pr->status == CMD_PARSE_SUCCESS) {
265
0
      if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
266
0
        flags |= CLIENT_STARTSERVER;
267
0
      cmd_list_free(pr->cmdlist);
268
0
    } else
269
0
      free(pr->error);
270
0
    args_free_values(values, argc);
271
0
    free(values);
272
0
  }
273
274
  /* Create client process structure (starts logging). */
275
0
  client_proc = proc_start("client");
276
0
  proc_set_signals(client_proc, client_signal);
277
278
  /* Save the flags. */
279
0
  client_flags = flags;
280
0
  log_debug("flags are %#llx", (unsigned long long)client_flags);
281
282
  /* Initialize the client socket and start the server. */
283
#ifdef HAVE_SYSTEMD
284
  if (systemd_activated()) {
285
    /* socket-based activation, do not even try to be a client. */
286
    fd = server_start(client_proc, flags, base, 0, NULL);
287
  } else
288
#endif
289
0
  fd = client_connect(base, socket_path, client_flags);
290
0
  if (fd == -1) {
291
0
    if (errno == ECONNREFUSED) {
292
0
      fprintf(stderr, "no server running on %s\n",
293
0
          socket_path);
294
0
    } else {
295
0
      fprintf(stderr, "error connecting to %s (%s)\n",
296
0
          socket_path, strerror(errno));
297
0
    }
298
0
    return (1);
299
0
  }
300
0
  client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
301
302
  /* Save these before pledge(). */
303
0
  if ((cwd = find_cwd()) == NULL && (cwd = find_home()) == NULL)
304
0
    cwd = "/";
305
0
  if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
306
0
    ttynam = "";
307
0
  if ((termname = getenv("TERM")) == NULL)
308
0
    termname = "";
309
310
  /*
311
   * Drop privileges for client. "proc exec" is needed for -c and for
312
   * locking (which uses system(3)).
313
   *
314
   * "tty" is needed to restore termios(4) and also for some reason -CC
315
   * does not work properly without it (input is not recognised).
316
   *
317
   * "sendfd" is dropped later in client_dispatch_wait().
318
   */
319
0
  if (pledge(
320
0
      "stdio rpath wpath cpath unix sendfd proc exec tty",
321
0
      NULL) != 0)
322
0
    fatal("pledge failed");
323
324
  /* Load terminfo entry if any. */
325
0
  if (isatty(STDIN_FILENO) &&
326
0
      *termname != '\0' &&
327
0
      tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
328
0
      &cause) != 0) {
329
0
    fprintf(stderr, "%s\n", cause);
330
0
    free(cause);
331
0
    return (1);
332
0
  }
333
334
  /* Free stuff that is not used in the client. */
335
0
  if (ptm_fd != -1)
336
0
    close(ptm_fd);
337
0
  options_free(global_options);
338
0
  options_free(global_s_options);
339
0
  options_free(global_w_options);
340
0
  environ_free(global_environ);
341
342
  /* Set up control mode. */
343
0
  if (client_flags & CLIENT_CONTROLCONTROL) {
344
0
    if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
345
0
      fprintf(stderr, "tcgetattr failed: %s\n",
346
0
          strerror(errno));
347
0
      return (1);
348
0
    }
349
0
    cfmakeraw(&tio);
350
0
    tio.c_iflag = ICRNL|IXANY;
351
0
    tio.c_oflag = OPOST|ONLCR;
352
#ifdef NOKERNINFO
353
    tio.c_lflag = NOKERNINFO;
354
#endif
355
0
    tio.c_cflag = CREAD|CS8|HUPCL;
356
0
    tio.c_cc[VMIN] = 1;
357
0
    tio.c_cc[VTIME] = 0;
358
0
    cfsetispeed(&tio, cfgetispeed(&saved_tio));
359
0
    cfsetospeed(&tio, cfgetospeed(&saved_tio));
360
0
    tcsetattr(STDIN_FILENO, TCSANOW, &tio);
361
0
  }
362
363
  /* Send identify messages. */
364
0
  client_send_identify(ttynam, termname, caps, ncaps, cwd, feat);
365
0
  tty_term_free_list(caps, ncaps);
366
0
  proc_flush_peer(client_peer);
367
368
  /* Send first command. */
369
0
  if (msg == MSG_COMMAND) {
370
    /* How big is the command? */
371
0
    size = 0;
372
0
    for (i = 0; i < argc; i++)
373
0
      size += strlen(argv[i]) + 1;
374
0
    if (size > MAX_IMSGSIZE - (sizeof *data)) {
375
0
      fprintf(stderr, "command too long\n");
376
0
      return (1);
377
0
    }
378
0
    data = xmalloc((sizeof *data) + size);
379
380
    /* Prepare command for server. */
381
0
    data->argc = argc;
382
0
    if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
383
0
      fprintf(stderr, "command too long\n");
384
0
      free(data);
385
0
      return (1);
386
0
    }
387
0
    size += sizeof *data;
388
389
    /* Send the command. */
390
0
    if (proc_send(client_peer, msg, -1, data, size) != 0) {
391
0
      fprintf(stderr, "failed to send command\n");
392
0
      free(data);
393
0
      return (1);
394
0
    }
395
0
    free(data);
396
0
  } else if (msg == MSG_SHELL)
397
0
    proc_send(client_peer, msg, -1, NULL, 0);
398
399
  /* Start main loop. */
400
0
  proc_loop(client_proc, NULL);
401
402
  /* Run command if user requested exec, instead of exiting. */
403
0
  if (client_exittype == MSG_EXEC) {
404
0
    if (client_flags & CLIENT_CONTROLCONTROL)
405
0
      tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
406
0
    client_exec(client_execshell, client_execcmd);
407
0
  }
408
409
  /* Print the exit message, if any, and exit. */
410
0
  if (client_attached) {
411
0
    if (client_exitreason != CLIENT_EXIT_NONE)
412
0
      printf("[%s]\n", client_exit_message());
413
414
0
    ppid = getppid();
415
0
    if (client_exittype == MSG_DETACHKILL && ppid > 1)
416
0
      kill(ppid, SIGHUP);
417
0
  } else if (client_flags & CLIENT_CONTROL) {
418
0
    if (client_exitreason != CLIENT_EXIT_NONE)
419
0
      printf("%%exit %s\n", client_exit_message());
420
0
    else
421
0
      printf("%%exit\n");
422
0
    fflush(stdout);
423
0
    if (client_flags & CLIENT_CONTROL_WAITEXIT)
424
0
      control_wait_exit(STDIN_FILENO);
425
0
    if (client_flags & CLIENT_CONTROLCONTROL) {
426
0
      printf("\033\\");
427
0
      fflush(stdout);
428
0
      tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
429
0
    }
430
0
  } else if (client_exitreason != CLIENT_EXIT_NONE)
431
0
    fprintf(stderr, "%s\n", client_exit_message());
432
433
  /* Restore the streams to blocking. */
434
0
  setblocking(STDIN_FILENO, 1);
435
0
  setblocking(STDOUT_FILENO, 1);
436
0
  setblocking(STDERR_FILENO, 1);
437
438
0
  return (client_exitval);
439
0
}
440
441
/* Send identify messages to server. */
442
static void
443
client_send_identify(const char *ttynam, const char *termname, char **caps,
444
    u_int ncaps, const char *cwd, int feat)
445
0
{
446
0
  char  **ss;
447
0
  size_t    sslen;
448
0
  int   fd;
449
0
  uint64_t  flags = client_flags;
450
0
  pid_t   pid;
451
0
  u_int   i;
452
453
0
  proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags);
454
0
  proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
455
0
      sizeof client_flags);
456
457
0
  proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
458
0
      strlen(termname) + 1);
459
0
  proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
460
461
0
  proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
462
0
      strlen(ttynam) + 1);
463
0
  proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
464
465
0
  for (i = 0; i < ncaps; i++) {
466
0
    proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
467
0
        caps[i], strlen(caps[i]) + 1);
468
0
  }
469
470
0
  if ((fd = dup(STDIN_FILENO)) == -1)
471
0
    fatal("dup failed");
472
0
  proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
473
0
  if ((fd = dup(STDOUT_FILENO)) == -1)
474
0
    fatal("dup failed");
475
0
  proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
476
477
0
  pid = getpid();
478
0
  proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
479
480
0
  for (ss = environ; *ss != NULL; ss++) {
481
0
    sslen = strlen(*ss) + 1;
482
0
    if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
483
0
      continue;
484
0
    proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
485
0
  }
486
487
0
  proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
488
0
}
489
490
/* Run command in shell; used for -c. */
491
static __dead void
492
client_exec(const char *shell, const char *shellcmd)
493
0
{
494
0
  char  *argv0;
495
496
0
  log_debug("shell %s, command %s", shell, shellcmd);
497
0
  argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
498
0
  setenv("SHELL", shell, 1);
499
500
0
  proc_clear_signals(client_proc, 1);
501
502
0
  setblocking(STDIN_FILENO, 1);
503
0
  setblocking(STDOUT_FILENO, 1);
504
0
  setblocking(STDERR_FILENO, 1);
505
0
  closefrom(STDERR_FILENO + 1);
506
507
0
  execl(shell, argv0, "-c", shellcmd, (char *) NULL);
508
0
  fatal("execl failed");
509
0
}
510
511
/* Callback to handle signals in the client. */
512
static void
513
client_signal(int sig)
514
0
{
515
0
  struct sigaction sigact;
516
0
  int    status;
517
0
  pid_t    pid;
518
519
0
  log_debug("%s: %s", __func__, strsignal(sig));
520
0
  if (sig == SIGCHLD) {
521
0
    for (;;) {
522
0
      pid = waitpid(WAIT_ANY, &status, WNOHANG);
523
0
      if (pid == 0)
524
0
        break;
525
0
      if (pid == -1) {
526
0
        if (errno == ECHILD)
527
0
          break;
528
0
        log_debug("waitpid failed: %s",
529
0
            strerror(errno));
530
0
      }
531
0
    }
532
0
  } else if (!client_attached) {
533
0
    if (sig == SIGTERM || sig == SIGHUP)
534
0
      proc_exit(client_proc);
535
0
  } else {
536
0
    switch (sig) {
537
0
    case SIGHUP:
538
0
      client_exitreason = CLIENT_EXIT_LOST_TTY;
539
0
      client_exitval = 1;
540
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
541
0
      break;
542
0
    case SIGTERM:
543
0
      if (!client_suspended)
544
0
        client_exitreason = CLIENT_EXIT_TERMINATED;
545
0
      client_exitval = 1;
546
0
      proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
547
0
      break;
548
0
    case SIGWINCH:
549
0
      proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
550
0
      break;
551
0
    case SIGCONT:
552
0
      memset(&sigact, 0, sizeof sigact);
553
0
      sigemptyset(&sigact.sa_mask);
554
0
      sigact.sa_flags = SA_RESTART;
555
0
      sigact.sa_handler = SIG_IGN;
556
0
      if (sigaction(SIGTSTP, &sigact, NULL) != 0)
557
0
        fatal("sigaction failed");
558
0
      proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
559
0
      client_suspended = 0;
560
0
      break;
561
0
    }
562
0
  }
563
0
}
564
565
/* Callback for file write error or close. */
566
static void
567
client_file_check_cb(__unused struct client *c, __unused const char *path,
568
    __unused int error, __unused int closed, __unused struct evbuffer *buffer,
569
    __unused void *data)
570
0
{
571
0
  if (client_exitflag)
572
0
    client_exit();
573
0
}
574
575
/* Callback for client read events. */
576
static void
577
client_dispatch(struct imsg *imsg, __unused void *arg)
578
0
{
579
0
  if (imsg == NULL) {
580
0
    if (!client_exitflag) {
581
0
      client_exitreason = CLIENT_EXIT_LOST_SERVER;
582
0
      client_exitval = 1;
583
0
    }
584
0
    proc_exit(client_proc);
585
0
    return;
586
0
  }
587
588
0
  if (client_attached)
589
0
    client_dispatch_attached(imsg);
590
0
  else
591
0
    client_dispatch_wait(imsg);
592
0
}
593
594
/* Process an exit message. */
595
static void
596
client_dispatch_exit_message(char *data, size_t datalen)
597
0
{
598
0
  int retval;
599
600
0
  if (datalen < sizeof retval && datalen != 0)
601
0
    fatalx("bad MSG_EXIT size");
602
603
0
  if (datalen >= sizeof retval) {
604
0
    memcpy(&retval, data, sizeof retval);
605
0
    client_exitval = retval;
606
0
  }
607
608
0
  if (datalen > sizeof retval) {
609
0
    datalen -= sizeof retval;
610
0
    data += sizeof retval;
611
612
0
    client_exitmessage = xmalloc(datalen);
613
0
    memcpy(client_exitmessage, data, datalen);
614
0
    client_exitmessage[datalen - 1] = '\0';
615
616
0
    client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
617
0
  }
618
0
}
619
620
/* Dispatch imsgs when in wait state (before MSG_READY). */
621
static void
622
client_dispatch_wait(struct imsg *imsg)
623
0
{
624
0
  char    *data;
625
0
  ssize_t    datalen;
626
0
  static int   pledge_applied;
627
628
  /*
629
   * "sendfd" is no longer required once all of the identify messages
630
   * have been sent. We know the server won't send us anything until that
631
   * point (because we don't ask it to), so we can drop "sendfd" once we
632
   * get the first message from the server.
633
   */
634
0
  if (!pledge_applied) {
635
0
    if (pledge(
636
0
        "stdio rpath wpath cpath unix proc exec tty",
637
0
        NULL) != 0)
638
0
      fatal("pledge failed");
639
0
    pledge_applied = 1;
640
0
  }
641
642
0
  data = imsg->data;
643
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
644
645
0
  switch (imsg->hdr.type) {
646
0
  case MSG_EXIT:
647
0
  case MSG_SHUTDOWN:
648
0
    client_dispatch_exit_message(data, datalen);
649
0
    client_exitflag = 1;
650
0
    client_exit();
651
0
    break;
652
0
  case MSG_READY:
653
0
    if (datalen != 0)
654
0
      fatalx("bad MSG_READY size");
655
656
0
    client_attached = 1;
657
0
    proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
658
0
    break;
659
0
  case MSG_VERSION:
660
0
    if (datalen != 0)
661
0
      fatalx("bad MSG_VERSION size");
662
663
0
    fprintf(stderr, "protocol version mismatch "
664
0
        "(client %d, server %u)\n", PROTOCOL_VERSION,
665
0
        imsg->hdr.peerid & 0xff);
666
0
    client_exitval = 1;
667
0
    proc_exit(client_proc);
668
0
    break;
669
0
  case MSG_FLAGS:
670
0
    if (datalen != sizeof client_flags)
671
0
      fatalx("bad MSG_FLAGS string");
672
673
0
    memcpy(&client_flags, data, sizeof client_flags);
674
0
    log_debug("new flags are %#llx",
675
0
        (unsigned long long)client_flags);
676
0
    break;
677
0
  case MSG_SHELL:
678
0
    if (datalen == 0 || data[datalen - 1] != '\0')
679
0
      fatalx("bad MSG_SHELL string");
680
681
0
    client_exec(data, shell_command);
682
    /* NOTREACHED */
683
0
  case MSG_DETACH:
684
0
  case MSG_DETACHKILL:
685
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
686
0
    break;
687
0
  case MSG_EXITED:
688
0
    proc_exit(client_proc);
689
0
    break;
690
0
  case MSG_READ_OPEN:
691
0
    file_read_open(&client_files, client_peer, imsg, 1,
692
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
693
0
        NULL);
694
0
    break;
695
0
  case MSG_READ_CANCEL:
696
0
    file_read_cancel(&client_files, imsg);
697
0
    break;
698
0
  case MSG_WRITE_OPEN:
699
0
    file_write_open(&client_files, client_peer, imsg, 1,
700
0
        !(client_flags & CLIENT_CONTROL), client_file_check_cb,
701
0
        NULL);
702
0
    break;
703
0
  case MSG_WRITE:
704
0
    file_write_data(&client_files, imsg);
705
0
    break;
706
0
  case MSG_WRITE_CLOSE:
707
0
    file_write_close(&client_files, imsg);
708
0
    break;
709
0
  case MSG_OLDSTDERR:
710
0
  case MSG_OLDSTDIN:
711
0
  case MSG_OLDSTDOUT:
712
0
    fprintf(stderr, "server version is too old for client\n");
713
0
    proc_exit(client_proc);
714
0
    break;
715
0
  }
716
0
}
717
718
/* Dispatch imsgs in attached state (after MSG_READY). */
719
static void
720
client_dispatch_attached(struct imsg *imsg)
721
0
{
722
0
  struct sigaction   sigact;
723
0
  char      *data;
724
0
  ssize_t      datalen;
725
726
0
  data = imsg->data;
727
0
  datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
728
729
0
  switch (imsg->hdr.type) {
730
0
  case MSG_FLAGS:
731
0
    if (datalen != sizeof client_flags)
732
0
      fatalx("bad MSG_FLAGS string");
733
734
0
    memcpy(&client_flags, data, sizeof client_flags);
735
0
    log_debug("new flags are %#llx",
736
0
        (unsigned long long)client_flags);
737
0
    break;
738
0
  case MSG_DETACH:
739
0
  case MSG_DETACHKILL:
740
0
    if (datalen == 0 || data[datalen - 1] != '\0')
741
0
      fatalx("bad MSG_DETACH string");
742
743
0
    client_exitsession = xstrdup(data);
744
0
    client_exittype = imsg->hdr.type;
745
0
    if (imsg->hdr.type == MSG_DETACHKILL)
746
0
      client_exitreason = CLIENT_EXIT_DETACHED_HUP;
747
0
    else
748
0
      client_exitreason = CLIENT_EXIT_DETACHED;
749
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
750
0
    break;
751
0
  case MSG_EXEC:
752
0
    if (datalen == 0 || data[datalen - 1] != '\0' ||
753
0
        strlen(data) + 1 == (size_t)datalen)
754
0
      fatalx("bad MSG_EXEC string");
755
0
    client_execcmd = xstrdup(data);
756
0
    client_execshell = xstrdup(data + strlen(data) + 1);
757
758
0
    client_exittype = imsg->hdr.type;
759
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
760
0
    break;
761
0
  case MSG_EXIT:
762
0
    client_dispatch_exit_message(data, datalen);
763
0
    if (client_exitreason == CLIENT_EXIT_NONE)
764
0
      client_exitreason = CLIENT_EXIT_EXITED;
765
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
766
0
    break;
767
0
  case MSG_EXITED:
768
0
    if (datalen != 0)
769
0
      fatalx("bad MSG_EXITED size");
770
771
0
    proc_exit(client_proc);
772
0
    break;
773
0
  case MSG_SHUTDOWN:
774
0
    if (datalen != 0)
775
0
      fatalx("bad MSG_SHUTDOWN size");
776
777
0
    proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
778
0
    client_exitreason = CLIENT_EXIT_SERVER_EXITED;
779
0
    client_exitval = 1;
780
0
    break;
781
0
  case MSG_SUSPEND:
782
0
    if (datalen != 0)
783
0
      fatalx("bad MSG_SUSPEND size");
784
785
0
    memset(&sigact, 0, sizeof sigact);
786
0
    sigemptyset(&sigact.sa_mask);
787
0
    sigact.sa_flags = SA_RESTART;
788
0
    sigact.sa_handler = SIG_DFL;
789
0
    if (sigaction(SIGTSTP, &sigact, NULL) != 0)
790
0
      fatal("sigaction failed");
791
0
    client_suspended = 1;
792
0
    kill(getpid(), SIGTSTP);
793
0
    break;
794
0
  case MSG_LOCK:
795
0
    if (datalen == 0 || data[datalen - 1] != '\0')
796
0
      fatalx("bad MSG_LOCK string");
797
798
0
    system(data);
799
    proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
800
0
    break;
801
0
  }
802
0
}