1 | /* $OpenBSD$ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2007 Nicholas Marriott <[email protected]> |
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 | |
21 | #include <errno.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <unistd.h> |
26 | |
27 | #include "tmux.h" |
28 | |
29 | static FILE *log_file; |
30 | static int log_level; |
31 | |
32 | static void log_event_cb(int, const char *); |
33 | static void log_vwrite(const char *, va_list); |
34 | |
35 | /* Log callback for libevent. */ |
36 | static void |
37 | log_event_cb(__unused int severity, const char *msg) |
38 | { |
39 | log_debug("%s" , msg); |
40 | } |
41 | |
42 | /* Increment log level. */ |
43 | void |
44 | log_add_level(void) |
45 | { |
46 | log_level++; |
47 | } |
48 | |
49 | /* Get log level. */ |
50 | int |
51 | log_get_level(void) |
52 | { |
53 | return (log_level); |
54 | } |
55 | |
56 | /* Open logging to file. */ |
57 | void |
58 | log_open(const char *name) |
59 | { |
60 | char *path; |
61 | |
62 | if (log_level == 0) |
63 | return; |
64 | log_close(); |
65 | |
66 | xasprintf(&path, "tmux-%s-%ld.log" , name, (long)getpid()); |
67 | log_file = fopen(path, "a" ); |
68 | free(path); |
69 | if (log_file == NULL) |
70 | return; |
71 | |
72 | setvbuf(log_file, NULL, _IOLBF, 0); |
73 | event_set_log_callback(log_event_cb); |
74 | } |
75 | |
76 | /* Toggle logging. */ |
77 | void |
78 | log_toggle(const char *name) |
79 | { |
80 | if (log_level == 0) { |
81 | log_level = 1; |
82 | log_open(name); |
83 | log_debug("log opened" ); |
84 | } else { |
85 | log_debug("log closed" ); |
86 | log_level = 0; |
87 | log_close(); |
88 | } |
89 | } |
90 | |
91 | /* Close logging. */ |
92 | void |
93 | log_close(void) |
94 | { |
95 | if (log_file != NULL) |
96 | fclose(log_file); |
97 | log_file = NULL; |
98 | |
99 | event_set_log_callback(NULL); |
100 | } |
101 | |
102 | /* Write a log message. */ |
103 | static void |
104 | log_vwrite(const char *msg, va_list ap) |
105 | { |
106 | char *fmt, *out; |
107 | struct timeval tv; |
108 | |
109 | if (log_file == NULL) |
110 | return; |
111 | |
112 | if (vasprintf(&fmt, msg, ap) == -1) |
113 | exit(1); |
114 | if (stravis(&out, fmt, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1) |
115 | exit(1); |
116 | |
117 | gettimeofday(&tv, NULL); |
118 | if (fprintf(log_file, "%lld.%06d %s\n" , (long long)tv.tv_sec, |
119 | (int)tv.tv_usec, out) == -1) |
120 | exit(1); |
121 | fflush(log_file); |
122 | |
123 | free(out); |
124 | free(fmt); |
125 | } |
126 | |
127 | /* Log a debug message. */ |
128 | void |
129 | log_debug(const char *msg, ...) |
130 | { |
131 | va_list ap; |
132 | |
133 | if (log_file == NULL) |
134 | return; |
135 | |
136 | va_start(ap, msg); |
137 | log_vwrite(msg, ap); |
138 | va_end(ap); |
139 | } |
140 | |
141 | /* Log a critical error with error string and die. */ |
142 | __dead void |
143 | fatal(const char *msg, ...) |
144 | { |
145 | char *fmt; |
146 | va_list ap; |
147 | |
148 | va_start(ap, msg); |
149 | if (asprintf(&fmt, "fatal: %s: %s" , msg, strerror(errno)) == -1) |
150 | exit(1); |
151 | log_vwrite(fmt, ap); |
152 | va_end(ap); |
153 | exit(1); |
154 | } |
155 | |
156 | /* Log a critical error and die. */ |
157 | __dead void |
158 | fatalx(const char *msg, ...) |
159 | { |
160 | char *fmt; |
161 | va_list ap; |
162 | |
163 | va_start(ap, msg); |
164 | if (asprintf(&fmt, "fatal: %s" , msg) == -1) |
165 | exit(1); |
166 | log_vwrite(fmt, ap); |
167 | va_end(ap); |
168 | exit(1); |
169 | } |
170 | |