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

Annotation of src/usr.bin/tmux/cfg.c, Revision 1.77

1.77    ! nicm        1: /* $OpenBSD: cfg.c,v 1.76 2019/12/10 14:22:15 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.44      nicm        4:  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        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:
1.21      nicm       21: #include <ctype.h>
1.1       nicm       22: #include <errno.h>
                     23: #include <stdio.h>
1.15      nicm       24: #include <stdlib.h>
1.1       nicm       25: #include <string.h>
1.32      tobias     26: #include <util.h>
1.1       nicm       27:
                     28: #include "tmux.h"
                     29:
1.63      nicm       30: struct client           *cfg_client;
1.58      nicm       31: static char             *cfg_file;
                     32: int                      cfg_finished;
                     33: static char            **cfg_causes;
                     34: static u_int             cfg_ncauses;
                     35: static struct cmdq_item         *cfg_item;
                     36:
                     37: static enum cmd_retval
                     38: cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
                     39: {
                     40:        if (!cfg_finished)
                     41:                return (CMD_RETURN_WAIT);
                     42:        return (CMD_RETURN_NORMAL);
                     43: }
1.40      nicm       44:
1.49      nicm       45: static enum cmd_retval
1.50      nicm       46: cfg_done(__unused struct cmdq_item *item, __unused void *data)
1.49      nicm       47: {
                     48:        if (cfg_finished)
                     49:                return (CMD_RETURN_NORMAL);
                     50:        cfg_finished = 1;
                     51:
                     52:        if (!RB_EMPTY(&sessions))
                     53:                cfg_show_causes(RB_MIN(sessions, &sessions));
1.57      nicm       54:
1.58      nicm       55:        if (cfg_item != NULL)
1.74      nicm       56:                cmdq_continue(cfg_item);
1.58      nicm       57:
1.57      nicm       58:        status_prompt_load_history();
1.49      nicm       59:
                     60:        return (CMD_RETURN_NORMAL);
                     61: }
1.40      nicm       62:
                     63: void
1.41      nicm       64: set_cfg_file(const char *path)
                     65: {
                     66:        free(cfg_file);
                     67:        cfg_file = xstrdup(path);
                     68: }
                     69:
1.76      nicm       70: static char *
                     71: expand_cfg_file(const char *path, const char *home)
                     72: {
                     73:        char                    *expanded, *name;
                     74:        const char              *end;
                     75:        struct environ_entry    *value;
                     76:
                     77:        if (strncmp(path, "~/", 2) == 0) {
                     78:                if (home == NULL)
                     79:                        return (NULL);
                     80:                xasprintf(&expanded, "%s%s", home, path + 1);
                     81:                return (expanded);
                     82:        }
                     83:
                     84:        if (*path == '$') {
                     85:                end = strchr(path, '/');
                     86:                if (end == NULL)
                     87:                        name = xstrdup(path + 1);
                     88:                else
                     89:                        name = xstrndup(path + 1, end - path - 1);
                     90:                value = environ_find(global_environ, name);
                     91:                free(name);
                     92:                if (value == NULL)
                     93:                        return (NULL);
                     94:                if (end == NULL)
                     95:                        end = "";
                     96:                xasprintf(&expanded, "%s%s", value->value, end);
                     97:                return (expanded);
                     98:        }
                     99:
                    100:        return (xstrdup(path));
                    101: }
                    102:
1.41      nicm      103: void
1.40      nicm      104: start_cfg(void)
                    105: {
1.76      nicm      106:        const char      *home = find_home();
1.58      nicm      107:        struct client   *c;
1.76      nicm      108:        char            *path, *copy, *next, *expanded;
1.40      nicm      109:
1.56      nicm      110:        /*
1.71      nicm      111:         * Configuration files are loaded without a client, so commands are run
                    112:         * in the global queue with item->client NULL.
1.58      nicm      113:         *
                    114:         * However, we must block the initial client (but just the initial
                    115:         * client) so that its command runs after the configuration is loaded.
                    116:         * Because start_cfg() is called so early, we can be sure the client's
                    117:         * command queue is currently empty and our callback will be at the
                    118:         * front - we need to get in before MSG_COMMAND.
1.56      nicm      119:         */
1.63      nicm      120:        cfg_client = c = TAILQ_FIRST(&clients);
1.58      nicm      121:        if (c != NULL) {
                    122:                cfg_item = cmdq_get_callback(cfg_client_done, NULL);
                    123:                cmdq_append(c, cfg_item);
                    124:        }
