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