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