1.40      nicm      125:
1.76      nicm      126:        if (cfg_file == NULL) {
                    127:                path = copy = xstrdup(TMUX_CONF);
                    128:                while ((next = strsep(&path, ":")) != NULL) {
                    129:                        expanded = expand_cfg_file(next, home);
                    130:                        if (expanded == NULL) {
                    131:                                log_debug("couldn't expand %s", next);
                    132:                                continue;
                    133:                        }
                    134:                        log_debug("expanded %s to %s", next, expanded);
                    135:                        load_cfg(expanded, c, NULL, CMD_PARSE_QUIET, NULL);
                    136:                        free(expanded);
                    137:                }
                    138:                free(copy);
                    139:        } else
                    140:                load_cfg(cfg_file, c, NULL, 0, NULL);
1.40      nicm      141:
1.56      nicm      142:        cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
1.40      nicm      143: }
1.1       nicm      144:
1.28      nicm      145: int
1.70      nicm      146: load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
                    147:     struct cmdq_item **new_item)
1.1       nicm      148: {
1.50      nicm      149:        FILE                    *f;
1.71      nicm      150:        struct cmd_parse_input   pi;
                    151:        struct cmd_parse_result *pr;
1.70      nicm      152:        struct cmdq_item        *new_item0;
1.61      nicm      153:
1.71      nicm      154:        if (new_item != NULL)
                    155:                *new_item = NULL;
1.1       nicm      156:
1.29      nicm      157:        log_debug("loading %s", path);
1.1       nicm      158:        if ((f = fopen(path, "rb")) == NULL) {
1.71      nicm      159:                if (errno == ENOENT && (flags & CMD_PARSE_QUIET))
1.45      tim       160:                        return (0);
                    161:                cfg_add_cause("%s: %s", path, strerror(errno));
1.28      nicm      162:                return (-1);
1.25      nicm      163:        }
                    164:
1.71      nicm      165:        memset(&pi, 0, sizeof pi);
                    166:        pi.flags = flags;
                    167:        pi.file = path;
1.72      nicm      168:        pi.line = 1;
1.73      nicm      169:        pi.item = item;
1.75      nicm      170:        pi.c = c;
1.13      nicm      171:
1.71      nicm      172:        pr = cmd_parse_from_file(f, &pi);
                    173:        fclose(f);
1.77    ! nicm      174:        if (pr->status == CMD_PARSE_EMPTY)
        !           175:                return (0);
        !           176:        if (pr->status == CMD_PARSE_ERROR) {
        !           177:                cfg_add_cause("%s", pr->error);
        !           178:                free(pr->error);
        !           179:                return (-1);
        !           180:        }
        !           181:        if (flags & CMD_PARSE_PARSEONLY) {
        !           182:                cmd_list_free(pr->cmdlist);
        !           183:                return (0);
        !           184:        }
        !           185:
        !           186:        new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
        !           187:        if (item != NULL)
        !           188:                cmdq_insert_after(item, new_item0);
        !           189:        else
        !           190:                cmdq_append(NULL, new_item0);
        !           191:        cmd_list_free(pr->cmdlist);
        !           192:
        !           193:        if (new_item != NULL)
        !           194:                *new_item = new_item0;
        !           195:        return (0);
        !           196: }
        !           197:
        !           198: int
        !           199: load_cfg_from_buffer(const void *buf, size_t len, const char *path,
        !           200:     struct client *c, struct cmdq_item *item, int flags,
        !           201:     struct cmdq_item **new_item)
        !           202: {
        !           203:        struct cmd_parse_input   pi;
        !           204:        struct cmd_parse_result *pr;
        !           205:        struct cmdq_item        *new_item0;
        !           206:
        !           207:        if (new_item != NULL)
        !           208:                *new_item = NULL;
        !           209:
        !           210:        log_debug("loading %s", path);
        !           211:
        !           212:        memset(&pi, 0, sizeof pi);
        !           213:        pi.flags = flags;
        !           214:        pi.file = path;
        !           215:        pi.line = 1;
        !           216:        pi.item = item;
        !           217:        pi.c = c;
        !           218:
        !           219:        pr = cmd_parse_from_buffer(buf, len, &pi);
1.71      nicm      220:        if (pr->status == CMD_PARSE_EMPTY)
                    221:                return (0);
                    222:        if (pr->status == CMD_PARSE_ERROR) {
                    223:                cfg_add_cause("%s", pr->error);
                    224:                free(pr->error);
                    225:                return (-1);
                    226:        }
                    227:        if (flags & CMD_PARSE_PARSEONLY) {
                    228:                cmd_list_free(pr->cmdlist);
                    229:                return (0);
1.1       nicm      230:        }
1.61      nicm      231:
1.71      nicm      232:        new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
                    233:        if (item != NULL)
                    234:                cmdq_insert_after(item, new_item0);
                    235:        else
1.75      nicm      236:                cmdq_append(NULL, new_item0);
1.71      nicm      237:        cmd_list_free(pr->cmdlist);
1.25      nicm      238:
1.70      nicm      239:        if (new_item != NULL)
1.71      nicm      240:                *new_item = new_item0;
                    241:        return (0);
1.33      nicm      242: }
                    243:
                    244: void
