1/* $Id: log.c,v 1.2 2011/08/25 16:41:51 joerg Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 <syslog.h>
26#include <time.h>
27
28#include "tmux.h"
29
30/* Logging type. */
31#define LOG_TYPE_OFF 0
32#define LOG_TYPE_TTY 1
33#define LOG_TYPE_FILE 2
34int	log_type = LOG_TYPE_OFF;
35
36/* Log file, if needed. */
37FILE   *log_file;
38
39/* Debug level. */
40int	log_level;
41
42void		 log_vwrite(int, const char *, va_list);
43__dead void	 log_vfatal(const char *, va_list);
44
45/* Open logging to tty. */
46void
47log_open_tty(int level)
48{
49	log_type = LOG_TYPE_TTY;
50	log_level = level;
51
52	setlinebuf(stderr);
53	setlinebuf(stdout);
54
55	tzset();
56}
57
58/* Open logging to file. */
59void
60log_open_file(int level, const char *path)
61{
62	log_file = fopen(path, "w");
63	if (log_file == NULL)
64		return;
65
66	log_type = LOG_TYPE_FILE;
67	log_level = level;
68
69	setlinebuf(log_file);
70
71	tzset();
72}
73
74/* Close logging. */
75void
76log_close(void)
77{
78	if (log_type == LOG_TYPE_FILE)
79		fclose(log_file);
80
81	log_type = LOG_TYPE_OFF;
82}
83
84/* Write a log message. */
85void
86log_vwrite(int pri, const char *msg, va_list ap)
87{
88	FILE	*f = log_file;
89
90	switch (log_type) {
91	case LOG_TYPE_TTY:
92		if (pri == LOG_INFO)
93			f = stdout;
94		else
95			f = stderr;
96		/* FALLTHROUGH */
97	case LOG_TYPE_FILE:
98		if (vfprintf(f, msg, ap) == -1)
99			exit(1);
100		if (putc('\n', f) == -1)
101			exit(1);
102		fflush(f);
103		break;
104	}
105}
106
107/* Log a warning with error string. */
108void printflike1
109log_warn(const char *msg, ...)
110{
111	va_list	 ap;
112	char	*fmt;
113
114	va_start(ap, msg);
115	if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1)
116		exit(1);
117	log_vwrite(LOG_CRIT, fmt, ap);
118	free(fmt);
119	va_end(ap);
120}
121
122/* Log a warning. */
123void printflike1
124log_warnx(const char *msg, ...)
125{
126	va_list	ap;
127
128	va_start(ap, msg);
129	log_vwrite(LOG_CRIT, msg, ap);
130	va_end(ap);
131}
132
133/* Log an informational message. */
134void printflike1
135log_info(const char *msg, ...)
136{
137	va_list	ap;
138
139	if (log_level > -1) {
140		va_start(ap, msg);
141		log_vwrite(LOG_INFO, msg, ap);
142		va_end(ap);
143	}
144}
145
146/* Log a debug message. */
147void printflike1
148log_debug(const char *msg, ...)
149{
150	va_list	ap;
151
152	if (log_level > 0) {
153		va_start(ap, msg);
154		log_vwrite(LOG_DEBUG, msg, ap);
155		va_end(ap);
156	}
157}
158
159/* Log a debug message at level 2. */
160void printflike1
161log_debug2(const char *msg, ...)
162{
163	va_list	ap;
164
165	if (log_level > 1) {
166		va_start(ap, msg);
167		log_vwrite(LOG_DEBUG, msg, ap);
168		va_end(ap);
169	}
170}
171
172/* Log a critical error, with error string if necessary, and die. */
173__dead void
174log_vfatal(const char *msg, va_list ap)
175{
176	char	*fmt;
177
178	if (errno != 0) {
179		if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
180			exit(1);
181		log_vwrite(LOG_CRIT, fmt, ap);
182	} else {
183		if (asprintf(&fmt, "fatal: %s", msg) == -1)
184			exit(1);
185		log_vwrite(LOG_CRIT, fmt, ap);
186	}
187	free(fmt);
188
189	exit(1);
190}
191
192/* Log a critical error, with error string, and die. */
193__dead void printflike1
194log_fatal(const char *msg, ...)
195{
196	va_list	ap;
197
198	va_start(ap, msg);
199	log_vfatal(msg, ap);
200}
201
202/* Log a critical error and die. */
203__dead void printflike1
204log_fatalx(const char *msg, ...)
205{
206	va_list	ap;
207
208	errno = 0;
209	va_start(ap, msg);
210	log_vfatal(msg, ap);
211}
212