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 
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 
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 
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 
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 
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 }
#define LIRC_MAX_LOGLEVEL
Definition: lirc_log.h:61
loglevel_t loglevel
Definition: lirc_log.c:47
int lirc_log_open(const char *_progname, int _nodaemon, loglevel_t level)
Definition: lirc_log.c:95
#define log_warn(fmt,...)
Definition: lirc_log.h:109
logchannel_t
Definition: lirc_log.h:53
int lirc_log_close(void)
Definition: lirc_log.c:136
loglevel_t
Definition: lirc_log.h:36
void lirc_log_set_file(const char *s)
Definition: lirc_log.c:84
int lirc_log_use_syslog(void)
Definition: lirc_log.c:78
#define log_trace(fmt,...)
Definition: lirc_log.h:129
logchannel_t logged_channels
Definition: lirc_log.c:49
#define LIRC_MIN_LOGLEVEL
Definition: lirc_log.h:64
#define DEFAULT_LOGLEVEL
Definition: lirc_log.h:79
int lirc_log_setlevel(loglevel_t level)
Definition: lirc_log.c:178
void hexdump(char *prefix, unsigned char *buf, int len)
Definition: lirc_log.c:377
loglevel_t lirc_log_defaultlevel(void)
Definition: lirc_log.c:218
void logperror(loglevel_t prio, const char *fmt,...)
Definition: lirc_log.c:318
int lirc_log_get_clientlog(const char *basename, char *buffer, ssize_t size)
Definition: lirc_log.c:340
loglevel_t string2loglevel(const char *s)
Definition: lirc_log.c:233
#define log_info(fmt,...)
Definition: lirc_log.h:114
void logprintf(loglevel_t prio, const char *format_str,...)
Definition: lirc_log.c:272
void perrorf(const char *format,...)
Definition: lirc_log.c:253