static void show_help() { fprintf(stderr, "Usage: daliserver [-d <loglevel>] [-l <address>] [-p <port>] [-n]\n"); fprintf(stderr, "\n"); if (log_debug_enabled()) { fprintf(stderr, "-d <loglevel> Set the logging level (fatal, error, warn, info, debug, default=info)\n"); } else { fprintf(stderr, "-d <loglevel> Set the logging level (fatal, error, warn, info, default=info)\n"); } fprintf(stderr, "-l <address> Set the IP address to listen on (default=127.0.0.1)\n"); fprintf(stderr, "-p <port> Set the port to listen on (default=55825)\n"); fprintf(stderr, "-n Enable dry-run mode for debugging (USB port won't be opened)\n"); #ifdef HAVE_VSYSLOG fprintf(stderr, "-s Enable syslog (errors only)\n"); #endif if (log_debug_enabled()) { fprintf(stderr, "-f <logfile> Write debug messages to logfile\n"); } else { fprintf(stderr, "-f <logfile> Write info messages to logfile\n"); } fprintf(stderr, "-b Fork into background (implies -r)\n"); fprintf(stderr, "-r <file> Save PID to file (default=/var/run/daliserver.pid)\n"); fprintf(stderr, "-u <bus:dev> Only drive the USB device at bus:dev\n"); fprintf(stderr, "\n"); }
/** Print a list of VALUE_PAIRs. * * @param[in] lvl Debug lvl (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. * @param[in] prefix (optional). */ void log_request_pair_list(fr_log_lvl_t lvl, REQUEST *request, VALUE_PAIR *vp, char const *prefix) { fr_cursor_t cursor; if (!vp || !request || !request->log.dst) return; if (!log_debug_enabled(L_DBG, lvl, request)) return; RINDENT(); for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { VP_VERIFY(vp); RDEBUGX(lvl, "%s%pP", prefix ? prefix : "&", vp); } REXDENT(); }
/** Send a log message to its destination, possibly including fields from the request * * @param[in] type of log message, #L_ERR, #L_WARN, #L_INFO, #L_DBG. * @param[in] lvl Minimum required server or request level to output this message. * @param[in] request The current request. * @param[in] msg with printf style substitution tokens. * @param[in] ap Substitution arguments. * @param[in] uctx The #fr_log_t specifying the destination for log messages. */ void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap, void *uctx) { char const *filename; FILE *fp = NULL; char *p; char const *extra = ""; uint8_t unlang_indent, module_indent; va_list aq; char *msg_prefix = NULL; char *msg_module = NULL; char *msg_exp = NULL; fr_log_t *log_dst = uctx; /* * No output means no output. */ if (!log_dst) return; filename = log_dst->file; /* * Debug messages get treated specially. */ if ((type & L_DBG) != 0) { if (!log_debug_enabled(type, lvl, request)) return; /* * If we're debugging to a file, then use that. * * @todo: have fr_vlog() take a fr_log_t*, so * that we can cache the opened descriptor, and * we don't need to re-open it on every log * message. */ switch (log_dst->dst) { case L_DST_FILES: fp = fopen(log_dst->file, "a"); if (!fp) goto finish; break; #if defined(HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN) case L_DST_EXTRA: { # ifdef HAVE_FOPENCOOKIE cookie_io_functions_t io; /* * These must be set separately as they have different prototypes. */ io.read = NULL; io.seek = NULL; io.close = NULL; io.write = log_dst->cookie_write; fp = fopencookie(log_dst->cookie, "w", io); # else fp = funopen(log_dst->cookie, NULL, log_dst->cookie_write, NULL, NULL); # endif if (!fp) goto finish; } break; #endif default: break; } goto print_msg; } if (filename) { char *exp; log_dst_t *dst; dst = request->log.dst; /* * Prevent infinitely recursive calls if * xlat_aeval attempts to write to the request log. */ request->log.dst = NULL; /* * This is SLOW! Doing it for every log message * in every request is NOT recommended! */ if (xlat_aeval(request, &exp, request, filename, rad_filename_escape, NULL) < 0) return; /* * Restore the original logging function */ request->log.dst = dst; /* * Ensure the directory structure exists, for * where we're going to write the log file. */ p = strrchr(exp, FR_DIR_SEP); if (p) { *p = '\0'; if (rad_mkdir(exp, S_IRWXU, -1, -1) < 0) { ERROR("Failed creating %s: %s", exp, fr_syserror(errno)); talloc_free(exp); return; } *p = FR_DIR_SEP; } fp = fopen(exp, "a"); talloc_free(exp); } print_msg: /* * Request prefix i.e. * * (0) <msg> */ if ((request->seq_start == 0) || (request->number == request->seq_start)) { msg_prefix = talloc_typed_asprintf(request, "(%s) ", request->name); } else { msg_prefix = talloc_typed_asprintf(request, "(%s,%" PRIu64 ") ", request->name, request->seq_start); } /* * Make sure the indent isn't set to something crazy */ unlang_indent = request->log.unlang_indent > sizeof(spaces) - 1 ? sizeof(spaces) - 1 : request->log.unlang_indent; module_indent = request->log.module_indent > sizeof(spaces) - 1 ? sizeof(spaces) - 1 : request->log.module_indent; /* * Module name and indentation i.e. * * test - <msg> */ if (request->module) { msg_module = talloc_typed_asprintf(request, "%s - %.*s", request->module, module_indent, spaces); } /* * If we don't copy the original ap we get a segfault from vasprintf. This is apparently * due to ap sometimes being implemented with a stack offset which is invalidated if * ap is passed into another function. See here: * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html * * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when * running unit tests which generate errors under CI. */ va_copy(aq, ap); msg_exp = fr_vasprintf(request, msg, aq); va_end(aq); /* * Logging to a file descriptor */ if (fp) { char time_buff[64]; /* The current timestamp */ time_t timeval; timeval = time(NULL); #ifdef HAVE_GMTIME_R if (log_dates_utc) { struct tm utc; gmtime_r(&timeval, &utc); ASCTIME_R(&utc, time_buff, sizeof(time_buff)); } else #endif { CTIME_R(&timeval, time_buff, sizeof(time_buff)); } /* * Strip trailing new lines */ p = strrchr(time_buff, '\n'); if (p) p[0] = '\0'; fprintf(fp, "%s" "%s : " "%s" "%.*s" "%s" "%s" "\n", msg_prefix, time_buff, fr_int2str(fr_log_levels, type, ""), unlang_indent, spaces, msg_module ? msg_module : "", msg_exp); fclose(fp); goto finish; } /* * Logging everywhere else */ if (!DEBUG_ENABLED3) switch (type) { case L_DBG_WARN: extra = "WARNING: "; type = L_DBG_WARN_REQ; break; case L_DBG_ERR: extra = "ERROR: "; type = L_DBG_ERR_REQ; break; default: break; }; log_always(log_dst, type, "%s" "%.*s" "%s" "%s" "%s", msg_prefix, unlang_indent, spaces, msg_module ? msg_module : "", extra, msg_exp); finish: talloc_free(msg_exp); talloc_free(msg_module); talloc_free(msg_prefix); }