199e242abSchristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4f26e8bc9Schristos * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv #include <sys/stat.h> 2168e6ba84Schristos #include <sys/utsname.h> 22698d5317Sjmmv 23698d5317Sjmmv #include <errno.h> 24698d5317Sjmmv #include <fcntl.h> 25f26e8bc9Schristos #include <langinfo.h> 2661fba46bSchristos #include <locale.h> 27698d5317Sjmmv #include <pwd.h> 28e271dbb8Schristos #include <signal.h> 29698d5317Sjmmv #include <stdlib.h> 30698d5317Sjmmv #include <string.h> 3199e242abSchristos #include <time.h> 32698d5317Sjmmv #include <unistd.h> 33698d5317Sjmmv 34698d5317Sjmmv #include "tmux.h" 35698d5317Sjmmv 36f26e8bc9Schristos struct options *global_options; /* server options */ 37f26e8bc9Schristos struct options *global_s_options; /* session options */ 38f26e8bc9Schristos struct options *global_w_options; /* window options */ 39f26e8bc9Schristos struct environ *global_environ; 40698d5317Sjmmv 41f26e8bc9Schristos struct timeval start_time; 42f26e8bc9Schristos const char *socket_path; 43e9a2d6faSchristos int ptm_fd = -1; 44fe99a117Schristos const char *shell_command; 45698d5317Sjmmv 46e9a2d6faSchristos static __dead void usage(void); 47c7e17de0Schristos static char *make_label(const char *, char **); 48698d5317Sjmmv 49e271dbb8Schristos static int areshell(const char *); 50e9a2d6faSchristos static const char *getshell(void); 51698d5317Sjmmv 52e9a2d6faSchristos static __dead void 53698d5317Sjmmv usage(void) 54698d5317Sjmmv { 55698d5317Sjmmv fprintf(stderr, 56f844e94eSwiz "usage: %s [-2CDlNuVv] [-c shell-command] [-f file] [-L socket-name]\n" 57e271dbb8Schristos " [-S socket-path] [-T features] [command [flags]]\n", 58e9a2d6faSchristos getprogname()); 59698d5317Sjmmv exit(1); 60698d5317Sjmmv } 61698d5317Sjmmv 62e9a2d6faSchristos static const char * 63698d5317Sjmmv getshell(void) 64698d5317Sjmmv { 65698d5317Sjmmv struct passwd *pw; 66698d5317Sjmmv const char *shell; 67698d5317Sjmmv 68698d5317Sjmmv shell = getenv("SHELL"); 69698d5317Sjmmv if (checkshell(shell)) 70698d5317Sjmmv return (shell); 71698d5317Sjmmv 72698d5317Sjmmv pw = getpwuid(getuid()); 73698d5317Sjmmv if (pw != NULL && checkshell(pw->pw_shell)) 74698d5317Sjmmv return (pw->pw_shell); 75698d5317Sjmmv 76698d5317Sjmmv return (_PATH_BSHELL); 77698d5317Sjmmv } 78698d5317Sjmmv 79e271dbb8Schristos int 80698d5317Sjmmv checkshell(const char *shell) 81698d5317Sjmmv { 82e9a2d6faSchristos if (shell == NULL || *shell != '/') 8361fba46bSchristos return (0); 8461fba46bSchristos if (areshell(shell)) 85698d5317Sjmmv return (0); 86698d5317Sjmmv if (access(shell, X_OK) != 0) 87698d5317Sjmmv return (0); 88698d5317Sjmmv return (1); 89698d5317Sjmmv } 90698d5317Sjmmv 91e271dbb8Schristos static int 92698d5317Sjmmv areshell(const char *shell) 93698d5317Sjmmv { 94698d5317Sjmmv const char *progname, *ptr; 95698d5317Sjmmv 96698d5317Sjmmv if ((ptr = strrchr(shell, '/')) != NULL) 97698d5317Sjmmv ptr++; 98698d5317Sjmmv else 99698d5317Sjmmv ptr = shell; 100e9a2d6faSchristos progname = getprogname(); 101698d5317Sjmmv if (*progname == '-') 102698d5317Sjmmv progname++; 103698d5317Sjmmv if (strcmp(ptr, progname) == 0) 104698d5317Sjmmv return (1); 105698d5317Sjmmv return (0); 106698d5317Sjmmv } 107698d5317Sjmmv 108f26e8bc9Schristos static char * 109e271dbb8Schristos expand_path(const char *path, const char *home) 110e271dbb8Schristos { 111e271dbb8Schristos char *expanded, *name; 112e271dbb8Schristos const char *end; 113e271dbb8Schristos struct environ_entry *value; 114e271dbb8Schristos 115e271dbb8Schristos if (strncmp(path, "~/", 2) == 0) { 116e271dbb8Schristos if (home == NULL) 117e271dbb8Schristos return (NULL); 118e271dbb8Schristos xasprintf(&expanded, "%s%s", home, path + 1); 119e271dbb8Schristos return (expanded); 120e271dbb8Schristos } 121e271dbb8Schristos 122e271dbb8Schristos if (*path == '$') { 123e271dbb8Schristos end = strchr(path, '/'); 124e271dbb8Schristos if (end == NULL) 125e271dbb8Schristos name = xstrdup(path + 1); 126e271dbb8Schristos else 127e271dbb8Schristos name = xstrndup(path + 1, end - path - 1); 128e271dbb8Schristos value = environ_find(global_environ, name); 129e271dbb8Schristos free(name); 130e271dbb8Schristos if (value == NULL) 131e271dbb8Schristos return (NULL); 132e271dbb8Schristos if (end == NULL) 133e271dbb8Schristos end = ""; 134e271dbb8Schristos xasprintf(&expanded, "%s%s", value->value, end); 135e271dbb8Schristos return (expanded); 136e271dbb8Schristos } 137e271dbb8Schristos 138e271dbb8Schristos return (xstrdup(path)); 139e271dbb8Schristos } 140e271dbb8Schristos 141e271dbb8Schristos static void 142e271dbb8Schristos expand_paths(const char *s, char ***paths, u_int *n, int ignore_errors) 143e271dbb8Schristos { 144e271dbb8Schristos const char *home = find_home(); 145e271dbb8Schristos char *copy, *next, *tmp, resolved[PATH_MAX], *expanded; 146e271dbb8Schristos char *path; 147e271dbb8Schristos u_int i; 148e271dbb8Schristos 149e271dbb8Schristos *paths = NULL; 150e271dbb8Schristos *n = 0; 151e271dbb8Schristos 152e271dbb8Schristos copy = tmp = xstrdup(s); 153e271dbb8Schristos while ((next = strsep(&tmp, ":")) != NULL) { 154e271dbb8Schristos expanded = expand_path(next, home); 155e271dbb8Schristos if (expanded == NULL) { 156e271dbb8Schristos log_debug("%s: invalid path: %s", __func__, next); 157e271dbb8Schristos continue; 158e271dbb8Schristos } 159e271dbb8Schristos if (realpath(expanded, resolved) == NULL) { 160e271dbb8Schristos log_debug("%s: realpath(\"%s\") failed: %s", __func__, 161e271dbb8Schristos expanded, strerror(errno)); 162e271dbb8Schristos if (ignore_errors) { 163e271dbb8Schristos free(expanded); 164e271dbb8Schristos continue; 165e271dbb8Schristos } 166e271dbb8Schristos path = expanded; 167e271dbb8Schristos } else { 168e271dbb8Schristos path = xstrdup(resolved); 169e271dbb8Schristos free(expanded); 170e271dbb8Schristos } 171e271dbb8Schristos for (i = 0; i < *n; i++) { 172e271dbb8Schristos if (strcmp(path, (*paths)[i]) == 0) 173e271dbb8Schristos break; 174e271dbb8Schristos } 175e271dbb8Schristos if (i != *n) { 176e271dbb8Schristos log_debug("%s: duplicate path: %s", __func__, path); 177e271dbb8Schristos free(path); 178e271dbb8Schristos continue; 179e271dbb8Schristos } 180e271dbb8Schristos *paths = xreallocarray(*paths, (*n) + 1, sizeof *paths); 181e271dbb8Schristos (*paths)[(*n)++] = path; 182e271dbb8Schristos } 183e271dbb8Schristos free(copy); 184e271dbb8Schristos } 185e271dbb8Schristos 186e271dbb8Schristos static char * 187c7e17de0Schristos make_label(const char *label, char **cause) 188698d5317Sjmmv { 189e271dbb8Schristos char **paths, *path, *base; 190e271dbb8Schristos u_int i, n; 191698d5317Sjmmv struct stat sb; 192e9a2d6faSchristos uid_t uid; 193c7e17de0Schristos 194c7e17de0Schristos *cause = NULL; 195f26e8bc9Schristos if (label == NULL) 196f26e8bc9Schristos label = "default"; 197698d5317Sjmmv uid = getuid(); 198f26e8bc9Schristos 199e271dbb8Schristos expand_paths(TMUX_SOCK, &paths, &n, 1); 200e271dbb8Schristos if (n == 0) { 201e271dbb8Schristos xasprintf(cause, "no suitable socket path"); 202e271dbb8Schristos return (NULL); 203c7e17de0Schristos } 204e271dbb8Schristos path = paths[0]; /* can only have one socket! */ 205e271dbb8Schristos for (i = 1; i < n; i++) 206e271dbb8Schristos free(paths[i]); 207e271dbb8Schristos free(paths); 208698d5317Sjmmv 209e271dbb8Schristos xasprintf(&base, "%s/tmux-%ld", path, (long)uid); 21046548964Swiz free(path); 21146548964Swiz if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) { 21246548964Swiz xasprintf(cause, "couldn't create directory %s (%s)", base, 21346548964Swiz strerror(errno)); 214c7e17de0Schristos goto fail; 21546548964Swiz } 21646548964Swiz if (lstat(base, &sb) != 0) { 21746548964Swiz xasprintf(cause, "couldn't read directory %s (%s)", base, 21846548964Swiz strerror(errno)); 219f26e8bc9Schristos goto fail; 22046548964Swiz } 221698d5317Sjmmv if (!S_ISDIR(sb.st_mode)) { 22246548964Swiz xasprintf(cause, "%s is not a directory", base); 223f26e8bc9Schristos goto fail; 224698d5317Sjmmv } 22599e242abSchristos if (sb.st_uid != uid || (sb.st_mode & S_IRWXO) != 0) { 22646548964Swiz xasprintf(cause, "directory %s has unsafe permissions", base); 227f26e8bc9Schristos goto fail; 228698d5317Sjmmv } 229e271dbb8Schristos xasprintf(&path, "%s/%s", base, label); 230e271dbb8Schristos free(base); 231698d5317Sjmmv return (path); 232f26e8bc9Schristos 233f26e8bc9Schristos fail: 234e271dbb8Schristos free(base); 235f26e8bc9Schristos return (NULL); 236698d5317Sjmmv } 237698d5317Sjmmv 238*890b6d91Swiz char * 239*890b6d91Swiz shell_argv0(const char *shell, int is_login) 240*890b6d91Swiz { 241*890b6d91Swiz const char *slash, *name; 242*890b6d91Swiz char *argv0; 243*890b6d91Swiz 244*890b6d91Swiz slash = strrchr(shell, '/'); 245*890b6d91Swiz if (slash != NULL && slash[1] != '\0') 246*890b6d91Swiz name = slash + 1; 247*890b6d91Swiz else 248*890b6d91Swiz name = shell; 249*890b6d91Swiz if (is_login) 250*890b6d91Swiz xasprintf(&argv0, "-%s", name); 251*890b6d91Swiz else 252*890b6d91Swiz xasprintf(&argv0, "%s", name); 253*890b6d91Swiz return (argv0); 254*890b6d91Swiz } 255*890b6d91Swiz 256d530c4d0Sjmmv void 257d530c4d0Sjmmv setblocking(int fd, int state) 258d530c4d0Sjmmv { 259d530c4d0Sjmmv int mode; 260d530c4d0Sjmmv 261d530c4d0Sjmmv if ((mode = fcntl(fd, F_GETFL)) != -1) { 262d530c4d0Sjmmv if (!state) 263d530c4d0Sjmmv mode |= O_NONBLOCK; 264d530c4d0Sjmmv else 265d530c4d0Sjmmv mode &= ~O_NONBLOCK; 266d530c4d0Sjmmv fcntl(fd, F_SETFL, mode); 267d530c4d0Sjmmv } 268d530c4d0Sjmmv } 269d530c4d0Sjmmv 270e271dbb8Schristos uint64_t 271e271dbb8Schristos get_timer(void) 272e271dbb8Schristos { 273e271dbb8Schristos struct timespec ts; 274e271dbb8Schristos 275e271dbb8Schristos /* 276e271dbb8Schristos * We want a timestamp in milliseconds suitable for time measurement, 277e271dbb8Schristos * so prefer the monotonic clock. 278e271dbb8Schristos */ 279e271dbb8Schristos if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 280e271dbb8Schristos clock_gettime(CLOCK_REALTIME, &ts); 281e271dbb8Schristos return ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL)); 282e271dbb8Schristos } 283e271dbb8Schristos 284e271dbb8Schristos const char * 285e271dbb8Schristos sig2name(int signo) 286e271dbb8Schristos { 287e271dbb8Schristos static char s[11]; 288e271dbb8Schristos 289e271dbb8Schristos #ifdef HAVE_SYS_SIGNAME 290e271dbb8Schristos if (signo > 0 && signo < NSIG) 291e271dbb8Schristos return (sys_signame[signo]); 292e271dbb8Schristos #endif 293e271dbb8Schristos xsnprintf(s, sizeof s, "%d", signo); 294e271dbb8Schristos return (s); 295e271dbb8Schristos } 296e271dbb8Schristos 29799e242abSchristos const char * 2980a274e86Schristos find_cwd(void) 2990a274e86Schristos { 3000a274e86Schristos char resolved1[PATH_MAX], resolved2[PATH_MAX]; 3010a274e86Schristos static char cwd[PATH_MAX]; 3020a274e86Schristos const char *pwd; 3030a274e86Schristos 3040a274e86Schristos if (getcwd(cwd, sizeof cwd) == NULL) 3050a274e86Schristos return (NULL); 3060a274e86Schristos if ((pwd = getenv("PWD")) == NULL || *pwd == '\0') 3070a274e86Schristos return (cwd); 3080a274e86Schristos 3090a274e86Schristos /* 3100a274e86Schristos * We want to use PWD so that symbolic links are maintained, 3110a274e86Schristos * but only if it matches the actual working directory. 3120a274e86Schristos */ 3130a274e86Schristos if (realpath(pwd, resolved1) == NULL) 3140a274e86Schristos return (cwd); 3150a274e86Schristos if (realpath(cwd, resolved2) == NULL) 3160a274e86Schristos return (cwd); 3170a274e86Schristos if (strcmp(resolved1, resolved2) != 0) 3180a274e86Schristos return (cwd); 3190a274e86Schristos return (pwd); 3200a274e86Schristos } 3210a274e86Schristos 3220a274e86Schristos const char * 32399e242abSchristos find_home(void) 324698d5317Sjmmv { 32599e242abSchristos struct passwd *pw; 32699e242abSchristos static const char *home; 327698d5317Sjmmv 32899e242abSchristos if (home != NULL) 32999e242abSchristos return (home); 33099e242abSchristos 33199e242abSchristos home = getenv("HOME"); 33299e242abSchristos if (home == NULL || *home == '\0') { 33399e242abSchristos pw = getpwuid(getuid()); 33499e242abSchristos if (pw != NULL) 33599e242abSchristos home = pw->pw_dir; 336698d5317Sjmmv else 33799e242abSchristos home = NULL; 33899e242abSchristos } 339698d5317Sjmmv 34099e242abSchristos return (home); 341698d5317Sjmmv } 342698d5317Sjmmv 34368e6ba84Schristos const char * 34468e6ba84Schristos getversion(void) 34568e6ba84Schristos { 34646548964Swiz return (TMUX_VERSION); 34768e6ba84Schristos } 34868e6ba84Schristos 349698d5317Sjmmv int 350698d5317Sjmmv main(int argc, char **argv) 351698d5317Sjmmv { 352e271dbb8Schristos char *path = NULL, *label = NULL; 353e271dbb8Schristos char *cause, **var; 354e271dbb8Schristos const char *s, *cwd; 35559b94b2cSchristos int opt, keys, feat = 0, fflag = 0; 356e271dbb8Schristos uint64_t flags = 0; 357e9a2d6faSchristos const struct options_table_entry *oe; 358e271dbb8Schristos u_int i; 359698d5317Sjmmv 360fe99a117Schristos if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL && 361fe99a117Schristos setlocale(LC_CTYPE, "C.UTF-8") == NULL) { 362f26e8bc9Schristos if (setlocale(LC_CTYPE, "") == NULL) 363f26e8bc9Schristos errx(1, "invalid LC_ALL, LC_CTYPE or LANG"); 364f26e8bc9Schristos s = nl_langinfo(CODESET); 365e9a2d6faSchristos if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0) 366f26e8bc9Schristos errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s); 367f26e8bc9Schristos } 368698d5317Sjmmv 36961fba46bSchristos setlocale(LC_TIME, ""); 37099e242abSchristos tzset(); 37161fba46bSchristos 37299e242abSchristos if (**argv == '-') 37399e242abSchristos flags = CLIENT_LOGIN; 37499e242abSchristos 375e271dbb8Schristos global_environ = environ_create(); 376e271dbb8Schristos for (var = environ; *var != NULL; var++) 377e271dbb8Schristos environ_put(global_environ, *var, 0); 378e271dbb8Schristos if ((cwd = find_cwd()) != NULL) 379e271dbb8Schristos environ_set(global_environ, "PWD", 0, "%s", cwd); 380e271dbb8Schristos expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1); 381e271dbb8Schristos 382e271dbb8Schristos while ((opt = getopt(argc, argv, "2c:CDdf:lL:NqS:T:uUvV")) != -1) { 383698d5317Sjmmv switch (opt) { 384698d5317Sjmmv case '2': 385e271dbb8Schristos tty_add_features(&feat, "256", ":,"); 386698d5317Sjmmv break; 387698d5317Sjmmv case 'c': 388fe99a117Schristos shell_command = optarg; 389698d5317Sjmmv break; 390e271dbb8Schristos case 'D': 391e271dbb8Schristos flags |= CLIENT_NOFORK; 392e271dbb8Schristos break; 39361fba46bSchristos case 'C': 39461fba46bSchristos if (flags & CLIENT_CONTROL) 39561fba46bSchristos flags |= CLIENT_CONTROLCONTROL; 39661fba46bSchristos else 39761fba46bSchristos flags |= CLIENT_CONTROL; 39861fba46bSchristos break; 399698d5317Sjmmv case 'f': 40059b94b2cSchristos if (!fflag) { 40159b94b2cSchristos fflag = 1; 402e271dbb8Schristos for (i = 0; i < cfg_nfiles; i++) 403e271dbb8Schristos free(cfg_files[i]); 40459b94b2cSchristos cfg_nfiles = 0; 40559b94b2cSchristos } 40659b94b2cSchristos cfg_files = xreallocarray(cfg_files, cfg_nfiles + 1, 40759b94b2cSchristos sizeof *cfg_files); 40859b94b2cSchristos cfg_files[cfg_nfiles++] = xstrdup(optarg); 409e271dbb8Schristos cfg_quiet = 0; 410698d5317Sjmmv break; 41168e6ba84Schristos case 'V': 412f844e94eSwiz printf("tmux %s\n", getversion()); 41368e6ba84Schristos exit(0); 414698d5317Sjmmv case 'l': 41599e242abSchristos flags |= CLIENT_LOGIN; 416698d5317Sjmmv break; 417698d5317Sjmmv case 'L': 41861fba46bSchristos free(label); 419698d5317Sjmmv label = xstrdup(optarg); 420698d5317Sjmmv break; 421e271dbb8Schristos case 'N': 422e271dbb8Schristos flags |= CLIENT_NOSTARTSERVER; 423e271dbb8Schristos break; 424698d5317Sjmmv case 'q': 425698d5317Sjmmv break; 426698d5317Sjmmv case 'S': 42761fba46bSchristos free(path); 428698d5317Sjmmv path = xstrdup(optarg); 429698d5317Sjmmv break; 430e271dbb8Schristos case 'T': 431e271dbb8Schristos tty_add_features(&feat, optarg, ":,"); 432e271dbb8Schristos break; 433698d5317Sjmmv case 'u': 43461fba46bSchristos flags |= CLIENT_UTF8; 435698d5317Sjmmv break; 436698d5317Sjmmv case 'v': 437f26e8bc9Schristos log_add_level(); 438698d5317Sjmmv break; 439698d5317Sjmmv default: 440698d5317Sjmmv usage(); 441698d5317Sjmmv } 442698d5317Sjmmv } 443698d5317Sjmmv argc -= optind; 444698d5317Sjmmv argv += optind; 445698d5317Sjmmv 446fe99a117Schristos if (shell_command != NULL && argc != 0) 447698d5317Sjmmv usage(); 448e271dbb8Schristos if ((flags & CLIENT_NOFORK) && argc != 0) 449e271dbb8Schristos usage(); 450698d5317Sjmmv 451fe99a117Schristos if ((ptm_fd = getptmfd()) == -1) 452fe99a117Schristos err(1, "getptmfd"); 453f26e8bc9Schristos if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd " 454f26e8bc9Schristos "recvfd proc exec tty ps", NULL) != 0) 455f26e8bc9Schristos err(1, "pledge"); 456698d5317Sjmmv 457698d5317Sjmmv /* 458f26e8bc9Schristos * tmux is a UTF-8 terminal, so if TMUX is set, assume UTF-8. 459f26e8bc9Schristos * Otherwise, if the user has set LC_ALL, LC_CTYPE or LANG to contain 460f26e8bc9Schristos * UTF-8, it is a safe assumption that either they are using a UTF-8 461f26e8bc9Schristos * terminal, or if not they know that output from UTF-8-capable 462f26e8bc9Schristos * programs may be wrong. 463698d5317Sjmmv */ 464f26e8bc9Schristos if (getenv("TMUX") != NULL) 465f26e8bc9Schristos flags |= CLIENT_UTF8; 466f26e8bc9Schristos else { 467f26e8bc9Schristos s = getenv("LC_ALL"); 468f26e8bc9Schristos if (s == NULL || *s == '\0') 469f26e8bc9Schristos s = getenv("LC_CTYPE"); 470f26e8bc9Schristos if (s == NULL || *s == '\0') 471698d5317Sjmmv s = getenv("LANG"); 472f26e8bc9Schristos if (s == NULL || *s == '\0') 473f26e8bc9Schristos s = ""; 474f26e8bc9Schristos if (strcasestr(s, "UTF-8") != NULL || 475f26e8bc9Schristos strcasestr(s, "UTF8") != NULL) 47661fba46bSchristos flags |= CLIENT_UTF8; 477698d5317Sjmmv } 478698d5317Sjmmv 479f26e8bc9Schristos global_options = options_create(NULL); 480f26e8bc9Schristos global_s_options = options_create(NULL); 481f26e8bc9Schristos global_w_options = options_create(NULL); 482e9a2d6faSchristos for (oe = options_table; oe->name != NULL; oe++) { 48330744affSchristos if (oe->scope & OPTIONS_TABLE_SERVER) 484e9a2d6faSchristos options_default(global_options, oe); 48530744affSchristos if (oe->scope & OPTIONS_TABLE_SESSION) 486e9a2d6faSchristos options_default(global_s_options, oe); 48730744affSchristos if (oe->scope & OPTIONS_TABLE_WINDOW) 488e9a2d6faSchristos options_default(global_w_options, oe); 489e9a2d6faSchristos } 490e9a2d6faSchristos 491e9a2d6faSchristos /* 492e9a2d6faSchristos * The default shell comes from SHELL or from the user's passwd entry 493e9a2d6faSchristos * if available. 494e9a2d6faSchristos */ 495e271dbb8Schristos options_set_string(global_s_options, "default-shell", 0, "%s", 496e271dbb8Schristos getshell()); 497698d5317Sjmmv 498d530c4d0Sjmmv /* Override keys to vi if VISUAL or EDITOR are set. */ 499698d5317Sjmmv if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) { 500e271dbb8Schristos options_set_string(global_options, "editor", 0, "%s", s); 501698d5317Sjmmv if (strrchr(s, '/') != NULL) 502698d5317Sjmmv s = strrchr(s, '/') + 1; 503698d5317Sjmmv if (strstr(s, "vi") != NULL) 504698d5317Sjmmv keys = MODEKEY_VI; 505d530c4d0Sjmmv else 506d530c4d0Sjmmv keys = MODEKEY_EMACS; 507f26e8bc9Schristos options_set_number(global_s_options, "status-keys", keys); 508f26e8bc9Schristos options_set_number(global_w_options, "mode-keys", keys); 509698d5317Sjmmv } 510698d5317Sjmmv 511698d5317Sjmmv /* 512f26e8bc9Schristos * If socket is specified on the command-line with -S or -L, it is 513f26e8bc9Schristos * used. Otherwise, $TMUX is checked and if that fails "default" is 514f26e8bc9Schristos * used. 515698d5317Sjmmv */ 516f26e8bc9Schristos if (path == NULL && label == NULL) { 51799e242abSchristos s = getenv("TMUX"); 518f26e8bc9Schristos if (s != NULL && *s != '\0' && *s != ',') { 51999e242abSchristos path = xstrdup(s); 52099e242abSchristos path[strcspn(path, ",")] = '\0'; 52199e242abSchristos } 522698d5317Sjmmv } 523e271dbb8Schristos if (path == NULL) { 524e271dbb8Schristos if ((path = make_label(label, &cause)) == NULL) { 525c7e17de0Schristos if (cause != NULL) { 526c7e17de0Schristos fprintf(stderr, "%s\n", cause); 527c7e17de0Schristos free(cause); 528c7e17de0Schristos } 529698d5317Sjmmv exit(1); 530698d5317Sjmmv } 531e271dbb8Schristos flags |= CLIENT_DEFAULTSOCKET; 532e271dbb8Schristos } 533f26e8bc9Schristos socket_path = path; 53461fba46bSchristos free(label); 53561fba46bSchristos 536698d5317Sjmmv /* Pass control to the client. */ 537e271dbb8Schristos exit(client_main(osdep_event_init(), argc, argv, flags, feat)); 538698d5317Sjmmv } 539