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  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 
137 int lirc_log_close(void)
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 
150 int 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 
190 static 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 
254 void 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 
273 void 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 
310 void 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 
332 int 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 
369 void 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 }
#define LIRC_MAX_LOGLEVEL
Max loglevel (for validation).
Definition: lirc_log.h:61
loglevel_t loglevel
The actual loglevel.
Definition: lirc_log.c:47
int lirc_log_open(const char *_progname, int _nodaemon, loglevel_t level)
Open the log for upcoming logging.
Definition: lirc_log.c:95
#define log_warn(fmt,...)
Log a warning message.
Definition: lirc_log.h:109
logchannel_t
Log channels used to filter messages.
Definition: lirc_log.h:53
int lirc_log_close(void)
Close the log previosly opened with lirc_log_open().
Definition: lirc_log.c:137
loglevel_t
The defined loglevels.
Definition: lirc_log.h:36
void lirc_log_set_file(const char *s)
Set logfile.
Definition: lirc_log.c:84
int lirc_log_use_syslog(void)
Check if log is set up to use syslog or not.
Definition: lirc_log.c:78
#define log_trace(fmt,...)
Log a trace message.
Definition: lirc_log.h:129
logchannel_t logged_channels
The actual logchannel.
Definition: lirc_log.c:49
#define LIRC_MIN_LOGLEVEL
Mix loglevel (for validation).
Definition: lirc_log.h:64
#define DEFAULT_LOGLEVEL
Default loglevel (last resort).
Definition: lirc_log.h:79
int lirc_log_setlevel(loglevel_t level)
Set the level.
Definition: lirc_log.c:179
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
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
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
loglevel_t string2loglevel(const char *s)
Convert a string, either a number or 'info', 'trace1', error etc.
Definition: lirc_log.c:234
#define log_info(fmt,...)
Log an info message.
Definition: lirc_log.h:114
void logprintf(loglevel_t prio, const char *format_str,...)
Write a message to the log.
Definition: lirc_log.c:273
void perrorf(const char *format,...)
Adds printf-style arguments to perror(3).
Definition: lirc_log.c:254