1 /* $Id: log.c,v 1.6 2014/01/23 14:14:23 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 34 int log_type = LOG_TYPE_OFF; 35 36 /* Log file, if needed. */ 37 FILE *log_file; 38 39 /* Debug level. */ 40 int log_level; 41 42 void log_vwrite(int, const char *, va_list) __printflike(2, 0); 43 __dead void log_vfatal(const char *, va_list); 44 45 /* Open logging to tty. */ 46 void 47 log_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. */ 59 void 60 log_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. */ 75 void 76 log_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. */ 85 void 86 log_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. */ 108 #if __GNUC_PREREQ__(4, 6) || defined(__clang__) 109 #pragma GCC diagnostic push 110 #endif 111 #if __GNUC_PREREQ__(4, 5) || defined(__clang__) 112 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 113 #endif 114 void printflike1 115 log_warn(const char *msg, ...) 116 { 117 va_list ap; 118 char *fmt; 119 120 va_start(ap, msg); 121 if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) 122 exit(1); 123 log_vwrite(LOG_CRIT, fmt, ap); 124 free(fmt); 125 va_end(ap); 126 } 127 #if __GNUC_PREREQ__(4, 6) || defined(__clang__) 128 #pragma GCC diagnostic push 129 #endif 130 131 /* Log a warning. */ 132 void printflike1 133 log_warnx(const char *msg, ...) 134 { 135 va_list ap; 136 137 va_start(ap, msg); 138 log_vwrite(LOG_CRIT, msg, ap); 139 va_end(ap); 140 } 141 142 /* Log an informational message. */ 143 void printflike1 144 log_info(const char *msg, ...) 145 { 146 va_list ap; 147 148 if (log_level > -1) { 149 va_start(ap, msg); 150 log_vwrite(LOG_INFO, msg, ap); 151 va_end(ap); 152 } 153 } 154 155 /* Log a debug message. */ 156 void printflike1 157 log_debug(const char *msg, ...) 158 { 159 va_list ap; 160 161 if (log_level > 0) { 162 va_start(ap, msg); 163 log_vwrite(LOG_DEBUG, msg, ap); 164 va_end(ap); 165 } 166 } 167 168 /* Log a debug message at level 2. */ 169 void printflike1 170 log_debug2(const char *msg, ...) 171 { 172 va_list ap; 173 174 if (log_level > 1) { 175 va_start(ap, msg); 176 log_vwrite(LOG_DEBUG, msg, ap); 177 va_end(ap); 178 } 179 } 180 181 /* Log a critical error, with error string if necessary, and die. */ 182 __dead void 183 log_vfatal(const char *msg, va_list ap) 184 { 185 char *fmt; 186 187 if (errno != 0) { 188 if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) 189 exit(1); 190 log_vwrite(LOG_CRIT, fmt, ap); 191 } else { 192 if (asprintf(&fmt, "fatal: %s", msg) == -1) 193 exit(1); 194 log_vwrite(LOG_CRIT, fmt, ap); 195 } 196 free(fmt); 197 198 exit(1); 199 } 200 201 /* Log a critical error, with error string, and die. */ 202 __dead void printflike1 203 log_fatal(const char *msg, ...) 204 { 205 va_list ap; 206 207 va_start(ap, msg); 208 log_vfatal(msg, ap); 209 } 210 211 /* Log a critical error and die. */ 212 __dead void printflike1 213 log_fatalx(const char *msg, ...) 214 { 215 va_list ap; 216 217 errno = 0; 218 va_start(ap, msg); 219 log_vfatal(msg, ap); 220 } 221