File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / tmux.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (6 years, 11 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    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/stat.h>
   21: 
   22: #include <errno.h>
   23: #include <event.h>
   24: #include <fcntl.h>
   25: #include <getopt.h>
   26: #include <langinfo.h>
   27: #include <locale.h>
   28: #include <pwd.h>
   29: #include <stdlib.h>
   30: #include <string.h>
   31: #include <time.h>
   32: #include <unistd.h>
   33: 
   34: #include "tmux.h"
   35: 
   36: struct options	*global_options;	/* server options */
   37: struct options	*global_s_options;	/* session options */
   38: struct options	*global_w_options;	/* window options */
   39: struct environ	*global_environ;
   40: struct hooks	*global_hooks;
   41: 
   42: struct timeval	 start_time;
   43: const char	*socket_path;
   44: int		 ptm_fd = -1;
   45: 
   46: static __dead void	 usage(void);
   47: static char		*make_label(const char *);
   48: 
   49: static const char	*getshell(void);
   50: static int		 checkshell(const char *);
   51: 
   52: static __dead void
   53: usage(void)
   54: {
   55: 	fprintf(stderr,
   56: 	    "usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
   57: 	    "            [-S socket-path] [command [flags]]\n",
   58: 	    getprogname());
   59: 	exit(1);
   60: }
   61: 
   62: static const char *
   63: getshell(void)
   64: {
   65: 	struct passwd	*pw;
   66: 	const char	*shell;
   67: 
   68: 	shell = getenv("SHELL");
   69: 	if (checkshell(shell))
   70: 		return (shell);
   71: 
   72: 	pw = getpwuid(getuid());
   73: 	if (pw != NULL && checkshell(pw->pw_shell))
   74: 		return (pw->pw_shell);
   75: 
   76: 	return (_PATH_BSHELL);
   77: }
   78: 
   79: static int
   80: checkshell(const char *shell)
   81: {
   82: 	if (shell == NULL || *shell != '/')
   83: 		return (0);
   84: 	if (areshell(shell))
   85: 		return (0);
   86: 	if (access(shell, X_OK) != 0)
   87: 		return (0);
   88: 	return (1);
   89: }
   90: 
   91: int
   92: areshell(const char *shell)
   93: {
   94: 	const char	*progname, *ptr;
   95: 
   96: 	if ((ptr = strrchr(shell, '/')) != NULL)
   97: 		ptr++;
   98: 	else
   99: 		ptr = shell;
  100: 	progname = getprogname();
  101: 	if (*progname == '-')
  102: 		progname++;
  103: 	if (strcmp(ptr, progname) == 0)
  104: 		return (1);
  105: 	return (0);
  106: }
  107: 
  108: static char *
  109: make_label(const char *label)
  110: {
  111: 	char		*base, resolved[PATH_MAX], *path, *s;
  112: 	struct stat	 sb;
  113: 	uid_t		 uid;
  114: 	int		 saved_errno;
  115: 
  116: 	if (label == NULL)
  117: 		label = "default";
  118: 	uid = getuid();
  119: 
  120: 	if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0')
  121: 		xasprintf(&base, "%s/tmux-%u", s, uid);
  122: 	else
  123: 		xasprintf(&base, "%s/tmux-%ld", _PATH_TMP, (long)uid);
  124: 
  125: 	if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
  126: 		goto fail;
  127: 
  128: 	if (lstat(base, &sb) != 0)
  129: 		goto fail;
  130: 	if (!S_ISDIR(sb.st_mode)) {
  131: 		errno = ENOTDIR;
  132: 		goto fail;
  133: 	}
  134: 	if (sb.st_uid != uid || (sb.st_mode & S_IRWXO) != 0) {
  135: 		errno = EACCES;
  136: 		goto fail;
  137: 	}
  138: 
  139: 	if (realpath(base, resolved) == NULL)
  140: 		strlcpy(resolved, base, sizeof resolved);
  141: 	xasprintf(&path, "%s/%s", resolved, label);
  142: 
  143: 	free(base);
  144: 	return (path);
  145: 
  146: fail:
  147: 	saved_errno = errno;
  148: 	free(base);
  149: 	errno = saved_errno;
  150: 	return (NULL);
  151: }
  152: 
  153: void
  154: setblocking(int fd, int state)
  155: {
  156: 	int mode;
  157: 
  158: 	if ((mode = fcntl(fd, F_GETFL)) != -1) {
  159: 		if (!state)
  160: 			mode |= O_NONBLOCK;
  161: 		else
  162: 			mode &= ~O_NONBLOCK;
  163: 		fcntl(fd, F_SETFL, mode);
  164: 	}
  165: }
  166: 
  167: const char *
  168: find_home(void)
  169: {
  170: 	struct passwd		*pw;
  171: 	static const char	*home;
  172: 
  173: 	if (home != NULL)
  174: 		return (home);
  175: 
  176: 	home = getenv("HOME");
  177: 	if (home == NULL || *home == '\0') {
  178: 		pw = getpwuid(getuid());
  179: 		if (pw != NULL)
  180: 			home = pw->pw_dir;
  181: 		else
  182: 			home = NULL;
  183: 	}
  184: 
  185: 	return (home);
  186: }
  187: 
  188: int
  189: main(int argc, char **argv)
  190: {
  191: 	char					*path, *label, tmp[PATH_MAX];
  192: 	char					*shellcmd = NULL, **var;
  193: 	const char				*s, *shell;
  194: 	int					 opt, flags, keys;
  195: 	const struct options_table_entry	*oe;
  196: 
  197: 	if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) {
  198: 		if (setlocale(LC_CTYPE, "") == NULL)
  199: 			errx(1, "invalid LC_ALL, LC_CTYPE or LANG");
  200: 		s = nl_langinfo(CODESET);
  201: 		if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0)
  202: 			errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s);
  203: 	}
  204: 
  205: 	setlocale(LC_TIME, "");
  206: 	tzset();
  207: 
  208: 	if (**argv == '-')
  209: 		flags = CLIENT_LOGIN;
  210: 	else
  211: 		flags = 0;
  212: 
  213: 	label = path = NULL;
  214: 	while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) {
  215: 		switch (opt) {
  216: 		case '2':
  217: 			flags |= CLIENT_256COLOURS;
  218: 			break;
  219: 		case 'c':
  220: 			free(shellcmd);
  221: 			shellcmd = xstrdup(optarg);
  222: 			break;
  223: 		case 'C':
  224: 			if (flags & CLIENT_CONTROL)
  225: 				flags |= CLIENT_CONTROLCONTROL;
  226: 			else
  227: 				flags |= CLIENT_CONTROL;
  228: 			break;
  229: 		case 'V':
  230: 			printf("%s %s\n", getprogname(), VERSION);
  231: 			exit(0);
  232: 		case 'f':
  233: 			set_cfg_file(optarg);
  234: 			break;
  235: 		case 'l':
  236: 			flags |= CLIENT_LOGIN;
  237: 			break;
  238: 		case 'L':
  239: 			free(label);
  240: 			label = xstrdup(optarg);
  241: 			break;
  242: 		case 'q':
  243: 			break;
  244: 		case 'S':
  245: 			free(path);
  246: 			path = xstrdup(optarg);
  247: 			break;
  248: 		case 'u':
  249: 			flags |= CLIENT_UTF8;
  250: 			break;
  251: 		case 'v':
  252: 			log_add_level();
  253: 			break;
  254: 		default:
  255: 			usage();
  256: 		}
  257: 	}
  258: 	argc -= optind;
  259: 	argv += optind;
  260: 
  261: 	if (shellcmd != NULL && argc != 0)
  262: 		usage();
  263: 
  264: 	if (pty_open(&ptm_fd) != 0)
  265: 		errx(1, "open(\"/dev/ptm\"");
  266: 	if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd "
  267: 	    "recvfd proc exec tty ps", NULL) != 0)
  268: 		err(1, "pledge");
  269: 
  270: 	/*
  271: 	 * tmux is a UTF-8 terminal, so if TMUX is set, assume UTF-8.
  272: 	 * Otherwise, if the user has set LC_ALL, LC_CTYPE or LANG to contain
  273: 	 * UTF-8, it is a safe assumption that either they are using a UTF-8
  274: 	 * terminal, or if not they know that output from UTF-8-capable
  275: 	 * programs may be wrong.
  276: 	 */
  277: 	if (getenv("TMUX") != NULL)
  278: 		flags |= CLIENT_UTF8;
  279: 	else {
  280: 		s = getenv("LC_ALL");
  281: 		if (s == NULL || *s == '\0')
  282: 			s = getenv("LC_CTYPE");
  283: 		if (s == NULL || *s == '\0')
  284: 			s = getenv("LANG");
  285: 		if (s == NULL || *s == '\0')
  286: 			s = "";
  287: 		if (strcasestr(s, "UTF-8") != NULL ||
  288: 		    strcasestr(s, "UTF8") != NULL)
  289: 			flags |= CLIENT_UTF8;
  290: 	}
  291: 
  292: 	global_hooks = hooks_create(NULL);
  293: 
  294: 	global_environ = environ_create();
  295: 	for (var = environ; *var != NULL; var++)
  296: 		environ_put(global_environ, *var);
  297: 	if (getcwd(tmp, sizeof tmp) != NULL)
  298: 		environ_set(global_environ, "PWD", "%s", tmp);
  299: 
  300: 	global_options = options_create(NULL);
  301: 	global_s_options = options_create(NULL);
  302: 	global_w_options = options_create(NULL);
  303: 	for (oe = options_table; oe->name != NULL; oe++) {
  304: 		if (oe->scope == OPTIONS_TABLE_SERVER)
  305: 			options_default(global_options, oe);
  306: 		if (oe->scope == OPTIONS_TABLE_SESSION)
  307: 			options_default(global_s_options, oe);
  308: 		if (oe->scope == OPTIONS_TABLE_WINDOW)
  309: 			options_default(global_w_options, oe);
  310: 	}
  311: 
  312: 	/*
  313: 	 * The default shell comes from SHELL or from the user's passwd entry
  314: 	 * if available.
  315: 	 */
  316: 	shell = getshell();
  317: 	options_set_string(global_s_options, "default-shell", 0, "%s", shell);
  318: 
  319: 	/* Override keys to vi if VISUAL or EDITOR are set. */
  320: 	if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
  321: 		if (strrchr(s, '/') != NULL)
  322: 			s = strrchr(s, '/') + 1;
  323: 		if (strstr(s, "vi") != NULL)
  324: 			keys = MODEKEY_VI;
  325: 		else
  326: 			keys = MODEKEY_EMACS;
  327: 		options_set_number(global_s_options, "status-keys", keys);
  328: 		options_set_number(global_w_options, "mode-keys", keys);
  329: 	}
  330: 
  331: 	/*
  332: 	 * If socket is specified on the command-line with -S or -L, it is
  333: 	 * used. Otherwise, $TMUX is checked and if that fails "default" is
  334: 	 * used.
  335: 	 */
  336: 	if (path == NULL && label == NULL) {
  337: 		s = getenv("TMUX");
  338: 		if (s != NULL && *s != '\0' && *s != ',') {
  339: 			path = xstrdup(s);
  340: 			path[strcspn(path, ",")] = '\0';
  341: 		}
  342: 	}
  343: 	if (path == NULL && (path = make_label(label)) == NULL) {
  344: 		fprintf(stderr, "can't create socket: %s\n", strerror(errno));
  345: 		exit(1);
  346: 	}
  347: 	socket_path = path;
  348: 	free(label);
  349: 
  350: 	/* Pass control to the client. */
  351: 	exit(client_main(osdep_event_init(), argc, argv, flags, shellcmd));
  352: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>