1 /* Id */ 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 /* Log file, if needed. */ 31 FILE *log_file; 32 33 /* Debug level. */ 34 int log_level = 0; 35 36 void log_event_cb(int, const char *); 37 void log_vwrite(const char *, va_list) __printflike(1, 0); 38 __dead void log_vfatal(const char *, va_list); 39 40 /* Log callback for libevent. */ 41 void 42 log_event_cb(unused int severity, const char *msg) 43 { 44 log_warnx("%s", msg); 45 } 46 47 /* Open logging to file. */ 48 void 49 log_open(int level, const char *path) 50 { 51 log_file = fopen(path, "w"); 52 if (log_file == NULL) 53 return; 54 log_level = level; 55 56 setlinebuf(log_file); 57 event_set_log_callback(log_event_cb); 58 59 tzset(); 60 } 61 62 /* Close logging. */ 63 void 64 log_close(void) 65 { 66 if (log_file != NULL) 67 fclose(log_file); 68 69 event_set_log_callback(NULL); 70 } 71 72 /* Write a log message. */ 73 void 74 log_vwrite(const char *msg, va_list ap) 75 { 76 if (log_file == NULL) 77 return; 78 79 if (vfprintf(log_file, msg, ap) == -1) 80 exit(1); 81 if (fprintf(log_file, "\n") == -1) 82 exit(1); 83 fflush(log_file); 84 } 85 86 /* Log a warning with error string. */ 87 #if __GNUC_PREREQ__(4, 6) || defined(__clang__) 88 #pragma GCC diagnostic push 89 #endif 90 #if __GNUC_PREREQ__(4, 5) || defined(__clang__) 91 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 92 #endif 93 void printflike1 94 log_warn(const char *msg, ...) 95 { 96 va_list ap; 97 char *fmt; 98 99 va_start(ap, msg); 100 if (asprintf(&fmt, "%s: %s", msg, strerror(errno)) == -1) 101 exit(1); 102 log_vwrite(fmt, ap); 103 free(fmt); 104 va_end(ap); 105 } 106 #if __GNUC_PREREQ__(4, 6) || defined(__clang__) 107 #pragma GCC diagnostic push 108 #endif 109 110 /* Log a warning. */ 111 void printflike1 112 log_warnx(const char *msg, ...) 113 { 114 va_list ap; 115 116 va_start(ap, msg); 117 log_vwrite(msg, ap); 118 va_end(ap); 119 } 120 121 /* Log an informational message. */ 122 void printflike1 123 log_info(const char *msg, ...) 124 { 125 va_list ap; 126 127 if (log_level > -1) { 128 va_start(ap, msg); 129 log_vwrite(msg, ap); 130 va_end(ap); 131 } 132 } 133 134 /* Log a debug message. */ 135 void printflike1 136 log_debug(const char *msg, ...) 137 { 138 va_list ap; 139 140 if (log_level > 0) { 141 va_start(ap, msg); 142 log_vwrite(msg, ap); 143 va_end(ap); 144 } 145 } 146 147 /* Log a debug message at level 2. */ 148 void printflike1 149 log_debug2(const char *msg, ...) 150 { 151 va_list ap; 152 153 if (log_level > 1) { 154 va_start(ap, msg); 155 log_vwrite(msg, ap); 156 va_end(ap); 157 } 158 } 159 160 /* Log a critical error, with error string if necessary, and die. */ 161 __dead void 162 log_vfatal(const char *msg, va_list ap) 163 { 164 char *fmt; 165 166 if (errno != 0) { 167 if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) 168 exit(1); 169 log_vwrite(fmt, ap); 170 } else { 171 if (asprintf(&fmt, "fatal: %s", msg) == -1) 172 exit(1); 173 log_vwrite(fmt, ap); 174 } 175 free(fmt); 176 177 exit(1); 178 } 179 180 /* Log a critical error, with error string, and die. */ 181 __dead void printflike1 182 log_fatal(const char *msg, ...) 183 { 184 va_list ap; 185 186 va_start(ap, msg); 187 log_vfatal(msg, ap); 188 } 189 190 /* Log a critical error and die. */ 191 __dead void printflike1 192 log_fatalx(const char *msg, ...) 193 { 194 va_list ap; 195 196 errno = 0; 197 va_start(ap, msg); 198 log_vfatal(msg, ap); 199 } 200