[BACK]Return to tmux.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/tmux.c, Revision 1.1

1.1     ! nicm        1: /* $OpenBSD$ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
        !             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 <paths.h>
        !            24: #include <pwd.h>
        !            25: #include <signal.h>
        !            26: #include <stdlib.h>
        !            27: #include <string.h>
        !            28: #include <syslog.h>
        !            29: #include <unistd.h>
        !            30:
        !            31: #include "tmux.h"
        !            32:
        !            33: #ifdef DEBUG
        !            34: const char     *malloc_options = "AFGJPX";
        !            35: #endif
        !            36:
        !            37: volatile sig_atomic_t sigwinch;
        !            38: volatile sig_atomic_t sigterm;
        !            39: volatile sig_atomic_t sigcont;
        !            40: volatile sig_atomic_t sigchld;
        !            41: volatile sig_atomic_t sigusr1;
        !            42: volatile sig_atomic_t sigusr2;
        !            43:
        !            44: char           *cfg_file;
        !            45: struct options  global_options;
        !            46: struct options  global_window_options;
        !            47:
        !            48: int             server_locked;
        !            49: char           *server_password;
        !            50: time_t          server_activity;
        !            51:
        !            52: int             debug_level;
        !            53: int             be_quiet;
        !            54: time_t          start_time;
        !            55: char           *socket_path;
        !            56:
        !            57: __dead void     usage(void);
        !            58: char           *makesockpath(const char *);
        !            59:
        !            60: __dead void
        !            61: usage(void)
        !            62: {
        !            63:        fprintf(stderr, "usage: %s [-28dqUuVv] [-f file] "
        !            64:            "[-L socket-name] [-S socket-path] [command [flags]]\n",
        !            65:            __progname);
        !            66:        exit(1);
        !            67: }
        !            68:
        !            69: void
        !            70: logfile(const char *name)
        !            71: {
        !            72:        char    *path;
        !            73:
        !            74:        log_close();
        !            75:        if (debug_level > 0) {
        !            76:                xasprintf(
        !            77:                    &path, "%s-%s-%ld.log", __progname, name, (long) getpid());
        !            78:                log_open_file(debug_level, path);
        !            79:                xfree(path);
        !            80:        }
        !            81: }
        !            82:
        !            83: void
        !            84: sighandler(int sig)
        !            85: {
        !            86:        int     saved_errno;
        !            87:
        !            88:        saved_errno = errno;
        !            89:        switch (sig) {
        !            90:        case SIGWINCH:
        !            91:                sigwinch = 1;
        !            92:                break;
        !            93:        case SIGTERM:
        !            94:                sigterm = 1;
        !            95:                break;
        !            96:        case SIGCHLD:
        !            97:                sigchld = 1;
        !            98:                break;
        !            99:        case SIGCONT:
        !           100:                sigcont = 1;
        !           101:                break;
        !           102:        case SIGUSR1:
        !           103:                sigusr1 = 1;
        !           104:                break;
        !           105:        case SIGUSR2:
        !           106:                sigusr2 = 1;
        !           107:                break;
        !           108:        }
        !           109:        errno = saved_errno;
        !           110: }
        !           111:
        !           112: void
        !           113: siginit(void)
        !           114: {
        !           115:        struct sigaction         act;
        !           116:
        !           117:        memset(&act, 0, sizeof act);
        !           118:        sigemptyset(&act.sa_mask);
        !           119:        act.sa_flags = SA_RESTART;
        !           120:
        !           121:        act.sa_handler = SIG_IGN;
        !           122:        if (sigaction(SIGPIPE, &act, NULL) != 0)
        !           123:                fatal("sigaction failed");
        !           124:        if (sigaction(SIGINT, &act, NULL) != 0)
        !           125:                fatal("sigaction failed");
        !           126:        if (sigaction(SIGTSTP, &act, NULL) != 0)
        !           127:                fatal("sigaction failed");
        !           128:        if (sigaction(SIGQUIT, &act, NULL) != 0)
        !           129:                fatal("sigaction failed");
        !           130:
        !           131:        act.sa_handler = sighandler;
        !           132:        if (sigaction(SIGWINCH, &act, NULL) != 0)
        !           133:                fatal("sigaction failed");
        !           134:        if (sigaction(SIGTERM, &act, NULL) != 0)
        !           135:                fatal("sigaction failed");
        !           136:        if (sigaction(SIGCHLD, &act, NULL) != 0)
        !           137:                fatal("sigaction failed");
        !           138:        if (sigaction(SIGUSR1, &act, NULL) != 0)
        !           139:                fatal("sigaction failed");
        !           140:        if (sigaction(SIGUSR2, &act, NULL) != 0)
        !           141:                fatal("sigaction failed");
        !           142: }
        !           143:
        !           144: void
        !           145: sigreset(void)
        !           146: {
        !           147:        struct sigaction act;
        !           148:
        !           149:        memset(&act, 0, sizeof act);
        !           150:        sigemptyset(&act.sa_mask);
        !           151:
        !           152:        act.sa_handler = SIG_DFL;
        !           153:        if (sigaction(SIGPIPE, &act, NULL) != 0)
        !           154:                fatal("sigaction failed");
        !           155:        if (sigaction(SIGUSR1, &act, NULL) != 0)
        !           156:                fatal("sigaction failed");
        !           157:        if (sigaction(SIGUSR2, &act, NULL) != 0)
        !           158:                fatal("sigaction failed");
        !           159:        if (sigaction(SIGINT, &act, NULL) != 0)
        !           160:                fatal("sigaction failed");
        !           161:        if (sigaction(SIGTSTP, &act, NULL) != 0)
        !           162:                fatal("sigaction failed");
        !           163:        if (sigaction(SIGQUIT, &act, NULL) != 0)
        !           164:                fatal("sigaction failed");
        !           165:        if (sigaction(SIGWINCH, &act, NULL) != 0)
        !           166:                fatal("sigaction failed");
        !           167:        if (sigaction(SIGTERM, &act, NULL) != 0)
        !           168:                fatal("sigaction failed");
        !           169:        if (sigaction(SIGCHLD, &act, NULL) != 0)
        !           170:                fatal("sigaction failed");
        !           171: }
        !           172:
        !           173: char *
        !           174: makesockpath(const char *label)
        !           175: {
        !           176:        char            base[MAXPATHLEN], *path;
        !           177:        struct stat     sb;
        !           178:        u_int           uid;
        !           179:
        !           180:        uid = getuid();
        !           181:        xsnprintf(base, MAXPATHLEN, "%s/%s-%d", _PATH_TMP, __progname, uid);
        !           182:
        !           183:        if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST)
        !           184:                return (NULL);
        !           185:
        !           186:        if (lstat(base, &sb) != 0)
        !           187:                return (NULL);
        !           188:        if (!S_ISDIR(sb.st_mode)) {
        !           189:                errno = ENOTDIR;
        !           190:                return (NULL);
        !           191:        }
        !           192:        if (sb.st_uid != uid || (sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) {
        !           193:                errno = EACCES;
        !           194:                return (NULL);
        !           195:        }
        !           196:
        !           197:        xasprintf(&path, "%s/%s", base, label);
        !           198:        return (path);
        !           199: }
        !           200:
        !           201: int
        !           202: main(int argc, char **argv)
        !           203: {
        !           204:        struct client_ctx        cctx;
        !           205:        struct msg_command_data  cmddata;
        !           206:        struct buffer           *b;
        !           207:        struct cmd_list         *cmdlist;
        !           208:        struct cmd              *cmd;
        !           209:        struct pollfd            pfd;
        !           210:        struct hdr               hdr;
        !           211:        const char              *shell;
        !           212:        struct passwd           *pw;
        !           213:        char                    *s, *path, *label, *cause, *home, *pass = NULL;
        !           214:        char                     cwd[MAXPATHLEN];
        !           215:        int                      retcode, opt, flags, unlock, start_server;
        !           216:
        !           217:        unlock = flags = 0;
        !           218:        label = path = NULL;
        !           219:         while ((opt = getopt(argc, argv, "28df:L:qS:uUv")) != -1) {
        !           220:                 switch (opt) {
        !           221:                case '2':
        !           222:                        flags |= IDENTIFY_256COLOURS;
        !           223:                        flags &= ~IDENTIFY_88COLOURS;
        !           224:                        break;
        !           225:                case '8':
        !           226:                        flags |= IDENTIFY_88COLOURS;
        !           227:                        flags &= ~IDENTIFY_256COLOURS;
        !           228:                        break;
        !           229:                case 'f':
        !           230:                        cfg_file = xstrdup(optarg);
        !           231:                        break;
        !           232:                case 'L':
        !           233:                        if (path != NULL) {
        !           234:                                log_warnx("-L and -S cannot be used together");
        !           235:                                exit(1);
        !           236:                        }
        !           237:                        if (label != NULL)
        !           238:                                xfree(label);
        !           239:                        label = xstrdup(optarg);
        !           240:                        break;
        !           241:                case 'S':
        !           242:                        if (label != NULL) {
        !           243:                                log_warnx("-L and -S cannot be used together");
        !           244:                                exit(1);
        !           245:                        }
        !           246:                        if (path != NULL)
        !           247:                                xfree(path);
        !           248:                        path = xstrdup(optarg);
        !           249:                        break;
        !           250:                case 'q':
        !           251:                        be_quiet = 1;
        !           252:                        break;
        !           253:                case 'u':
        !           254:                        flags |= IDENTIFY_UTF8;
        !           255:                        break;
        !           256:                case 'U':
        !           257:                        unlock = 1;
        !           258:                        break;
        !           259:                case 'd':
        !           260:                        flags |= IDENTIFY_HASDEFAULTS;
        !           261:                        break;
        !           262:                case 'v':
        !           263:                        debug_level++;
        !           264:                        break;
        !           265:                 default:
        !           266:                        usage();
        !           267:                 }
        !           268:         }
        !           269:        argc -= optind;
        !           270:        argv += optind;
        !           271:
        !           272:        log_open_tty(debug_level);
        !           273:        siginit();
        !           274:
        !           275:        options_init(&global_options, NULL);
        !           276:        options_set_number(&global_options, "bell-action", BELL_ANY);
        !           277:        options_set_number(&global_options, "buffer-limit", 9);
        !           278:        options_set_number(&global_options, "display-time", 750);
        !           279:        options_set_number(&global_options, "history-limit", 2000);
        !           280:        options_set_number(&global_options, "lock-after-time", 0);
        !           281:        options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE);
        !           282:        options_set_number(&global_options, "message-bg", 3);
        !           283:        options_set_number(&global_options, "message-fg", 0);
        !           284:        options_set_number(&global_options, "prefix", '\002');
        !           285:        options_set_number(&global_options, "repeat-time", 500);
        !           286:        options_set_number(&global_options, "set-remain-on-exit", 0);
        !           287:        options_set_number(&global_options, "set-titles", 1);
        !           288:        options_set_number(&global_options, "status", 1);
        !           289:        options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE);
        !           290:        options_set_number(&global_options, "status-bg", 2);
        !           291:        options_set_number(&global_options, "status-fg", 0);
        !           292:        options_set_number(&global_options, "status-interval", 15);
        !           293:        options_set_number(&global_options, "status-keys", MODEKEY_EMACS);
        !           294:        options_set_number(&global_options, "status-left-length", 10);
        !           295:        options_set_number(&global_options, "status-right-length", 40);
        !           296:        options_set_string(&global_options, "status-left", "[#S]");
        !           297:        options_set_string(
        !           298:            &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y");
        !           299:
        !           300:        options_init(&global_window_options, NULL);
        !           301:        options_set_number(&global_window_options, "aggressive-resize", 0);
        !           302:        options_set_number(&global_window_options, "automatic-rename", 1);
        !           303:        options_set_number(&global_window_options, "clock-mode-colour", 4);
        !           304:        options_set_number(&global_window_options, "clock-mode-style", 1);
        !           305:        options_set_number(&global_window_options, "force-height", 0);
        !           306:        options_set_number(&global_window_options, "force-width", 0);
        !           307:        options_set_number(
        !           308:            &global_window_options, "mode-attr", GRID_ATTR_REVERSE);
        !           309:        options_set_number(&global_window_options, "main-pane-width", 81);
        !           310:        options_set_number(&global_window_options, "main-pane-height", 24);
        !           311:        options_set_number(&global_window_options, "mode-bg", 3);
        !           312:        options_set_number(&global_window_options, "mode-fg", 0);
        !           313:        options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS);
        !           314:        options_set_number(&global_window_options, "monitor-activity", 0);
        !           315:        options_set_string(&global_window_options, "monitor-content", "%s", "");
        !           316:        options_set_number(&global_window_options, "utf8", 0);
        !           317:        options_set_number(&global_window_options, "window-status-attr", 0);
        !           318:        options_set_number(&global_window_options, "window-status-bg", 8);
        !           319:        options_set_number(&global_window_options, "window-status-fg", 8);
        !           320:        options_set_number(&global_window_options, "xterm-keys", 0);
        !           321:        options_set_number(&global_window_options, "remain-on-exit", 0);
        !           322:
        !           323:        if (!(flags & IDENTIFY_UTF8)) {
        !           324:                /*
        !           325:                 * If the user has set LANG to contain UTF-8, it is a safe
        !           326:                 * assumption that either they are using a UTF-8 terminal, or
        !           327:                 * if not they know that output from UTF-8-capable programs may
        !           328:                 * be wrong.
        !           329:                 */
        !           330:                if ((s = getenv("LANG")) != NULL && strstr(s, "UTF-8") != NULL)
        !           331:                        flags |= IDENTIFY_UTF8;
        !           332:        }
        !           333:
        !           334:        if (cfg_file == NULL) {
        !           335:                home = getenv("HOME");
        !           336:                if (home == NULL || *home == '\0') {
        !           337:                        pw = getpwuid(getuid());
        !           338:                        if (pw != NULL)
        !           339:                                home = pw->pw_dir;
        !           340:                }
        !           341:                xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG);
        !           342:                if (access(cfg_file, R_OK) != 0) {
        !           343:                        xfree(cfg_file);
        !           344:                        cfg_file = NULL;
        !           345:                }
        !           346:        } else {
        !           347:                if (access(cfg_file, R_OK) != 0) {
        !           348:                        log_warn("%s", cfg_file);
        !           349:                        exit(1);
        !           350:                }
        !           351:        }
        !           352:
        !           353:        if (label == NULL)
        !           354:                label = xstrdup("default");
        !           355:        if (path == NULL && (path = makesockpath(label)) == NULL) {
        !           356:                log_warn("can't create socket");
        !           357:                exit(1);
        !           358:        }
        !           359:        xfree(label);
        !           360:
        !           361:        shell = getenv("SHELL");
        !           362:        if (shell == NULL || *shell == '\0') {
        !           363:                pw = getpwuid(getuid());
        !           364:                if (pw != NULL)
        !           365:                        shell = pw->pw_shell;
        !           366:                if (shell == NULL || *shell == '\0')
        !           367:                        shell = _PATH_BSHELL;
        !           368:        }
        !           369:        options_set_string(
        !           370:            &global_options, "default-command", "exec %s", shell);
        !           371:
        !           372:        if (getcwd(cwd, sizeof cwd) == NULL) {
        !           373:                log_warn("getcwd");
        !           374:                exit(1);
        !           375:        }
        !           376:        options_set_string(&global_options, "default-path", "%s", cwd);
        !           377:
        !           378:        if (unlock) {
        !           379:                if (argc != 0) {
        !           380:                        log_warnx("can't specify a command when unlocking");
        !           381:                        exit(1);
        !           382:                }
        !           383:                cmdlist = NULL;
        !           384:                if ((pass = getpass("Password: ")) == NULL)
        !           385:                        exit(1);
        !           386:                start_server = 0;
        !           387:        } else {
        !           388:                if (argc == 0) {
        !           389:                        cmd = xmalloc(sizeof *cmd);
        !           390:                        cmd->entry = &cmd_new_session_entry;
        !           391:                        cmd->entry->init(cmd, 0);
        !           392:
        !           393:                        cmdlist = xmalloc(sizeof *cmdlist);
        !           394:                        TAILQ_INIT(cmdlist);
        !           395:                        TAILQ_INSERT_HEAD(cmdlist, cmd, qentry);
        !           396:                } else {
        !           397:                        cmdlist = cmd_list_parse(argc, argv, &cause);
        !           398:                        if (cmdlist == NULL) {
        !           399:                                log_warnx("%s", cause);
        !           400:                                exit(1);
        !           401:                        }
        !           402:                }
        !           403:                start_server = 0;
        !           404:                TAILQ_FOREACH(cmd, cmdlist, qentry) {
        !           405:                        if (cmd->entry->flags & CMD_STARTSERVER) {
        !           406:                                start_server = 1;
        !           407:                                break;
        !           408:                        }
        !           409:                }
        !           410:        }
        !           411:
        !           412:        memset(&cctx, 0, sizeof cctx);
        !           413:        if (client_init(path, &cctx, start_server, flags) != 0)
        !           414:                exit(1);
        !           415:        xfree(path);
        !           416:
        !           417:        b = buffer_create(BUFSIZ);
        !           418:        if (unlock) {
        !           419:                cmd_send_string(b, pass);
        !           420:                client_write_server(
        !           421:                    &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b));
        !           422:        } else {
        !           423:                cmd_list_send(cmdlist, b);
        !           424:                cmd_list_free(cmdlist);
        !           425:                client_fill_session(&cmddata);
        !           426:                client_write_server2(&cctx, MSG_COMMAND,
        !           427:                    &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b));
        !           428:        }
        !           429:        buffer_destroy(b);
        !           430:
        !           431:        retcode = 0;
        !           432:        for (;;) {
        !           433:                pfd.fd = cctx.srv_fd;
        !           434:                pfd.events = POLLIN;
        !           435:                if (BUFFER_USED(cctx.srv_out) > 0)
        !           436:                        pfd.events |= POLLOUT;
        !           437:
        !           438:                if (poll(&pfd, 1, INFTIM) == -1) {
        !           439:                        if (errno == EAGAIN || errno == EINTR)
        !           440:                                continue;
        !           441:                        fatal("poll failed");
        !           442:                }
        !           443:
        !           444:                if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
        !           445:                        goto out;
        !           446:
        !           447:        restart:
        !           448:                if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
        !           449:                        continue;
        !           450:                memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
        !           451:                if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
        !           452:                        continue;
        !           453:                buffer_remove(cctx.srv_in, sizeof hdr);
        !           454:
        !           455:                switch (hdr.type) {
        !           456:                case MSG_EXIT:
        !           457:                case MSG_SHUTDOWN:
        !           458:                        goto out;
        !           459:                case MSG_ERROR:
        !           460:                        retcode = 1;
        !           461:                        /* FALLTHROUGH */
        !           462:                case MSG_PRINT:
        !           463:                        if (hdr.size > INT_MAX - 1)
        !           464:                                fatalx("bad MSG_PRINT size");
        !           465:                        log_info("%.*s",
        !           466:                            (int) hdr.size, BUFFER_OUT(cctx.srv_in));
        !           467:                        if (hdr.size != 0)
        !           468:                                buffer_remove(cctx.srv_in, hdr.size);
        !           469:                        goto restart;
        !           470:                case MSG_READY:
        !           471:                        retcode = client_main(&cctx);
        !           472:                        goto out;
        !           473:                default:
        !           474:                        fatalx("unexpected command");
        !           475:                }
        !           476:        }
        !           477:
        !           478: out:
        !           479:        options_free(&global_options);
        !           480:        options_free(&global_window_options);
        !           481:
        !           482:        close(cctx.srv_fd);
        !           483:        buffer_destroy(cctx.srv_in);
        !           484:        buffer_destroy(cctx.srv_out);
        !           485:
        !           486:        return (retcode);
        !           487: }