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