xref: /netbsd-src/external/bsd/tmux/dist/log.c (revision 46548964d21002ed96d2f9f7eeb6357c81c3425c)
199e242abSchristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4f26e8bc9Schristos  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/types.h>
20698d5317Sjmmv 
21698d5317Sjmmv #include <errno.h>
22698d5317Sjmmv #include <stdio.h>
23698d5317Sjmmv #include <stdlib.h>
24698d5317Sjmmv #include <string.h>
25f26e8bc9Schristos #include <unistd.h>
26698d5317Sjmmv 
27698d5317Sjmmv #include "tmux.h"
28698d5317Sjmmv 
29f26e8bc9Schristos static FILE	*log_file;
30f26e8bc9Schristos static int	 log_level;
31698d5317Sjmmv 
3261fba46bSchristos /* Log callback for libevent. */
33f26e8bc9Schristos static void
log_event_cb(__unused int severity,const char * msg)34f26e8bc9Schristos log_event_cb(__unused int severity, const char *msg)
35698d5317Sjmmv {
3699e242abSchristos 	log_debug("%s", msg);
37698d5317Sjmmv }
38698d5317Sjmmv 
39f26e8bc9Schristos /* Increment log level. */
40f26e8bc9Schristos void
log_add_level(void)41f26e8bc9Schristos log_add_level(void)
42f26e8bc9Schristos {
43f26e8bc9Schristos 	log_level++;
44f26e8bc9Schristos }
45f26e8bc9Schristos 
46f26e8bc9Schristos /* Get log level. */
47f26e8bc9Schristos int
log_get_level(void)48f26e8bc9Schristos log_get_level(void)
49f26e8bc9Schristos {
50f26e8bc9Schristos 	return (log_level);
51f26e8bc9Schristos }
52f26e8bc9Schristos 
53698d5317Sjmmv /* Open logging to file. */
54698d5317Sjmmv void
log_open(const char * name)55f26e8bc9Schristos log_open(const char *name)
56698d5317Sjmmv {
57f26e8bc9Schristos 	char	*path;
58f26e8bc9Schristos 
59f26e8bc9Schristos 	if (log_level == 0)
60f26e8bc9Schristos 		return;
61fe99a117Schristos 	log_close();
6299e242abSchristos 
63f26e8bc9Schristos 	xasprintf(&path, "tmux-%s-%ld.log", name, (long)getpid());
64fe99a117Schristos 	log_file = fopen(path, "a");
65f26e8bc9Schristos 	free(path);
66698d5317Sjmmv 	if (log_file == NULL)
67698d5317Sjmmv 		return;
68698d5317Sjmmv 
6999e242abSchristos 	setvbuf(log_file, NULL, _IOLBF, 0);
7061fba46bSchristos 	event_set_log_callback(log_event_cb);
71698d5317Sjmmv }
72698d5317Sjmmv 
73fe99a117Schristos /* Toggle logging. */
74fe99a117Schristos void
log_toggle(const char * name)75fe99a117Schristos log_toggle(const char *name)
76fe99a117Schristos {
77fe99a117Schristos 	if (log_level == 0) {
78fe99a117Schristos 		log_level = 1;
79fe99a117Schristos 		log_open(name);
80fe99a117Schristos 		log_debug("log opened");
81fe99a117Schristos 	} else {
82fe99a117Schristos 		log_debug("log closed");
83fe99a117Schristos 		log_level = 0;
84fe99a117Schristos 		log_close();
85fe99a117Schristos 	}
86fe99a117Schristos }
87fe99a117Schristos 
88698d5317Sjmmv /* Close logging. */
89698d5317Sjmmv void
log_close(void)90698d5317Sjmmv log_close(void)
91698d5317Sjmmv {
9261fba46bSchristos 	if (log_file != NULL)
93698d5317Sjmmv 		fclose(log_file);
9499e242abSchristos 	log_file = NULL;
95698d5317Sjmmv 
9661fba46bSchristos 	event_set_log_callback(NULL);
97698d5317Sjmmv }
98698d5317Sjmmv 
99698d5317Sjmmv /* Write a log message. */
100*46548964Swiz static void printflike(1, 0)
log_vwrite(const char * msg,va_list ap,const char * prefix)101*46548964Swiz log_vwrite(const char *msg, va_list ap, const char *prefix)
102698d5317Sjmmv {
103*46548964Swiz 	char		*s, *out;
10499e242abSchristos 	struct timeval	 tv;
10599e242abSchristos 
10661fba46bSchristos 	if (log_file == NULL)
10761fba46bSchristos 		return;
10861fba46bSchristos 
109*46548964Swiz 	if (vasprintf(&s, msg, ap) == -1)
110e271dbb8Schristos 		return;
111*46548964Swiz 	if (stravis(&out, s, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1) {
112*46548964Swiz 		free(s);
113e271dbb8Schristos 		return;
114e271dbb8Schristos 	}
115*46548964Swiz 	free(s);
11699e242abSchristos 
11799e242abSchristos 	gettimeofday(&tv, NULL);
118*46548964Swiz 	if (fprintf(log_file, "%lld.%06d %s%s\n", (long long)tv.tv_sec,
119*46548964Swiz 	    (int)tv.tv_usec, prefix, out) != -1)
12061fba46bSchristos 		fflush(log_file);
12199e242abSchristos 	free(out);
122698d5317Sjmmv }
123698d5317Sjmmv 
124698d5317Sjmmv /* Log a debug message. */
12599e242abSchristos void
log_debug(const char * msg,...)126698d5317Sjmmv log_debug(const char *msg, ...)
127698d5317Sjmmv {
128698d5317Sjmmv 	va_list	ap;
129698d5317Sjmmv 
13068e6ba84Schristos 	if (log_file == NULL)
13168e6ba84Schristos 		return;
13268e6ba84Schristos 
133698d5317Sjmmv 	va_start(ap, msg);
134*46548964Swiz 	log_vwrite(msg, ap, "");
135698d5317Sjmmv 	va_end(ap);
136698d5317Sjmmv }
137698d5317Sjmmv 
1387e0794aeSjoerg #if __GNUC_PREREQ__(4, 6) || defined(__clang__)
1397e0794aeSjoerg #pragma GCC diagnostic push
1407e0794aeSjoerg #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1417e0794aeSjoerg #endif
1427e0794aeSjoerg 
14399e242abSchristos /* Log a critical error with error string and die. */
144698d5317Sjmmv __dead void
fatal(const char * msg,...)145f26e8bc9Schristos fatal(const char *msg, ...)
146698d5317Sjmmv {
147*46548964Swiz 	char	 tmp[256];
14899e242abSchristos 	va_list	 ap;
149698d5317Sjmmv 
150*46548964Swiz 	if (snprintf(tmp, sizeof tmp, "fatal: %s: ", strerror(errno)) < 0)
151698d5317Sjmmv 		exit(1);
152*46548964Swiz 
153*46548964Swiz 	va_start(ap, msg);
154*46548964Swiz 	log_vwrite(msg, ap, tmp);
155e9a2d6faSchristos 	va_end(ap);
156*46548964Swiz 
157698d5317Sjmmv 	exit(1);
158698d5317Sjmmv }
159698d5317Sjmmv 
160698d5317Sjmmv /* Log a critical error and die. */
16199e242abSchristos __dead void
fatalx(const char * msg,...)162f26e8bc9Schristos fatalx(const char *msg, ...)
163698d5317Sjmmv {
164698d5317Sjmmv 	va_list	 ap;
165698d5317Sjmmv 
166698d5317Sjmmv 	va_start(ap, msg);
167*46548964Swiz 	log_vwrite(msg, ap, "fatal: ");
168e9a2d6faSchristos 	va_end(ap);
169*46548964Swiz 
17099e242abSchristos 	exit(1);
171698d5317Sjmmv }
1727e0794aeSjoerg 
1737e0794aeSjoerg #if __GNUC_PREREQ__(4, 6) || defined(__clang__)
1747e0794aeSjoerg #pragma GCC diagnostic pop
1757e0794aeSjoerg #endif
176