1.36      nicm      245: cfg_add_cause(const char *fmt, ...)
1.33      nicm      246: {
1.36      nicm      247:        va_list  ap;
                    248:        char    *msg;
1.33      nicm      249:
                    250:        va_start(ap, fmt);
                    251:        xvasprintf(&msg, fmt, ap);
1.38      nicm      252:        va_end(ap);
1.33      nicm      253:
1.35      nicm      254:        cfg_ncauses++;
                    255:        cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
                    256:        cfg_causes[cfg_ncauses - 1] = msg;
1.33      nicm      257: }
                    258:
                    259: void
1.50      nicm      260: cfg_print_causes(struct cmdq_item *item)
1.33      nicm      261: {
                    262:        u_int    i;
                    263:
1.35      nicm      264:        for (i = 0; i < cfg_ncauses; i++) {
1.50      nicm      265:                cmdq_print(item, "%s", cfg_causes[i]);
1.35      nicm      266:                free(cfg_causes[i]);
1.33      nicm      267:        }
1.35      nicm      268:
                    269:        free(cfg_causes);
                    270:        cfg_causes = NULL;
1.37      nicm      271:        cfg_ncauses = 0;
1.17      nicm      272: }
                    273:
                    274: void
1.28      nicm      275: cfg_show_causes(struct session *s)
1.17      nicm      276: {
1.66      nicm      277:        struct window_pane              *wp;
                    278:        struct window_mode_entry        *wme;
                    279:        u_int                            i;
1.17      nicm      280:
1.35      nicm      281:        if (s == NULL || cfg_ncauses == 0)
1.17      nicm      282:                return;
                    283:        wp = s->curw->window->active;
                    284:
1.66      nicm      285:        wme = TAILQ_FIRST(&wp->modes);
                    286:        if (wme == NULL || wme->mode != &window_view_mode)
1.65      nicm      287:                window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
1.35      nicm      288:        for (i = 0; i < cfg_ncauses; i++) {
                    289:                window_copy_add(wp, "%s", cfg_causes[i]);
                    290:                free(cfg_causes[i]);
1.17      nicm      291:        }
1.35      nicm      292:
                    293:        free(cfg_causes);
                    294:        cfg_causes = NULL;
1.37      nicm      295:        cfg_ncauses = 0;
1.1       nicm      296: }