cfg.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <ctype.h>
  19. #include <errno.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include "tmux.h"
  25. #include "tmate.h"
  26. char *cfg_file;
  27. #ifdef TMATE
  28. char *tmate_cfg_file;
  29. #endif
  30. struct cmd_q *cfg_cmd_q;
  31. int cfg_finished;
  32. int cfg_references;
  33. char **cfg_causes;
  34. u_int cfg_ncauses;
  35. struct client *cfg_client;
  36. void cfg_default_done(struct cmd_q *);
  37. void
  38. set_cfg_file(const char *path)
  39. {
  40. free(cfg_file);
  41. cfg_file = xstrdup(path);
  42. }
  43. void
  44. start_cfg(void)
  45. {
  46. char *cause = NULL;
  47. const char *home;
  48. cfg_cmd_q = cmdq_new(NULL);
  49. cfg_cmd_q->emptyfn = cfg_default_done;
  50. cfg_finished = 0;
  51. cfg_references = 1;
  52. cfg_client = TAILQ_FIRST(&clients);
  53. if (cfg_client != NULL)
  54. cfg_client->references++;
  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. if (cfg_file == NULL && (home = find_home()) != NULL) {
  61. xasprintf(&cfg_file, "%s/.tmux.conf", home);
  62. if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
  63. free(cfg_file);
  64. cfg_file = NULL;
  65. }
  66. }
  67. if (cfg_file != NULL && load_cfg(cfg_file, cfg_cmd_q, &cause) == -1)
  68. cfg_add_cause("%s: %s", cfg_file, cause);
  69. free(cause);
  70. #ifdef TMATE
  71. cause = NULL;
  72. if ((home = find_home()) != NULL) {
  73. xasprintf(&tmate_cfg_file, "%s/.tmate.conf", home);
  74. if (access(tmate_cfg_file, R_OK) != 0 && errno == ENOENT) {
  75. free(tmate_cfg_file);
  76. tmate_cfg_file = NULL;
  77. }
  78. }
  79. if (tmate_cfg_file != NULL && load_cfg(tmate_cfg_file, cfg_cmd_q, &cause) == -1)
  80. cfg_add_cause("%s: %s", cfg_file, cause);
  81. free(cause);
  82. #endif
  83. cmdq_continue(cfg_cmd_q);
  84. }
  85. int
  86. load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
  87. {
  88. FILE *f;
  89. char delim[3] = { '\\', '\\', '\0' };
  90. u_int found;
  91. size_t line = 0;
  92. char *buf, *cause1, *p;
  93. struct cmd_list *cmdlist;
  94. log_debug("loading %s", path);
  95. if ((f = fopen(path, "rb")) == NULL) {
  96. xasprintf(cause, "%s: %s", path, strerror(errno));
  97. return (-1);
  98. }
  99. found = 0;
  100. while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
  101. log_debug("%s: %s", path, buf);
  102. /* Skip empty lines. */
  103. p = buf;
  104. while (isspace((u_char) *p))
  105. p++;
  106. if (*p == '\0') {
  107. free(buf);
  108. continue;
  109. }
  110. /* Parse and run the command. */
  111. if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
  112. free(buf);
  113. if (cause1 == NULL)
  114. continue;
  115. cfg_add_cause("%s:%zu: %s", path, line, cause1);
  116. free(cause1);
  117. continue;
  118. }
  119. free(buf);
  120. if (cmdlist == NULL)
  121. continue;
  122. cmdq_append(cmdq, cmdlist, NULL);
  123. cmd_list_free(cmdlist);
  124. found++;
  125. }
  126. fclose(f);
  127. return (found);
  128. }
  129. void
  130. cfg_default_done(__unused struct cmd_q *cmdq)
  131. {
  132. if (--cfg_references != 0)
  133. return;
  134. cfg_finished = 1;
  135. #ifdef TMATE
  136. tmate_session_start();
  137. #endif
  138. if (!RB_EMPTY(&sessions))
  139. cfg_show_causes(RB_MIN(sessions, &sessions));
  140. cmdq_free(cfg_cmd_q);
  141. cfg_cmd_q = NULL;
  142. if (cfg_client != NULL) {
  143. /*
  144. * The client command queue starts with client_exit set to 1 so
  145. * only continue if not empty (that is, we have been delayed
  146. * during configuration parsing for long enough that the
  147. * MSG_COMMAND has arrived), else the client will exit before
  148. * the MSG_COMMAND which might tell it not to.
  149. */
  150. if (!TAILQ_EMPTY(&cfg_client->cmdq->queue))
  151. cmdq_continue(cfg_client->cmdq);
  152. server_client_unref(cfg_client);
  153. cfg_client = NULL;
  154. }
  155. }
  156. void
  157. cfg_add_cause(const char *fmt, ...)
  158. {
  159. va_list ap;
  160. char *msg;
  161. va_start(ap, fmt);
  162. xvasprintf(&msg, fmt, ap);
  163. va_end(ap);
  164. cfg_ncauses++;
  165. cfg_causes = xreallocarray(cfg_causes, cfg_ncauses, sizeof *cfg_causes);
  166. cfg_causes[cfg_ncauses - 1] = msg;
  167. }
  168. void
  169. cfg_print_causes(struct cmd_q *cmdq)
  170. {
  171. u_int i;
  172. for (i = 0; i < cfg_ncauses; i++) {
  173. cmdq_print(cmdq, "%s", cfg_causes[i]);
  174. free(cfg_causes[i]);
  175. }
  176. free(cfg_causes);
  177. cfg_causes = NULL;
  178. cfg_ncauses = 0;
  179. }
  180. void
  181. cfg_show_causes(struct session *s)
  182. {
  183. struct window_pane *wp;
  184. u_int i;
  185. if (s == NULL || cfg_ncauses == 0)
  186. return;
  187. wp = s->curw->window->active;
  188. window_pane_set_mode(wp, &window_copy_mode);
  189. window_copy_init_for_output(wp);
  190. for (i = 0; i < cfg_ncauses; i++) {
  191. window_copy_add(wp, "%s", cfg_causes[i]);
  192. free(cfg_causes[i]);
  193. }
  194. free(cfg_causes);
  195. cfg_causes = NULL;
  196. cfg_ncauses = 0;
  197. }