Annotation of src/usr.bin/tmux/cfg.c, Revision 1.40
1.40 ! nicm 1: /* $OpenBSD: cfg.c,v 1.39 2015/06/05 18:06:30 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2008 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:
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.40 ! nicm 26: #include <unistd.h>
1.32 tobias 27: #include <util.h>
1.1 nicm 28:
29: #include "tmux.h"
30:
1.40 ! nicm 31: struct cmd_q *cfg_cmd_q;
! 32: int cfg_finished;
! 33: int cfg_references;
! 34: char **cfg_causes;
! 35: u_int cfg_ncauses;
! 36: struct client *cfg_client;
! 37:
! 38: void cfg_default_done(struct cmd_q *);
! 39:
! 40: void
! 41: start_cfg(void)
! 42: {
! 43: char *cause = NULL;
! 44:
! 45: cfg_cmd_q = cmdq_new(NULL);
! 46: cfg_cmd_q->emptyfn = cfg_default_done;
! 47:
! 48: cfg_finished = 0;
! 49: cfg_references = 1;
! 50:
! 51: cfg_client = TAILQ_FIRST(&clients);
! 52: if (cfg_client != NULL)
! 53: cfg_client->references++;
! 54:
! 55: if (access(TMUX_CONF, R_OK) == 0) {
! 56: if (load_cfg(TMUX_CONF, cfg_cmd_q, &cause) == -1)
! 57: cfg_add_cause("%s: %s", TMUX_CONF, cause);
! 58: } else if (errno != ENOENT)
! 59: cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno));
! 60:
! 61: if (cfg_file != NULL && load_cfg(cfg_file, cfg_cmd_q, &cause) == -1)
! 62: cfg_add_cause("%s: %s", cfg_file, cause);
! 63: free(cause);
! 64:
! 65: cmdq_continue(cfg_cmd_q);
! 66: }
1.1 nicm 67:
1.28 nicm 68: int
69: load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
1.1 nicm 70: {
1.7 deraadt 71: FILE *f;
1.32 tobias 72: char delim[3] = { '\\', '\\', '\0' };
73: u_int found;
74: size_t line = 0;
1.33 nicm 75: char *buf, *cause1, *p;
1.1 nicm 76: struct cmd_list *cmdlist;
77:
1.29 nicm 78: log_debug("loading %s", path);
1.1 nicm 79: if ((f = fopen(path, "rb")) == NULL) {
1.28 nicm 80: xasprintf(cause, "%s: %s", path, strerror(errno));
81: return (-1);
1.25 nicm 82: }
83:
1.32 tobias 84: found = 0;
85: while ((buf = fparseln(f, NULL, &line, delim, 0))) {
86: log_debug("%s: %s", path, buf);
1.13 nicm 87:
1.21 nicm 88: /* Skip empty lines. */
1.32 tobias 89: p = buf;
90: while (isspace((u_char) *p))
91: p++;
92: if (*p == '\0') {
93: free(buf);
1.21 nicm 94: continue;
1.22 nicm 95: }
1.21 nicm 96:
1.28 nicm 97: /* Parse and run the command. */
1.32 tobias 98: if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
99: free(buf);
1.28 nicm 100: if (cause1 == NULL)
1.1 nicm 101: continue;
1.33 nicm 102: cfg_add_cause("%s:%zu: %s", path, line, cause1);
1.28 nicm 103: free(cause1);
1.9 nicm 104: continue;
1.20 nicm 105: }
1.32 tobias 106: free(buf);
1.28 nicm 107:
1.1 nicm 108: if (cmdlist == NULL)
109: continue;
1.34 nicm 110: cmdq_append(cmdq, cmdlist, NULL);
1.1 nicm 111: cmd_list_free(cmdlist);
1.28 nicm 112: found++;
1.1 nicm 113: }
114: fclose(f);
1.25 nicm 115:
1.28 nicm 116: return (found);
117: }
118:
119: void
120: cfg_default_done(unused struct cmd_q *cmdq)
121: {
122: if (--cfg_references != 0)
123: return;
124: cfg_finished = 1;
1.18 nicm 125:
1.28 nicm 126: if (!RB_EMPTY(&sessions))
127: cfg_show_causes(RB_MIN(sessions, &sessions));
1.1 nicm 128:
1.28 nicm 129: cmdq_free(cfg_cmd_q);
130: cfg_cmd_q = NULL;
1.30 nicm 131:
132: if (cfg_client != NULL) {
133: /*
134: * The client command queue starts with client_exit set to 1 so
135: * only continue if not empty (that is, we have been delayed
136: * during configuration parsing for long enough that the
137: * MSG_COMMAND has arrived), else the client will exit before
138: * the MSG_COMMAND which might tell it not to.
139: */
140: if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
141: cmdq_continue(cfg_client->cmdq);
1.39 nicm 142: server_client_unref(cfg_client);
1.30 nicm 143: cfg_client = NULL;
144: }
1.33 nicm 145: }
146:
147: void
1.36 nicm 148: cfg_add_cause(const char *fmt, ...)
1.33 nicm 149: {
1.36 nicm 150: va_list ap;
151: char *msg;
1.33 nicm 152:
153: va_start(ap, fmt);
154: xvasprintf(&msg, fmt, ap);
1.38 nicm 155: va_end(ap);
1.33 nicm 156:
1.35 nicm 157: cfg_ncauses++;
158: cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
159: cfg_causes[cfg_ncauses - 1] = msg;
1.33 nicm 160: }
161:
162: void
163: cfg_print_causes(struct cmd_q *cmdq)
164: {
165: u_int i;
166:
1.35 nicm 167: for (i = 0; i < cfg_ncauses; i++) {
168: cmdq_print(cmdq, "%s", cfg_causes[i]);
169: free(cfg_causes[i]);
1.33 nicm 170: }
1.35 nicm 171:
172: free(cfg_causes);
173: cfg_causes = NULL;
1.37 nicm 174: cfg_ncauses = 0;
1.17 nicm 175: }
176:
177: void
1.28 nicm 178: cfg_show_causes(struct session *s)
1.17 nicm 179: {
180: struct window_pane *wp;
181: u_int i;
182:
1.35 nicm 183: if (s == NULL || cfg_ncauses == 0)
1.17 nicm 184: return;
185: wp = s->curw->window->active;
186:
187: window_pane_set_mode(wp, &window_copy_mode);
188: window_copy_init_for_output(wp);
1.35 nicm 189: for (i = 0; i < cfg_ncauses; i++) {
190: window_copy_add(wp, "%s", cfg_causes[i]);
191: free(cfg_causes[i]);
1.17 nicm 192: }
1.35 nicm 193:
194: free(cfg_causes);
195: cfg_causes = NULL;
1.37 nicm 196: cfg_ncauses = 0;
1.1 nicm 197: }