Annotation of embedaddon/tmux/tmux.c, revision 1.1

1.1     ! misho       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>