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