1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <[email protected]>
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
29static FILE *log_file;
30static int log_level;
31
32static void log_event_cb(int, const char *);
33static void log_vwrite(const char *, va_list);
34
35/* Log callback for libevent. */
36static void
37log_event_cb(__unused int severity, const char *msg)
38{
39 log_debug("%s", msg);
40}
41
42/* Increment log level. */
43void
44log_add_level(void)
45{
46 log_level++;
47}
48
49/* Get log level. */
50int
51log_get_level(void)
52{
53 return (log_level);
54}
55
56/* Open logging to file. */
57void
58log_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. */
77void
78log_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. */
92void
93log_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. */
103static void
104log_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 if (stravis(&out, fmt, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL) == -1)
115 exit(1);
116
117 gettimeofday(&tv, NULL);
118 if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
119 (int)tv.tv_usec, out) == -1)
120 exit(1);
121 fflush(log_file);
122
123 free(out);
124 free(fmt);
125}
126
127/* Log a debug message. */
128void
129log_debug(const char *msg, ...)
130{
131 va_list ap;
132
133 if (log_file == NULL)
134 return;
135
136 va_start(ap, msg);
137 log_vwrite(msg, ap);
138 va_end(ap);
139}
140
141/* Log a critical error with error string and die. */
142__dead void
143fatal(const char *msg, ...)
144{
145 char *fmt;
146 va_list ap;
147
148 va_start(ap, msg);
149 if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
150 exit(1);
151 log_vwrite(fmt, ap);
152 va_end(ap);
153 exit(1);
154}
155
156/* Log a critical error and die. */
157__dead void
158fatalx(const char *msg, ...)
159{
160 char *fmt;
161 va_list ap;
162
163 va_start(ap, msg);
164 if (asprintf(&fmt, "fatal: %s", msg) == -1)
165 exit(1);
166 log_vwrite(fmt, ap);
167 va_end(ap);
168 exit(1);
169}
170