#ifdef HAVE_SYSLOG_H
# include <syslog.h>
-/* keep track of whether we've run openlog() */
-static int openlog_run = 0;
#endif
-static int can_update_log_fp = TRUE;
-static FILE *log_fp = NULL;
-
/*
* Logging facility names
*/
{ NULL, 0 }
};
+int log_dates_utc = 0;
+
+
/*
* Log the message to the logfile. Include the severity and
* a time stamp.
int vradlog(int lvl, const char *fmt, va_list ap)
{
struct main_config_t *myconfig = &mainconfig;
- int fd = myconfig->radlog_fd;
- FILE *fp = NULL;
unsigned char *p;
char buffer[8192];
- int len, print_timestamp = 0;
+ int len;
/*
* NOT debugging, and trying to log debug messages.
return 0;
}
+ *buffer = '\0';
+ len = 0;
+
/*
* Don't print timestamps to syslog, it does that for us.
* Don't print timestamps for low levels of debugging.
*/
if ((myconfig->radlog_dest != RADLOG_SYSLOG) &&
(debug_flag != 1) && (debug_flag != 2)) {
- print_timestamp = 1;
- }
-
- if ((fd != -1) &&
- (myconfig->radlog_dest != RADLOG_STDOUT) &&
- (myconfig->radlog_dest != RADLOG_STDERR)) {
- myconfig->radlog_fd = -1;
- fd = -1;
- }
-
- *buffer = '\0';
- len = 0;
- if (fd != -1) {
- /*
- * Use it, rather than anything else.
- */
-
-#ifdef HAVE_SYSLOG_H
- } else if (myconfig->radlog_dest == RADLOG_SYSLOG) {
- /*
- * Open run openlog() on the first log message
- */
- if(!openlog_run) {
- openlog(progname, LOG_PID, myconfig->syslog_facility);
- openlog_run = 1;
- }
-#endif
-
- } else if (myconfig->radlog_dest == RADLOG_FILES) {
- if (!myconfig->log_file) {
- /*
- * Errors go to stderr, in the hope that
- * they will be printed somewhere.
- */
- if (lvl & L_ERR) {
- fd = STDERR_FILENO;
- print_timestamp = 0;
- snprintf(buffer, sizeof(buffer), "%s: ", progname);
- len = strlen(buffer);
- } else {
- /*
- * No log file set. Discard it.
- */
- return 0;
- }
-
- } else if (log_fp) {
- struct stat buf;
-
- if (stat(myconfig->log_file, &buf) < 0) {
- fclose(log_fp);
- log_fp = fr_log_fp = NULL;
- }
- }
-
- if (!log_fp) {
- fp = fopen(myconfig->log_file, "a");
- if (!fp) {
- fprintf(stderr, "%s: Couldn't open %s for logging: %s\n",
- progname, myconfig->log_file, strerror(errno));
-
- fprintf(stderr, " (");
- vfprintf(stderr, fmt, ap); /* the message that caused the log */
- fprintf(stderr, ")\n");
- return -1;
- }
- setlinebuf(fp);
- }
-
- /*
- * We can only set the global variable log_fp IF
- * we have no child threads. If we do have child
- * threads, each thread has to open it's own FP.
- */
- if (can_update_log_fp) fr_log_fp = log_fp = fp;
- }
-
- if (print_timestamp) {
const char *s;
time_t timeval;
timeval = time(NULL);
- CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
+#ifdef HAVE_GMTIME_R
+ if (log_dates_utc) {
+ struct tm utc;
+ gmtime_r(&timeval, &utc);
+ asctime_r(&utc, buffer + len);
+ } else
+#endif
+ CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
}
strcat(buffer, "\n");
+ switch (myconfig->radlog_dest) {
+
#ifdef HAVE_SYSLOG_H
- if (myconfig->radlog_dest == RADLOG_SYSLOG) {
+ case RADLOG_SYSLOG:
switch(lvl & ~L_CONS) {
case L_DBG:
lvl = LOG_DEBUG;
break;
}
syslog(lvl, "%s", buffer);
- } else
+ break;
#endif
- if (log_fp != NULL) {
- fputs(buffer, log_fp);
- } else if (fp != NULL) {
- fputs(buffer, fp);
- fclose(fp);
- } else if (fd >= 0) {
- write(fd, buffer, strlen(buffer));
+
+ case RADLOG_FILES:
+ case RADLOG_STDOUT:
+ case RADLOG_STDERR:
+ write(myconfig->radlog_fd, buffer, strlen(buffer));
+ break;
+
+ default:
+ case RADLOG_NULL: /* should have been caught above */
+ break;
}
return 0;
}
}
-/*
- * If the server is running with multiple threads, signal the log
- * subsystem that we're about to START multiple threads. Once
- * that happens, we can no longer open/close the log_fp in a
- * child thread, as writing to global variables causes a race
- * condition.
- *
- * We also close the fr_log_fp, as it can no longer write to the
- * log file (if any).
- *
- * All of this work is because we want to catch the case of the
- * administrator deleting the log file. If that happens, we want
- * the logs to go to the *new* file, and not the *old* one.
- */
-void force_log_reopen(void)
+extern char *request_log_file;
+#ifdef HAVE_SYS_UN_H
+extern char *debug_log_file;
+#endif
+
+void radlog_request(int lvl, int priority, REQUEST *request, const char *msg, ...)
{
- can_update_log_fp = 0;
- if (log_fp) fclose(log_fp);
- fr_log_fp = log_fp = NULL;
+ size_t len = 0;
+ const char *filename = request_log_file;
+ FILE *fp = NULL;
+ va_list ap;
+ char buffer[1024];
+
+ va_start(ap, msg);
+
+ /*
+ * Debug messages get treated specially.
+ */
+ if (lvl == L_DBG) {
+ /*
+ * There is log function, but the debug level
+ * isn't high enough. OR, we're in debug mode,
+ * and the debug level isn't high enough. Return.
+ */
+ if ((request && request->radlog &&
+ (priority > request->options)) ||
+ ((debug_flag != 0) && (priority > debug_flag))) {
+ va_end(ap);
+ return;
+ }
+
+ /*
+ * Use the debug output file, if specified,
+ * otherwise leave it as "request_log_file".
+ */
+#ifdef HAVE_SYS_UN_H
+ filename = debug_log_file;
+ if (!filename)
+#endif
+ filename = request_log_file;
+
+ /*
+ * Debug messages get mashed to L_INFO for
+ * radius.log.
+ */
+ if (!filename) lvl = L_INFO;
+ }
+
+ if (request && filename) {
+ char *p;
+ radlog_func_t rl = request->radlog;
+
+ request->radlog = NULL;
+
+ /*
+ * This is SLOW! Doing it for every log message
+ * in every request is NOT recommended!
+ */
+
+ radius_xlat(buffer, sizeof(buffer), filename,
+ request, NULL); /* FIXME: escape chars! */
+ request->radlog = rl;
+
+ p = strrchr(buffer, FR_DIR_SEP);
+ if (p) {
+ *p = '\0';
+ if (rad_mkdir(buffer, S_IRWXU) < 0) {
+ radlog(L_ERR, "Failed creating %s: %s",
+ buffer,strerror(errno));
+ va_end(ap);
+ return;
+ }
+ *p = FR_DIR_SEP;
+ }
+
+ fp = fopen(buffer, "a");
+ }
+
+ /*
+ * Print timestamps to the file.
+ */
+ if (fp) {
+ char *s;
+ time_t timeval;
+ timeval = time(NULL);
+
+#ifdef HAVE_GMTIME_R
+ if (log_dates_utc) {
+ struct tm utc;
+ gmtime_r(&timeval, &utc);
+ ASCTIME_R(&utc, buffer + len, sizeof(buffer) - len - 1);
+ } else
+#endif
+ {
+ CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
+ }
+
+ s = strrchr(buffer, '\n');
+ if (s) {
+ s[0] = ' ';
+ s[1] = '\0';
+ }
+
+ len = strlen(buffer);
+
+ if (len < sizeof(buffer)) {
+ len += strlcpy(buffer + len, fr_int2str(levels, (lvl & ~L_CONS), ": "), sizeof(buffer) - len);
+ }
+ }
+
+ if (request && request->module[0]) {
+ snprintf(buffer + len, sizeof(buffer) - len, "[%s] ", request->module);
+ len = strlen(buffer);
+ }
+ vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
+
+ if (!fp) {
+ radlog(lvl, "%s", buffer);
+ } else {
+ if (strlcat(buffer, "\n", sizeof(buffer)) >= sizeof(buffer)) {
+ buffer[sizeof(buffer) - 1] = '\n';
+ }
+ fputs(buffer, fp);
+ fclose(fp);
+ }
+
+ va_end(ap);
}