예제 #1
0
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");
}
예제 #2
0
/** 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();
}
예제 #3
0
/** 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);
}