Annotation of embedaddon/tmux/tmux.c, revision 1.1.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>