Home | History | Annotate | Line # | Download | only in dist
tmux.c revision 1.13.2.1
      1       1.4  christos /* $OpenBSD$ */
      2       1.1      jmmv 
      3       1.1      jmmv /*
      4       1.5  christos  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5       1.1      jmmv  *
      6       1.1      jmmv  * Permission to use, copy, modify, and distribute this software for any
      7       1.1      jmmv  * purpose with or without fee is hereby granted, provided that the above
      8       1.1      jmmv  * copyright notice and this permission notice appear in all copies.
      9       1.1      jmmv  *
     10       1.1      jmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11       1.1      jmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12       1.1      jmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13       1.1      jmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14       1.1      jmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15       1.1      jmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16       1.1      jmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17       1.1      jmmv  */
     18       1.1      jmmv 
     19       1.1      jmmv #include <sys/types.h>
     20       1.1      jmmv #include <sys/stat.h>
     21      1.11  christos #include <sys/utsname.h>
     22       1.1      jmmv 
     23       1.1      jmmv #include <errno.h>
     24       1.1      jmmv #include <fcntl.h>
     25       1.5  christos #include <langinfo.h>
     26       1.3  christos #include <locale.h>
     27       1.1      jmmv #include <pwd.h>
     28      1.12  christos #include <signal.h>
     29       1.1      jmmv #include <stdlib.h>
     30       1.1      jmmv #include <string.h>
     31       1.4  christos #include <time.h>
     32       1.1      jmmv #include <unistd.h>
     33       1.1      jmmv 
     34       1.1      jmmv #include "tmux.h"
     35       1.1      jmmv 
     36       1.5  christos struct options	*global_options;	/* server options */
     37       1.5  christos struct options	*global_s_options;	/* session options */
     38       1.5  christos struct options	*global_w_options;	/* window options */
     39       1.5  christos struct environ	*global_environ;
     40       1.1      jmmv 
     41       1.5  christos struct timeval	 start_time;
     42       1.5  christos const char	*socket_path;
     43       1.6  christos int		 ptm_fd = -1;
     44       1.7  christos const char	*shell_command;
     45       1.1      jmmv 
     46  1.13.2.1    martin static __dead void	 usage(int);
     47       1.8  christos static char		*make_label(const char *, char **);
     48       1.1      jmmv 
     49      1.12  christos static int		 areshell(const char *);
     50       1.6  christos static const char	*getshell(void);
     51       1.1      jmmv 
     52       1.6  christos static __dead void
     53  1.13.2.1    martin usage(int status)
     54       1.1      jmmv {
     55  1.13.2.1    martin 	fprintf(status ? stderr : stdout,
     56  1.13.2.1    martin 	    "usage: %s [-2CDhlNuVv] [-c shell-command] [-f file] [-L socket-name]\n"
     57      1.12  christos 	    "            [-S socket-path] [-T features] [command [flags]]\n",
     58       1.6  christos 	    getprogname());
     59  1.13.2.1    martin 	exit(status);
     60       1.1      jmmv }
     61       1.1      jmmv 
     62       1.6  christos static const char *
     63       1.1      jmmv getshell(void)
     64       1.1      jmmv {
     65       1.1      jmmv 	struct passwd	*pw;
     66       1.1      jmmv 	const char	*shell;
     67       1.1      jmmv 
     68       1.1      jmmv 	shell = getenv("SHELL");
     69       1.1      jmmv 	if (checkshell(shell))
     70       1.1      jmmv 		return (shell);
     71       1.1      jmmv 
     72       1.1      jmmv 	pw = getpwuid(getuid());
     73       1.1      jmmv 	if (pw != NULL && checkshell(pw->pw_shell))
     74       1.1      jmmv 		return (pw->pw_shell);
     75       1.1      jmmv 
     76       1.1      jmmv 	return (_PATH_BSHELL);
     77       1.1      jmmv }
     78       1.1      jmmv 
     79      1.12  christos int
     80       1.1      jmmv checkshell(const char *shell)
     81       1.1      jmmv {
     82       1.6  christos 	if (shell == NULL || *shell != '/')
     83       1.3  christos 		return (0);
     84       1.3  christos 	if (areshell(shell))
     85       1.1      jmmv 		return (0);
     86       1.1      jmmv 	if (access(shell, X_OK) != 0)
     87       1.1      jmmv 		return (0);
     88       1.1      jmmv 	return (1);
     89       1.1      jmmv }
     90       1.1      jmmv 
     91      1.12  christos static int
     92       1.1      jmmv areshell(const char *shell)
     93       1.1      jmmv {
     94       1.1      jmmv 	const char	*progname, *ptr;
     95       1.1      jmmv 
     96       1.1      jmmv 	if ((ptr = strrchr(shell, '/')) != NULL)
     97       1.1      jmmv 		ptr++;
     98       1.1      jmmv 	else
     99       1.1      jmmv 		ptr = shell;
    100       1.6  christos 	progname = getprogname();
    101       1.1      jmmv 	if (*progname == '-')
    102       1.1      jmmv 		progname++;
    103       1.1      jmmv 	if (strcmp(ptr, progname) == 0)
    104       1.1      jmmv 		return (1);
    105       1.1      jmmv 	return (0);
    106       1.1      jmmv }
    107       1.1      jmmv 
    108       1.5  christos static char *
    109      1.12  christos expand_path(const char *path, const char *home)
    110      1.12  christos {
    111      1.12  christos 	char			*expanded, *name;
    112      1.12  christos 	const char		*end;
    113      1.12  christos 	struct environ_entry	*value;
    114      1.12  christos 
    115      1.12  christos 	if (strncmp(path, "~/", 2) == 0) {
    116      1.12  christos 		if (home == NULL)
    117      1.12  christos 			return (NULL);
    118      1.12  christos 		xasprintf(&expanded, "%s%s", home, path + 1);
    119      1.12  christos 		return (expanded);
    120      1.12  christos 	}
    121      1.12  christos 
    122      1.12  christos 	if (*path == '$') {
    123      1.12  christos 		end = strchr(path, '/');
    124      1.12  christos 		if (end == NULL)
    125      1.12  christos 			name = xstrdup(path + 1);
    126      1.12  christos 		else
    127      1.12  christos 			name = xstrndup(path + 1, end - path - 1);
    128      1.12  christos 		value = environ_find(global_environ, name);
    129      1.12  christos 		free(name);
    130      1.12  christos 		if (value == NULL)
    131      1.12  christos 			return (NULL);
    132      1.12  christos 		if (end == NULL)
    133      1.12  christos 			end = "";
    134      1.12  christos 		xasprintf(&expanded, "%s%s", value->value, end);
    135      1.12  christos 		return (expanded);
    136      1.12  christos 	}
    137      1.12  christos 
    138      1.12  christos 	return (xstrdup(path));
    139      1.12  christos }
    140      1.12  christos 
    141      1.12  christos static void
    142  1.13.2.1    martin expand_paths(const char *s, char ***paths, u_int *n, int no_realpath)
    143      1.12  christos {
    144      1.12  christos 	const char	*home = find_home();
    145      1.12  christos 	char		*copy, *next, *tmp, resolved[PATH_MAX], *expanded;
    146      1.12  christos 	char		*path;
    147      1.12  christos 	u_int		 i;
    148      1.12  christos 
    149      1.12  christos 	*paths = NULL;
    150      1.12  christos 	*n = 0;
    151      1.12  christos 
    152      1.12  christos 	copy = tmp = xstrdup(s);
    153      1.12  christos 	while ((next = strsep(&tmp, ":")) != NULL) {
    154      1.12  christos 		expanded = expand_path(next, home);
    155      1.12  christos 		if (expanded == NULL) {
    156      1.12  christos 			log_debug("%s: invalid path: %s", __func__, next);
    157      1.12  christos 			continue;
    158      1.12  christos 		}
    159  1.13.2.1    martin 		if (no_realpath)
    160  1.13.2.1    martin 			path = expanded;
    161  1.13.2.1    martin 		else {
    162  1.13.2.1    martin 			if (realpath(expanded, resolved) == NULL) {
    163  1.13.2.1    martin 				log_debug("%s: realpath(\"%s\") failed: %s", __func__,
    164  1.13.2.1    martin 			  expanded, strerror(errno));
    165      1.12  christos 				free(expanded);
    166      1.12  christos 				continue;
    167      1.12  christos 			}
    168      1.12  christos 			path = xstrdup(resolved);
    169      1.12  christos 			free(expanded);
    170      1.12  christos 		}
    171      1.12  christos 		for (i = 0; i < *n; i++) {
    172      1.12  christos 			if (strcmp(path, (*paths)[i]) == 0)
    173      1.12  christos 				break;
    174      1.12  christos 		}
    175      1.12  christos 		if (i != *n) {
    176      1.12  christos 			log_debug("%s: duplicate path: %s", __func__, path);
    177      1.12  christos 			free(path);
    178      1.12  christos 			continue;
    179      1.12  christos 		}
    180      1.12  christos 		*paths = xreallocarray(*paths, (*n) + 1, sizeof *paths);
    181      1.12  christos 		(*paths)[(*n)++] = path;
    182      1.12  christos 	}
    183      1.12  christos 	free(copy);
    184      1.12  christos }
    185      1.12  christos 
    186      1.12  christos static char *
    187       1.8  christos make_label(const char *label, char **cause)
    188       1.1      jmmv {
    189      1.12  christos 	char		**paths, *path, *base;
    190      1.12  christos 	u_int		  i, n;
    191      1.12  christos 	struct stat	  sb;
    192      1.12  christos 	uid_t		  uid;
    193       1.8  christos 
    194       1.8  christos 	*cause = NULL;
    195       1.5  christos 	if (label == NULL)
    196       1.5  christos 		label = "default";
    197       1.1      jmmv 	uid = getuid();
    198       1.5  christos 
    199  1.13.2.1    martin 	expand_paths(TMUX_SOCK, &paths, &n, 0);
    200      1.12  christos 	if (n == 0) {
    201      1.12  christos 		xasprintf(cause, "no suitable socket path");
    202      1.12  christos 		return (NULL);
    203       1.8  christos 	}
    204      1.12  christos 	path = paths[0]; /* can only have one socket! */
    205      1.12  christos 	for (i = 1; i < n; i++)
    206      1.12  christos 		free(paths[i]);
    207      1.12  christos 	free(paths);
    208       1.1      jmmv 
    209      1.12  christos 	xasprintf(&base, "%s/tmux-%ld", path, (long)uid);
    210  1.13.2.1    martin 	free(path);
    211  1.13.2.1    martin 	if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) {
    212  1.13.2.1    martin 		xasprintf(cause, "couldn't create directory %s (%s)", base,
    213  1.13.2.1    martin 		    strerror(errno));
    214       1.5  christos 		goto fail;
    215  1.13.2.1    martin 	}
    216  1.13.2.1    martin 	if (lstat(base, &sb) != 0) {
    217  1.13.2.1    martin 		xasprintf(cause, "couldn't read directory %s (%s)", base,
    218  1.13.2.1    martin 		    strerror(errno));
    219       1.5  christos 		goto fail;
    220  1.13.2.1    martin 	}
    221       1.1      jmmv 	if (!S_ISDIR(sb.st_mode)) {
    222  1.13.2.1    martin 		xasprintf(cause, "%s is not a directory", base);
    223       1.5  christos 		goto fail;
    224       1.1      jmmv 	}
    225  1.13.2.1    martin 	if (sb.st_uid != uid || (sb.st_mode & TMUX_SOCK_PERM) != 0) {
    226  1.13.2.1    martin 		xasprintf(cause, "directory %s has unsafe permissions", base);
    227       1.5  christos 		goto fail;
    228       1.1      jmmv 	}
    229      1.12  christos 	xasprintf(&path, "%s/%s", base, label);
    230      1.12  christos 	free(base);
    231       1.5  christos 	return (path);
    232       1.3  christos 
    233       1.5  christos fail:
    234      1.12  christos 	free(base);
    235       1.5  christos 	return (NULL);
    236       1.1      jmmv }
    237       1.1      jmmv 
    238  1.13.2.1    martin char *
    239  1.13.2.1    martin shell_argv0(const char *shell, int is_login)
    240  1.13.2.1    martin {
    241  1.13.2.1    martin 	const char	*slash, *name;
    242  1.13.2.1    martin 	char		*argv0;
    243  1.13.2.1    martin 
    244  1.13.2.1    martin 	slash = strrchr(shell, '/');
    245  1.13.2.1    martin 	if (slash != NULL && slash[1] != '\0')
    246  1.13.2.1    martin 		name = slash + 1;
    247  1.13.2.1    martin 	else
    248  1.13.2.1    martin 		name = shell;
    249  1.13.2.1    martin 	if (is_login)
    250  1.13.2.1    martin 		xasprintf(&argv0, "-%s", name);
    251  1.13.2.1    martin 	else
    252  1.13.2.1    martin 		xasprintf(&argv0, "%s", name);
    253  1.13.2.1    martin 	return (argv0);
    254  1.13.2.1    martin }
    255  1.13.2.1    martin 
    256       1.2    martin void
    257       1.2    martin setblocking(int fd, int state)
    258       1.2    martin {
    259       1.2    martin 	int mode;
    260       1.2    martin 
    261       1.2    martin 	if ((mode = fcntl(fd, F_GETFL)) != -1) {
    262       1.2    martin 		if (!state)
    263       1.2    martin 			mode |= O_NONBLOCK;
    264       1.2    martin 		else
    265       1.2    martin 			mode &= ~O_NONBLOCK;
    266       1.2    martin 		fcntl(fd, F_SETFL, mode);
    267       1.2    martin 	}
    268       1.2    martin }
    269       1.2    martin 
    270      1.12  christos uint64_t
    271      1.12  christos get_timer(void)
    272      1.12  christos {
    273      1.12  christos 	struct timespec	ts;
    274      1.12  christos 
    275      1.12  christos 	/*
    276      1.12  christos 	 * We want a timestamp in milliseconds suitable for time measurement,
    277      1.12  christos 	 * so prefer the monotonic clock.
    278      1.12  christos 	 */
    279      1.12  christos 	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
    280      1.12  christos 		clock_gettime(CLOCK_REALTIME, &ts);
    281      1.12  christos 	return ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL));
    282      1.12  christos }
    283      1.12  christos 
    284      1.12  christos const char *
    285      1.12  christos sig2name(int signo)
    286      1.12  christos {
    287      1.12  christos      static char	s[11];
    288      1.12  christos 
    289      1.12  christos #ifdef HAVE_SYS_SIGNAME
    290      1.12  christos      if (signo > 0 && signo < NSIG)
    291      1.12  christos 	     return (sys_signame[signo]);
    292      1.12  christos #endif
    293      1.12  christos      xsnprintf(s, sizeof s, "%d", signo);
    294      1.12  christos      return (s);
    295      1.12  christos }
    296      1.12  christos 
    297       1.4  christos const char *
    298       1.9  christos find_cwd(void)
    299       1.9  christos {
    300       1.9  christos 	char		 resolved1[PATH_MAX], resolved2[PATH_MAX];
    301       1.9  christos 	static char	 cwd[PATH_MAX];
    302       1.9  christos 	const char	*pwd;
    303       1.9  christos 
    304       1.9  christos 	if (getcwd(cwd, sizeof cwd) == NULL)
    305       1.9  christos 		return (NULL);
    306       1.9  christos 	if ((pwd = getenv("PWD")) == NULL || *pwd == '\0')
    307       1.9  christos 		return (cwd);
    308       1.9  christos 
    309       1.9  christos 	/*
    310       1.9  christos 	 * We want to use PWD so that symbolic links are maintained,
    311       1.9  christos 	 * but only if it matches the actual working directory.
    312       1.9  christos 	 */
    313       1.9  christos 	if (realpath(pwd, resolved1) == NULL)
    314       1.9  christos 		return (cwd);
    315       1.9  christos 	if (realpath(cwd, resolved2) == NULL)
    316       1.9  christos 		return (cwd);
    317       1.9  christos 	if (strcmp(resolved1, resolved2) != 0)
    318       1.9  christos 		return (cwd);
    319       1.9  christos 	return (pwd);
    320       1.9  christos }
    321       1.9  christos 
    322       1.9  christos const char *
    323       1.4  christos find_home(void)
    324       1.1      jmmv {
    325       1.4  christos 	struct passwd		*pw;
    326       1.4  christos 	static const char	*home;
    327       1.1      jmmv 
    328       1.4  christos 	if (home != NULL)
    329       1.4  christos 		return (home);
    330       1.1      jmmv 
    331       1.4  christos 	home = getenv("HOME");
    332       1.4  christos 	if (home == NULL || *home == '\0') {
    333       1.4  christos 		pw = getpwuid(getuid());
    334       1.4  christos 		if (pw != NULL)
    335       1.4  christos 			home = pw->pw_dir;
    336       1.4  christos 		else
    337       1.4  christos 			home = NULL;
    338       1.4  christos 	}
    339       1.1      jmmv 
    340       1.4  christos 	return (home);
    341       1.1      jmmv }
    342       1.1      jmmv 
    343      1.11  christos const char *
    344      1.11  christos getversion(void)
    345      1.11  christos {
    346  1.13.2.1    martin 	return (TMUX_VERSION);
    347      1.11  christos }
    348      1.11  christos 
    349       1.1      jmmv int
    350       1.1      jmmv main(int argc, char **argv)
    351       1.1      jmmv {
    352      1.12  christos 	char					*path = NULL, *label = NULL;
    353      1.12  christos 	char					*cause, **var;
    354      1.12  christos 	const char				*s, *cwd;
    355      1.13  christos 	int					 opt, keys, feat = 0, fflag = 0;
    356      1.12  christos 	uint64_t				 flags = 0;
    357       1.6  christos 	const struct options_table_entry	*oe;
    358      1.12  christos 	u_int					 i;
    359       1.5  christos 
    360       1.7  christos 	if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL &&
    361       1.7  christos 	    setlocale(LC_CTYPE, "C.UTF-8") == NULL) {
    362       1.5  christos 		if (setlocale(LC_CTYPE, "") == NULL)
    363       1.5  christos 			errx(1, "invalid LC_ALL, LC_CTYPE or LANG");
    364       1.5  christos 		s = nl_langinfo(CODESET);
    365       1.6  christos 		if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0)
    366       1.5  christos 			errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s);
    367       1.5  christos 	}
    368       1.1      jmmv 
    369       1.3  christos 	setlocale(LC_TIME, "");
    370       1.4  christos 	tzset();
    371       1.4  christos 
    372       1.4  christos 	if (**argv == '-')
    373       1.4  christos 		flags = CLIENT_LOGIN;
    374       1.3  christos 
    375      1.12  christos 	global_environ = environ_create();
    376      1.12  christos 	for (var = environ; *var != NULL; var++)
    377      1.12  christos 		environ_put(global_environ, *var, 0);
    378      1.12  christos 	if ((cwd = find_cwd()) != NULL)
    379      1.12  christos 		environ_set(global_environ, "PWD", 0, "%s", cwd);
    380      1.12  christos 	expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1);
    381      1.12  christos 
    382  1.13.2.1    martin 	while ((opt = getopt(argc, argv, "2c:CDdf:hlL:NqS:T:uUvV")) != -1) {
    383       1.1      jmmv 		switch (opt) {
    384       1.1      jmmv 		case '2':
    385      1.12  christos 			tty_add_features(&feat, "256", ":,");
    386       1.1      jmmv 			break;
    387       1.1      jmmv 		case 'c':
    388       1.7  christos 			shell_command = optarg;
    389       1.1      jmmv 			break;
    390      1.12  christos 		case 'D':
    391      1.12  christos 			flags |= CLIENT_NOFORK;
    392      1.12  christos 			break;
    393       1.3  christos 		case 'C':
    394       1.3  christos 			if (flags & CLIENT_CONTROL)
    395       1.3  christos 				flags |= CLIENT_CONTROLCONTROL;
    396       1.3  christos 			else
    397       1.3  christos 				flags |= CLIENT_CONTROL;
    398       1.3  christos 			break;
    399       1.1      jmmv 		case 'f':
    400      1.13  christos 			if (!fflag) {
    401      1.13  christos 				fflag = 1;
    402      1.13  christos 				for (i = 0; i < cfg_nfiles; i++)
    403      1.13  christos 					free(cfg_files[i]);
    404      1.13  christos 				cfg_nfiles = 0;
    405      1.13  christos 			}
    406      1.13  christos 			cfg_files = xreallocarray(cfg_files, cfg_nfiles + 1,
    407      1.13  christos 			    sizeof *cfg_files);
    408      1.13  christos 			cfg_files[cfg_nfiles++] = xstrdup(optarg);
    409      1.12  christos 			cfg_quiet = 0;
    410       1.1      jmmv 			break;
    411  1.13.2.1    martin 		case 'h':
    412  1.13.2.1    martin 			usage(0);
    413  1.13.2.1    martin 		case 'V':
    414  1.13.2.1    martin 			printf("tmux %s\n", getversion());
    415  1.13.2.1    martin 			exit(0);
    416       1.1      jmmv 		case 'l':
    417       1.4  christos 			flags |= CLIENT_LOGIN;
    418       1.1      jmmv 			break;
    419       1.1      jmmv 		case 'L':
    420       1.3  christos 			free(label);
    421       1.1      jmmv 			label = xstrdup(optarg);
    422       1.1      jmmv 			break;
    423      1.12  christos 		case 'N':
    424      1.12  christos 			flags |= CLIENT_NOSTARTSERVER;
    425      1.12  christos 			break;
    426       1.1      jmmv 		case 'q':
    427       1.1      jmmv 			break;
    428       1.1      jmmv 		case 'S':
    429       1.3  christos 			free(path);
    430       1.1      jmmv 			path = xstrdup(optarg);
    431       1.1      jmmv 			break;
    432      1.12  christos 		case 'T':
    433      1.12  christos 			tty_add_features(&feat, optarg, ":,");
    434      1.12  christos 			break;
    435       1.1      jmmv 		case 'u':
    436       1.3  christos 			flags |= CLIENT_UTF8;
    437       1.1      jmmv 			break;
    438       1.1      jmmv 		case 'v':
    439       1.5  christos 			log_add_level();
    440       1.1      jmmv 			break;
    441       1.1      jmmv 		default:
    442  1.13.2.1    martin 			usage(1);
    443       1.1      jmmv 		}
    444       1.1      jmmv 	}
    445       1.1      jmmv 	argc -= optind;
    446       1.1      jmmv 	argv += optind;
    447       1.1      jmmv 
    448       1.7  christos 	if (shell_command != NULL && argc != 0)
    449  1.13.2.1    martin 		usage(1);
    450      1.12  christos 	if ((flags & CLIENT_NOFORK) && argc != 0)
    451  1.13.2.1    martin 		usage(1);
    452       1.1      jmmv 
    453       1.7  christos 	if ((ptm_fd = getptmfd()) == -1)
    454       1.7  christos 		err(1, "getptmfd");
    455       1.5  christos 	if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd "
    456       1.5  christos 	    "recvfd proc exec tty ps", NULL) != 0)
    457       1.5  christos 		err(1, "pledge");
    458       1.1      jmmv 
    459       1.5  christos 	/*
    460       1.5  christos 	 * tmux is a UTF-8 terminal, so if TMUX is set, assume UTF-8.
    461       1.5  christos 	 * Otherwise, if the user has set LC_ALL, LC_CTYPE or LANG to contain
    462       1.5  christos 	 * UTF-8, it is a safe assumption that either they are using a UTF-8
    463       1.5  christos 	 * terminal, or if not they know that output from UTF-8-capable
    464       1.5  christos 	 * programs may be wrong.
    465       1.5  christos 	 */
    466       1.5  christos 	if (getenv("TMUX") != NULL)
    467       1.5  christos 		flags |= CLIENT_UTF8;
    468       1.5  christos 	else {
    469       1.5  christos 		s = getenv("LC_ALL");
    470       1.5  christos 		if (s == NULL || *s == '\0')
    471       1.5  christos 			s = getenv("LC_CTYPE");
    472       1.5  christos 		if (s == NULL || *s == '\0')
    473       1.5  christos 			s = getenv("LANG");
    474       1.5  christos 		if (s == NULL || *s == '\0')
    475       1.5  christos 			s = "";
    476       1.5  christos 		if (strcasestr(s, "UTF-8") != NULL ||
    477       1.5  christos 		    strcasestr(s, "UTF8") != NULL)
    478       1.3  christos 			flags |= CLIENT_UTF8;
    479       1.1      jmmv 	}
    480       1.1      jmmv 
    481       1.5  christos 	global_options = options_create(NULL);
    482       1.5  christos 	global_s_options = options_create(NULL);
    483       1.6  christos 	global_w_options = options_create(NULL);
    484       1.6  christos 	for (oe = options_table; oe->name != NULL; oe++) {
    485      1.10  christos 		if (oe->scope & OPTIONS_TABLE_SERVER)
    486       1.6  christos 			options_default(global_options, oe);
    487      1.10  christos 		if (oe->scope & OPTIONS_TABLE_SESSION)
    488       1.6  christos 			options_default(global_s_options, oe);
    489      1.10  christos 		if (oe->scope & OPTIONS_TABLE_WINDOW)
    490       1.6  christos 			options_default(global_w_options, oe);
    491       1.6  christos 	}
    492       1.1      jmmv 
    493       1.6  christos 	/*
    494       1.6  christos 	 * The default shell comes from SHELL or from the user's passwd entry
    495       1.6  christos 	 * if available.
    496       1.6  christos 	 */
    497      1.12  christos 	options_set_string(global_s_options, "default-shell", 0, "%s",
    498      1.12  christos 	    getshell());
    499       1.1      jmmv 
    500       1.2    martin 	/* Override keys to vi if VISUAL or EDITOR are set. */
    501       1.1      jmmv 	if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
    502      1.12  christos 		options_set_string(global_options, "editor", 0, "%s", s);
    503       1.1      jmmv 		if (strrchr(s, '/') != NULL)
    504       1.1      jmmv 			s = strrchr(s, '/') + 1;
    505       1.1      jmmv 		if (strstr(s, "vi") != NULL)
    506       1.1      jmmv 			keys = MODEKEY_VI;
    507       1.2    martin 		else
    508       1.2    martin 			keys = MODEKEY_EMACS;
    509       1.5  christos 		options_set_number(global_s_options, "status-keys", keys);
    510       1.5  christos 		options_set_number(global_w_options, "mode-keys", keys);
    511       1.1      jmmv 	}
    512       1.1      jmmv 
    513       1.1      jmmv 	/*
    514       1.5  christos 	 * If socket is specified on the command-line with -S or -L, it is
    515       1.5  christos 	 * used. Otherwise, $TMUX is checked and if that fails "default" is
    516       1.5  christos 	 * used.
    517       1.1      jmmv 	 */
    518       1.5  christos 	if (path == NULL && label == NULL) {
    519       1.5  christos 		s = getenv("TMUX");
    520       1.5  christos 		if (s != NULL && *s != '\0' && *s != ',') {
    521       1.5  christos 			path = xstrdup(s);
    522       1.6  christos 			path[strcspn(path, ",")] = '\0';
    523       1.1      jmmv 		}
    524       1.1      jmmv 	}
    525      1.12  christos 	if (path == NULL) {
    526      1.12  christos 		if ((path = make_label(label, &cause)) == NULL) {
    527      1.12  christos 			if (cause != NULL) {
    528      1.12  christos 				fprintf(stderr, "%s\n", cause);
    529      1.12  christos 				free(cause);
    530      1.12  christos 			}
    531      1.12  christos 			exit(1);
    532       1.8  christos 		}
    533      1.12  christos 		flags |= CLIENT_DEFAULTSOCKET;
    534       1.3  christos 	}
    535       1.5  christos 	socket_path = path;
    536       1.5  christos 	free(label);
    537       1.1      jmmv 
    538       1.1      jmmv 	/* Pass control to the client. */
    539      1.12  christos 	exit(client_main(osdep_event_init(), argc, argv, flags, feat));
    540       1.1      jmmv }
    541