LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
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
42static const logchannel_t logchannel = LOG_LIB;
43
44char hostname[HOSTNAME_LEN + 1];
45FILE* lf = NULL;
46
47loglevel_t loglevel = LIRC_NOLOG;
48
50
51static int use_syslog = 1;
52
53const char* syslogident = "lircd-" VERSION;
54const char* logfile = "syslog";
55
56char progname[128] = { '?', '\0' };
57static int nodaemon = 0;
58
59static const int PRIO_LEN = 16;
62static 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
79{
80 return use_syslog;
81}
82
83
84void 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
95int 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 log_warn("------------------------ Log re-opened ----------------------------");
125 }
126 if (getenv("LIRC_LOGCHANNEL") != NULL) {
127 logged_channels = atoi(getenv("LIRC_LOGCHANNEL")); // FIXME...
128 }
129 if (level != LIRC_NOLOG) {
130 logprintf(level, "%s: Opening log, level: %s",
131 _progname, prio2text(level));
132 }
133 return 0;
134}
135
136
138{
139 if (use_syslog) {
140 closelog();
141 return 0;
142 } else if (lf) {
143 return fclose(lf);
144 } else {
145 return 0;
146 }
147}
148
149
150int lirc_log_reopen(void)
151{
152 struct stat s;
153
154 if (use_syslog)
155 /* Don't need to do anything; this is syslogd's task */
156 return 0;
157
158 log_info("closing logfile");
159 if (-1 == fstat(fileno(lf), &s)) {
160 perror("Invalid logfile!");
161 return -1;
162 }
163 fclose(lf);
164 lf = fopen(logfile, "a");
165 if (lf == NULL) {
166 /* can't print any error messagees */
167 perror("Can't open logfile");
168 return -1;
169 }
170 log_info("reopened logfile");
171 if (-1 == fchmod(fileno(lf), s.st_mode)) {
172 log_warn("could not set file permissions");
173 logperror(LIRC_WARNING, NULL);
174 }
175 return 0;
176}
177
178
180{
181 if (level >= LIRC_MIN_LOGLEVEL && level <= LIRC_MAX_LOGLEVEL) {
182 loglevel = level;
183 return 1;
184 } else {
185 return 0;
186 }
187}
188
189
190static loglevel_t symbol2loglevel(const char* levelstring)
191{
192 static const struct { const char* label; int value; } options[] = {
193 { "TRACE2", LIRC_TRACE2 },
194 { "TRACE1", LIRC_TRACE1 },
195 { "TRACE", LIRC_TRACE },
196 { "DEBUG", LIRC_DEBUG },
197 { "INFO", LIRC_INFO },
198 { "NOTICE", LIRC_NOTICE },
199 { "WARNING", LIRC_WARNING },
200 { "ERROR", LIRC_ERROR },
201 { 0, 0 }
202 };
203
204 char label[128];
205 int i;
206
207 if (levelstring == NULL || !*levelstring)
208 return LIRC_BADLEVEL;
209 for (i = 0; i < sizeof(label) && levelstring[i]; i += 1)
210 label[i] = toupper(levelstring[i]);
211 label[i] = '\0';
212 i = 0;
213 while (options[i].label && strcmp(options[i].label, label) != 0)
214 i += 1;
215 return options[i].label ? options[i].value : -1;
216}
217
218
220// Try to parse LIRC_LOGLEVEL in environment, fall back to DEFAULT_LOGLEVEL.
221{
222 loglevel_t try;
223 const char* const level = getenv("LIRC_LOGLEVEL");
224
225 if (level != NULL) {
226 try = string2loglevel(level);
227 return try == LIRC_BADLEVEL ? DEFAULT_LOGLEVEL : try;
228 } else {
229 return DEFAULT_LOGLEVEL;
230 }
231}
232
233
235{
236 long level = LONG_MAX;
237
238 if (s == NULL || *s == '\0')
239 return LIRC_BADLEVEL;
240 while (isspace(*s) && *s)
241 s++;
242 if (isdigit(*s)) {
243 level = strtol(s, NULL, 10);
244 if (level > LIRC_MAX_LOGLEVEL || level < LIRC_MIN_LOGLEVEL)
245 return LIRC_BADLEVEL;
246 else
247 return level;
248 } else {
249 return symbol2loglevel(s);
250 }
251}
252
253
254void perrorf(const char* format, ...)
255{
256 char buff[256];
257 va_list ap;
258
259 va_start(ap, format);
260 vsnprintf(buff, sizeof(buff), format, ap);
261 va_end(ap);
262 perror(buff);
263}
264
265
273void logprintf(loglevel_t prio, const char* format_str, ...)
274{
275 int save_errno = errno;
276 va_list ap;
277 char buff[PRIO_LEN + strlen(format_str)];
278
279 if (use_syslog) {
280 snprintf(buff, sizeof(buff),
281 "%s: %s", prio2text(prio), format_str);
282 va_start(ap, format_str);
283 vsyslog(min(7, prio), buff, ap);
284 va_end(ap);
285 } else if (lf) {
286 char* currents;
287 struct timeval tv;
288 struct timezone tz;
289
290 gettimeofday(&tv, &tz);
291 currents = ctime(&tv.tv_sec);
292
293 fprintf(lf, "%15.15s.%06ld %s %s: ",
294 currents + 4, (long) tv.tv_usec, hostname, progname);
295 fprintf(lf, "%s: ", prio2text(prio));
296 va_start(ap, format_str);
297 vfprintf(lf, format_str, ap);
298 va_end(ap);
299 fputc('\n', lf);
300 fflush(lf);
301 }
302 errno = save_errno;
303}
304
310void logperror(loglevel_t prio, const char* fmt, ...)
311{
312 char s[256];
313 va_list ap;
314
315 va_start(ap, fmt);
316 vsnprintf(s, sizeof(s), fmt, ap);
317 va_end(ap);
318 if (use_syslog) {
319 if (*s != '\0')
320 syslog(min(7, prio), "%s: %m\n", s);
321 else
322 syslog(min(7, prio), "%m\n");
323 } else {
324 if (*s != '\0')
325 logprintf(prio, "%s: %s", s, strerror(errno));
326 else
327 logprintf(prio, "%s", strerror(errno));
328 }
329}
330
331
332int lirc_log_get_clientlog(const char* basename, char* buffer, ssize_t size)
333{
334 const char* home;
335 struct passwd* pw;
336 const char* user;
337 int r;
338
339 if (getenv("XDG_CACHE_HOME") != NULL) {
340 strncpy(buffer, getenv("XDG_CACHE_HOME"), size);
341 buffer[size - 1] = '\0';
342 } else if (getenv("SUDO_USER") != NULL && geteuid() == 0) {
343 user = getenv("SUDO_USER");
344 if (user == NULL)
345 user = "root";
346 pw = getpwnam(user);
347 snprintf(buffer, size, "%s/.cache", pw->pw_dir);
348 } else {
349 home = getenv("HOME");
350 home = home != NULL ? home : "/tmp";
351 snprintf(buffer, size, "%s/.cache", home);
352 }
353 if (access(buffer, F_OK) != 0) {
354 r = mkdir(buffer, 0777);
355 if (r != 0) {
356 syslog(LOG_WARNING,
357 "Cannot create log directory %s", buffer);
358 syslog(LOG_WARNING, "Falling back to using /tmp");
359 strcpy(buffer, "/tmp");
360 }
361 }
362 strncat(buffer, "/", size - strlen(buffer) - 1);
363 strncat(buffer, basename, size - strlen(buffer) - 1);
364 strncat(buffer, ".log", size - strlen(buffer) - 1);
365 return 0;
366}
367
368
369void hexdump(char* prefix, unsigned char* buf, int len)
370// Dump a byte array as hex code, adding a prefix.
371{
372 int i;
373 char str[1024];
374 int pos = 0;
375
376 if (prefix != NULL) {
377 strncpy(str, prefix, sizeof(str));
378 pos = strnlen(str, sizeof(str));
379 }
380 if (len > 0) {
381 for (i = 0; i < len; i++) {
382 if (pos + 3 >= sizeof(str))
383 break;
384
385 if (!(i % 8))
386 str[pos++] = ' ';
387
388 sprintf(str + pos, "%02x ", buf[i]);
389
390 pos += 3;
391 }
392 } else {
393 strncpy(str + pos, "NO DATA", sizeof(str));
394 }
395 log_trace("%s", str);
396}
loglevel_t loglevel
The actual loglevel.
Definition lirc_log.c:47
int lirc_log_use_syslog(void)
Check if log is set up to use syslog or not.
Definition lirc_log.c:78
loglevel_t string2loglevel(const char *s)
Convert a string, either a number or 'info', 'trace1', error etc.
Definition lirc_log.c:234
void lirc_log_set_file(const char *s)
Set logfile.
Definition lirc_log.c:84
void hexdump(char *prefix, unsigned char *buf, int len)
Print prefix + a hex dump of len bytes starting at *buf.
Definition lirc_log.c:369
int lirc_log_open(const char *_progname, int _nodaemon, loglevel_t level)
Open the log for upcoming logging.
Definition lirc_log.c:95
int lirc_log_setlevel(loglevel_t level)
Set the level.
Definition lirc_log.c:179
int lirc_log_get_clientlog(const char *basename, char *buffer, ssize_t size)
Retrieve a client path for logging according to freedesktop specs.
Definition lirc_log.c:332
logchannel_t logged_channels
The actual logchannel.
Definition lirc_log.c:49
void perrorf(const char *format,...)
Adds printf-style arguments to perror(3).
Definition lirc_log.c:254
int lirc_log_close(void)
Close the log previosly opened with lirc_log_open().
Definition lirc_log.c:137
loglevel_t lirc_log_defaultlevel(void)
Get the default level, from environment or hardcoded.
Definition lirc_log.c:219
void logperror(loglevel_t prio, const char *fmt,...)
Prints a description of the last error to the log.
Definition lirc_log.c:310
#define log_trace(fmt,...)
Log a trace message.
Definition lirc_log.h:129
loglevel_t
The defined loglevels.
Definition lirc_log.h:36
#define log_info(fmt,...)
Log an info message.
Definition lirc_log.h:114
#define LIRC_MIN_LOGLEVEL
Mix loglevel (for validation).
Definition lirc_log.h:64
#define LIRC_MAX_LOGLEVEL
Max loglevel (for validation).
Definition lirc_log.h:61
logchannel_t
Log channels used to filter messages.
Definition lirc_log.h:53
#define DEFAULT_LOGLEVEL
Default loglevel (last resort).
Definition lirc_log.h:79
#define log_warn(fmt,...)
Log a warning message.
Definition lirc_log.h:109