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