LIRC libraries LinuxInfraredRemoteControl

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Examples

- File List
- Globals

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
69 int lirc_log_use_syslog(void)
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
162 int lirc_log_setlevel(loglevel_t level)
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
202 loglevel_t lirc_log_defaultlevel(void)
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
217 loglevel_t string2loglevel(const char* s)
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 }
LIRC_MAX_LOGLEVEL
#define LIRC_MAX_LOGLEVEL
Definition: lirc_log.h:50
loglevel
loglevel_t loglevel
Definition: lirc_log.c:40
lirc_log_open
int lirc_log_open(const char *_progname, int _nodaemon, loglevel_t level)
Definition: lirc_log.c:86
lirc_log_close
int lirc_log_close(void)
Definition: lirc_log.c:120
loglevel_t
loglevel_t
Definition: lirc_log.h:36
lirc_log_set_file
void lirc_log_set_file(const char *s)
Definition: lirc_log.c:75
lirc_log_use_syslog
int lirc_log_use_syslog(void)
Definition: lirc_log.c:69
LIRC_MIN_LOGLEVEL
#define LIRC_MIN_LOGLEVEL
Definition: lirc_log.h:53
DEFAULT_LOGLEVEL
#define DEFAULT_LOGLEVEL
Definition: lirc_log.h:62
lirc_log_setlevel
int lirc_log_setlevel(loglevel_t level)
Definition: lirc_log.c:162
LOGPRINTF
#define LOGPRINTF(level, fmt, args...)
Definition: lirc_log.h:75
hexdump
void hexdump(char *prefix, unsigned char *buf, int len)
Definition: lirc_log.c:348
lirc_log_defaultlevel
loglevel_t lirc_log_defaultlevel(void)
Definition: lirc_log.c:202
logperror
void logperror(loglevel_t prio, const char *fmt,...)
Definition: lirc_log.c:289
lirc_log_get_clientlog
int lirc_log_get_clientlog(const char *basename, char *buffer, ssize_t size)
Definition: lirc_log.c:311
string2loglevel
loglevel_t string2loglevel(const char *s)
Definition: lirc_log.c:217
logprintf
void logprintf(loglevel_t prio, const char *format_str,...)
Definition: lirc_log.c:243