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