xref: /netbsd-src/external/bsd/tmux/dist/log.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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) printflike(1, 0);
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 		return;
114 	if (stravis(&out, fmt, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1) {
115 		free(fmt);
116 		return;
117 	}
118 
119 	gettimeofday(&tv, NULL);
120 	if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
121 	    (int)tv.tv_usec, out) != -1)
122 		fflush(log_file);
123 
124 	free(out);
125 	free(fmt);
126 }
127 
128 /* Log a debug message. */
129 void
130 log_debug(const char *msg, ...)
131 {
132 	va_list	ap;
133 
134 	if (log_file == NULL)
135 		return;
136 
137 	va_start(ap, msg);
138 	log_vwrite(msg, ap);
139 	va_end(ap);
140 }
141 
142 #if __GNUC_PREREQ__(4, 6) || defined(__clang__)
143 #pragma GCC diagnostic push
144 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
145 #endif
146 
147 /* Log a critical error with error string and die. */
148 __dead void
149 fatal(const char *msg, ...)
150 {
151 	char	*fmt;
152 	va_list	 ap;
153 
154 	va_start(ap, msg);
155 	if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
156 		exit(1);
157 	log_vwrite(fmt, ap);
158 	va_end(ap);
159 	exit(1);
160 }
161 
162 /* Log a critical error and die. */
163 __dead void
164 fatalx(const char *msg, ...)
165 {
166 	char	*fmt;
167 	va_list	 ap;
168 
169 	va_start(ap, msg);
170 	if (asprintf(&fmt, "fatal: %s", msg) == -1)
171 		exit(1);
172 	log_vwrite(fmt, ap);
173 	va_end(ap);
174 	exit(1);
175 }
176 
177 #if __GNUC_PREREQ__(4, 6) || defined(__clang__)
178 #pragma GCC diagnostic pop
179 #endif
180