| LIRC libraries LinuxInfraredRemoteControl

lirc_log.c
Go to the documentation of this file.
1 /****************************************************************************
2 ** lircd.c *****************************************************************
3 ****************************************************************************
4 *
5 * lirc_log - simple logging module.
6 *
7 *
8 */
9
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19
20
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <time.h>
28 #include <pwd.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <ctype.h>
32 #include <syslog.h>
33
34 #include "lirc/lirc_log.h"
35
36 #ifndef min
37 #define min(a, b) (a < b ? a : b)
38 #endif
39
40 #define HOSTNAME_LEN 128
41
42 static const logchannel_t logchannel = LOG_LIB;
43
44 char hostname[HOSTNAME_LEN + 1];
45 FILE* lf = NULL;
46
47 loglevel_t loglevel = LIRC_NOLOG;
48
49 logchannel_t logged_channels = LOG_ALL;
50
51 static int use_syslog = 1;
52
53 const char* syslogident = "lircd-" VERSION;
54 const char* logfile = "syslog";
55
56 char progname[128] = { '?', '\0' };
57 static int nodaemon = 0;
58
59 static const int PRIO_LEN = 16;
62 static const char* prio2text(int prio)
63 {
64 switch (prio) {
65 case LIRC_DEBUG: return "Debug";
66 case LIRC_NOTICE: return "Notice";
67 case LIRC_INFO: return "Info";
68 case LIRC_WARNING: return "Warning";
69 case LIRC_ERROR: return "Error";
70 case LIRC_TRACE: return "Trace";
71 case LIRC_TRACE1: return "Trace1";
72 case LIRC_TRACE2: return "Trace2";
73 default: return "(Bad prio)";
74 }
75 }
76
77
78 int lirc_log_use_syslog(void)
79 {
80 return use_syslog;
81 }
82
83
84 void lirc_log_set_file(const char* s)
85 {
86 if (strcmp(s, "syslog") == 0) {
87 use_syslog = 1;
88 } else {
89 logfile = s;
90 use_syslog = 0;
91 }
92 }
93
94
95 int lirc_log_open(const char* _progname, int _nodaemon, loglevel_t level)
96 {
97 strncpy(progname, _progname, sizeof(progname));
98 nodaemon = _nodaemon;
99 loglevel = level;
100 struct passwd* pw;
101 const char* user;
102
103 if (use_syslog) {
104 if (nodaemon)
105 openlog(syslogident, LOG_CONS | LOG_PID | LOG_PERROR, LOG_LOCAL0);
106 else
107 openlog(syslogident, LOG_CONS | LOG_PID, LOG_LOCAL0);
108 } else {
109 lf = fopen(logfile, "a");
110 if (lf == NULL) {
111 fprintf(stderr, "%s: could not open logfile \"%s\"\n",
112 progname, logfile);
113 perror(progname);
114 return 1;
115 }
116 if (getenv("SUDO_USER") != NULL && geteuid() == 0) {
117 user = getenv("SUDO_USER");
118 user = user == NULL ? "root" : user;
119 pw = getpwnam(user);
120 if (chown(logfile, pw->pw_uid, pw->pw_gid) == -1)
121 perror("Cannot reset log file owner.");
122 }
123 gethostname(hostname, HOSTNAME_LEN);
124 }
125 if (getenv("LIRC_LOGCHANNEL") != NULL) {
126 logged_channels = atoi(getenv("LIRC_LOGCHANNEL")); // FIXME...
127 }
128 if (level != LIRC_NOLOG) {
129 logprintf(level, "%s: Opening log, level: %s",
130 _progname, prio2text(level));
131 }
132 return 0;
133 }
134
135
136 int lirc_log_close(void)
137 {
138 if (use_syslog) {
139 closelog();
140 return 0;
141 } else if (lf) {
142 return fclose(lf);
143 } else {
144 return 0;
145 }
146 }
147
148
149 int lirc_log_reopen(void)
150 {
151 struct stat s;
152
153 if (use_syslog)
154 /* Don't need to do anything; this is syslogd's task */
155 return 0;
156
157 log_info("closing logfile");
158 if (-1 == fstat(fileno(lf), &s)) {
159 perror("Invalid logfile!");
160 return -1;
161 }
162 fclose(lf);
163 lf = fopen(logfile, "a");
164 if (lf == NULL) {
165 /* can't print any error messagees */
166 perror("Can't open logfile");
167 return -1;
168 }
169 log_info("reopened logfile");
170 if (-1 == fchmod(fileno(lf), s.st_mode)) {
171 log_warn("could not set file permissions");
172 logperror(LIRC_WARNING, NULL);
173 }
174 return 0;
175 }
176
177
178 int lirc_log_setlevel(loglevel_t level)
179 {
180 if (level >= LIRC_MIN_LOGLEVEL && level <= LIRC_MAX_LOGLEVEL) {
181 loglevel = level;
182 return 1;
183 } else {
184 return 0;
185 }
186 }
187
188
189 static loglevel_t symbol2loglevel(const char* levelstring)
190 {
191 static const struct { const char* label; int value; } options[] = {
192 { "TRACE2", LIRC_TRACE2 },
193 { "TRACE1", LIRC_TRACE1 },
194 { "TRACE", LIRC_TRACE },
195 { "DEBUG", LIRC_DEBUG },
196 { "INFO", LIRC_INFO },
197 { "NOTICE", LIRC_NOTICE },
198 { "WARNING", LIRC_WARNING },
199 { "ERROR", LIRC_ERROR },
200 { 0, 0 }
201 };
202
203 char label[128];
204 int i;
205
206 if (levelstring == NULL || !*levelstring)
207 return LIRC_BADLEVEL;
208 for (i = 0; i < sizeof(label) && levelstring[i]; i += 1)
209 label[i] = toupper(levelstring[i]);
210 label[i] = '\0';
211 i = 0;
212 while (options[i].label && strcmp(options[i].label, label) != 0)
213 i += 1;
214 return options[i].label ? options[i].value : -1;
215 }
216
217
218 loglevel_t lirc_log_defaultlevel(void)
219 // Try to parse LIRC_LOGLEVEL in environment, fall back to DEFAULT_LOGLEVEL.
220 {
221 loglevel_t try;
222 const char* const level = getenv("LIRC_LOGLEVEL");
223
224 if (level != NULL) {
225 try = string2loglevel(level);
226 return try == LIRC_BADLEVEL ? DEFAULT_LOGLEVEL : try;
227 } else {
228 return DEFAULT_LOGLEVEL;
229 }
230 }
231
232
233 loglevel_t string2loglevel(const char* s)
234 {
235 long level = LONG_MAX;
236
237 if (s == NULL || *s == '\0')
238 return LIRC_BADLEVEL;
239 while (isspace(*s) && *s)
240 s++;
241 if (isdigit(*s)) {
242 level = strtol(s, NULL, 10);
243 if (level > LIRC_MAX_LOGLEVEL || level < LIRC_MIN_LOGLEVEL)
244 return LIRC_BADLEVEL;
245 else
246 return level;
247 } else {
248 return symbol2loglevel(s);
249 }
250 }
251
252
253 void perrorf(const char* format, ...)
254 {
255 char buff[256];
256 va_list ap;
257
258 va_start(ap, format);
259 vsnprintf(buff, sizeof(buff), format, ap);
260 va_end(ap);
261 perror(buff);
262 }
263
264
272 void logprintf(loglevel_t prio, const char* format_str, ...)
273 {
274 int save_errno = errno;
275 va_list ap;
276 char buff[PRIO_LEN + strlen(format_str)];
277 #ifdef SYSTEMD_LOGPERROR_FIX
278 if (nodaemon && prio <= loglevel) {
279 fprintf(stderr, "%s: %s ", progname, prio2text(prio));
280 va_start(ap, format_str);
281 vfprintf(stderr, format_str, ap);
282 va_end(ap);
283 fputc('\n', stderr);
284 fflush(stderr);
285 }
286 #endif
287 if (use_syslog) {
288 snprintf(buff, sizeof(buff),
289 "%s: %s", prio2text(prio), format_str);
290 va_start(ap, format_str);
291 vsyslog(min(7, prio), buff, ap);
292 va_end(ap);
293 } else if (lf) {
294 char* currents;
295 struct timeval tv;
296 struct timezone tz;
297
298 gettimeofday(&tv, &tz);
299 currents = ctime(&tv.tv_sec);
300
301 fprintf(lf, "%15.15s.%06ld %s %s: ",
302 currents + 4, (long) tv.tv_usec, hostname, progname);
303 fprintf(lf, "%s: ", prio2text(prio));
304 va_start(ap, format_str);
305 vfprintf(lf, format_str, ap);
306 va_end(ap);
307 fputc('\n', lf);
308 fflush(lf);
309 }
310 errno = save_errno;
311 }
312
318 void logperror(loglevel_t prio, const char* fmt, ...)
319 {
320 char s[256];
321 va_list ap;
322
323 va_start(ap, fmt);
324 vsnprintf(s, sizeof(s), fmt, ap);
325 va_end(ap);
326 if (use_syslog) {
327 if (*s != '\0')
328 syslog(min(7, prio), "%s: %m\n", s);
329 else
330 syslog(min(7, prio), "%m\n");
331 } else {
332 if (*s != '\0')
333 logprintf(prio, "%s: %s", s, strerror(errno));
334 else
335 logprintf(prio, "%s", strerror(errno));
336 }
337 }
338
339
340 int lirc_log_get_clientlog(const char* basename, char* buffer, ssize_t size)
341 {
342 const char* home;
343 struct passwd* pw;
344 const char* user;
345 int r;
346
347 if (getenv("XDG_CACHE_HOME") != NULL) {
348 strncpy(buffer, getenv("XDG_CACHE_HOME"), size);
349 buffer[size - 1] = '\0';
350 } else if (getenv("SUDO_USER") != NULL && geteuid() == 0) {
351 user = getenv("SUDO_USER");
352 if (user == NULL)
353 user = "root";
354 pw = getpwnam(user);
355 snprintf(buffer, size, "%s/.cache", pw->pw_dir);
356 } else {
357 home = getenv("HOME");
358 home = home != NULL ? home : "/tmp";
359 snprintf(buffer, size, "%s/.cache", home);
360 }
361 if (access(buffer, F_OK) != 0) {
362 r = mkdir(buffer, 0777);
363 if (r != 0) {
364 syslog(LOG_WARNING,
365 "Cannot create log directory %s", buffer);
366 syslog(LOG_WARNING, "Falling back to using /tmp");
367 strcpy(buffer, "/tmp");
368 }
369 }
370 strncat(buffer, "/", size - strlen(buffer) - 1);
371 strncat(buffer, basename, size - strlen(buffer) - 1);
372 strncat(buffer, ".log", size - strlen(buffer) - 1);
373 return 0;
374 }
375
376
377 void hexdump(char* prefix, unsigned char* buf, int len)
378 // Dump a byte array as hex code, adding a prefix.
379 {
380 int i;
381 char str[1024];
382 int pos = 0;
383
384 if (prefix != NULL) {
385 strncpy(str, prefix, sizeof(str));
386 pos = strnlen(str, sizeof(str));
387 }
388 if (len > 0) {
389 for (i = 0; i < len; i++) {
390 if (pos + 3 >= sizeof(str))
391 break;
392
393 if (!(i % 8))
394 str[pos++] = ' ';
395
396 sprintf(str + pos, "%02x ", buf[i]);
397
398 pos += 3;
399 }
400 } else {
401 strncpy(str + pos, "NO DATA", sizeof(str));
402 }
403 log_trace("%s", str);
404 }
LIRC_MAX_LOGLEVEL
#define LIRC_MAX_LOGLEVEL
Definition: lirc_log.h:61
loglevel
loglevel_t loglevel
Definition: lirc_log.c:47
lirc_log_open
int lirc_log_open(const char *_progname, int _nodaemon, loglevel_t level)
Definition: lirc_log.c:95
log_warn
#define log_warn(fmt,...)
Definition: lirc_log.h:109
logchannel_t
logchannel_t
Definition: lirc_log.h:53
lirc_log_close
int lirc_log_close(void)
Definition: lirc_log.c:136
loglevel_t
loglevel_t
Definition: lirc_log.h:36
lirc_log_set_file
void lirc_log_set_file(const char *s)
Definition: lirc_log.c:84
lirc_log_use_syslog
int lirc_log_use_syslog(void)
Definition: lirc_log.c:78
log_trace
#define log_trace(fmt,...)
Definition: lirc_log.h:129
logged_channels
logchannel_t logged_channels
Definition: lirc_log.c:49
LIRC_MIN_LOGLEVEL
#define LIRC_MIN_LOGLEVEL
Definition: lirc_log.h:64
DEFAULT_LOGLEVEL
#define DEFAULT_LOGLEVEL
Definition: lirc_log.h:79
lirc_log_setlevel
int lirc_log_setlevel(loglevel_t level)
Definition: lirc_log.c:178
hexdump
void hexdump(char *prefix, unsigned char *buf, int len)
Definition: lirc_log.c:377
lirc_log_defaultlevel
loglevel_t lirc_log_defaultlevel(void)
Definition: lirc_log.c:218
logperror
void logperror(loglevel_t prio, const char *fmt,...)
Definition: lirc_log.c:318
lirc_log_get_clientlog
int lirc_log_get_clientlog(const char *basename, char *buffer, ssize_t size)
Definition: lirc_log.c:340
string2loglevel
loglevel_t string2loglevel(const char *s)
Definition: lirc_log.c:233
log_info
#define log_info(fmt,...)
Definition: lirc_log.h:114
logprintf
void logprintf(loglevel_t prio, const char *format_str,...)
Definition: lirc_log.c:272
perrorf
void perrorf(const char *format,...)
Definition: lirc_log.c:253