xref: /netbsd-src/external/bsd/ntp/dist/libntp/msyslog.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: msyslog.c,v 1.8 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * msyslog - either send a message to the terminal or print it on
5abb0f93cSkardel  *	     the standard output.
6abb0f93cSkardel  *
7abb0f93cSkardel  * Converted to use varargs, much better ... jks
8abb0f93cSkardel  */
9abb0f93cSkardel 
10abb0f93cSkardel #ifdef HAVE_CONFIG_H
11abb0f93cSkardel # include <config.h>
12abb0f93cSkardel #endif
13abb0f93cSkardel 
14abb0f93cSkardel #include <sys/types.h>
15abb0f93cSkardel #ifdef HAVE_UNISTD_H
16abb0f93cSkardel # include <unistd.h>
17abb0f93cSkardel #endif
18abb0f93cSkardel #include <stdio.h>
19abb0f93cSkardel 
20abb0f93cSkardel #include "ntp_string.h"
218585484eSchristos #include "ntp.h"
228585484eSchristos #include "ntp_debug.h"
23abb0f93cSkardel #include "ntp_syslog.h"
24abb0f93cSkardel 
25abb0f93cSkardel #ifdef SYS_WINNT
26abb0f93cSkardel # include <stdarg.h>
27abb0f93cSkardel # include "..\ports\winnt\libntp\messages.h"
28abb0f93cSkardel #endif
29abb0f93cSkardel 
30f003fb54Skardel 
318585484eSchristos int	syslogit = TRUE;
32f003fb54Skardel int	msyslog_term = FALSE;	/* duplicate to stdout/err */
338585484eSchristos int	msyslog_term_pid = TRUE;
348585484eSchristos int	msyslog_include_timestamp = TRUE;
35f003fb54Skardel FILE *	syslog_file;
368585484eSchristos char *	syslog_fname;
378585484eSchristos char *	syslog_abs_fname;
38abb0f93cSkardel 
398585484eSchristos /* libntp default ntp_syslogmask is all bits lit */
408585484eSchristos #define INIT_NTP_SYSLOGMASK	~(u_int32)0
418585484eSchristos u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK;
42abb0f93cSkardel 
43af12ab5eSchristos extern char const * progname;
44abb0f93cSkardel 
45abb0f93cSkardel /* Declare the local functions */
46f003fb54Skardel void	addto_syslog	(int, const char *);
4722eebdc3Schristos #ifdef VSNPRINTF_PERCENT_M
4822eebdc3Schristos #define format_errmsg(buf, len, fmt, error) (fmt)
4922eebdc3Schristos #else
5022eebdc3Schristos static const char *format_errmsg(char *, size_t, const char *, int)
5122eebdc3Schristos     NTP_FORMAT_ARG(3);
52abb0f93cSkardel 
538585484eSchristos /* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */
5422eebdc3Schristos static const char *
558585484eSchristos format_errmsg(
568585484eSchristos 	char *		nfmt,
578585484eSchristos 	size_t		lennfmt,
588585484eSchristos 	const char *	fmt,
598585484eSchristos 	int		errval
608585484eSchristos 	)
618585484eSchristos {
628585484eSchristos 	char errmsg[256];
638585484eSchristos 	char c;
648585484eSchristos 	char *n;
658585484eSchristos 	const char *f;
668585484eSchristos 	size_t len;
678585484eSchristos 
688585484eSchristos 	n = nfmt;
698585484eSchristos 	f = fmt;
708585484eSchristos 	while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) {
718585484eSchristos 		if (c != '%') {
728585484eSchristos 			*n++ = c;
738585484eSchristos 			continue;
748585484eSchristos 		}
758585484eSchristos 		if ((c = *f++) != 'm') {
768585484eSchristos 			*n++ = '%';
778585484eSchristos 			if ('\0' == c)
788585484eSchristos 				break;
798585484eSchristos 			*n++ = c;
808585484eSchristos 			continue;
818585484eSchristos 		}
828585484eSchristos 		errno_to_str(errval, errmsg, sizeof(errmsg));
838585484eSchristos 		len = strlen(errmsg);
848585484eSchristos 
858585484eSchristos 		/* Make sure we have enough space for the error message */
868585484eSchristos 		if ((n + len) < (nfmt + lennfmt - 1)) {
878585484eSchristos 			memcpy(n, errmsg, len);
888585484eSchristos 			n += len;
898585484eSchristos 		}
908585484eSchristos 	}
918585484eSchristos 	*n = '\0';
9222eebdc3Schristos 	return nfmt;
938585484eSchristos }
948585484eSchristos #endif	/* VSNPRINTF_PERCENT_M */
958585484eSchristos 
96abb0f93cSkardel 
97abb0f93cSkardel /*
988585484eSchristos  * errno_to_str() - a thread-safe strerror() replacement.
998585484eSchristos  *		    Hides the varied signatures of strerror_r().
1008585484eSchristos  *		    For Windows, we have:
101*eabc0478Schristos  *			#define errno_to_str isc__strerror
1028585484eSchristos  */
1038585484eSchristos #ifndef errno_to_str
1048585484eSchristos void
1058585484eSchristos errno_to_str(
1068585484eSchristos 	int	err,
1078585484eSchristos 	char *	buf,
1088585484eSchristos 	size_t	bufsiz
1098585484eSchristos 	)
1108585484eSchristos {
1118585484eSchristos # if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R
1128585484eSchristos 	char *	pstatic;
1138585484eSchristos 
1148585484eSchristos 	buf[0] = '\0';
1158585484eSchristos #  ifdef STRERROR_R_CHAR_P
1168585484eSchristos 	pstatic = strerror_r(err, buf, bufsiz);
1178585484eSchristos #  else
1188585484eSchristos 	pstatic = strerror(err);
1198585484eSchristos #  endif
1208585484eSchristos 	if (NULL == pstatic && '\0' == buf[0])
1218585484eSchristos 		snprintf(buf, bufsiz, "%s(%d): errno %d",
1228585484eSchristos #  ifdef STRERROR_R_CHAR_P
1238585484eSchristos 			 "strerror_r",
1248585484eSchristos #  else
1258585484eSchristos 			 "strerror",
1268585484eSchristos #  endif
1278585484eSchristos 			 err, errno);
1288585484eSchristos 	/* protect against believing an int return is a pointer */
1298585484eSchristos 	else if (pstatic != buf && pstatic > (char *)bufsiz)
1308585484eSchristos 		strlcpy(buf, pstatic, bufsiz);
1318585484eSchristos # else
1328585484eSchristos 	int	rc;
1338585484eSchristos 
1348585484eSchristos 	rc = strerror_r(err, buf, bufsiz);
1358585484eSchristos 	if (rc < 0)
1368585484eSchristos 		snprintf(buf, bufsiz, "strerror_r(%d): errno %d",
1378585484eSchristos 			 err, errno);
1388585484eSchristos # endif
1398585484eSchristos }
1408585484eSchristos #endif	/* errno_to_str */
1418585484eSchristos 
1428585484eSchristos 
1438585484eSchristos /*
1448585484eSchristos  * addto_syslog()
145f003fb54Skardel  * This routine adds the contents of a buffer to the syslog or an
146f003fb54Skardel  * application-specific logfile.
147abb0f93cSkardel  */
148abb0f93cSkardel void
149f003fb54Skardel addto_syslog(
150f003fb54Skardel 	int		level,
151f003fb54Skardel 	const char *	msg
152f003fb54Skardel 	)
153abb0f93cSkardel {
154af12ab5eSchristos 	static char const *	prevcall_progname;
155af12ab5eSchristos 	static char const *	prog;
156f003fb54Skardel 	const char	nl[] = "\n";
157f003fb54Skardel 	const char	empty[] = "";
158f003fb54Skardel 	FILE *		term_file;
159f003fb54Skardel 	int		log_to_term;
160f003fb54Skardel 	int		log_to_file;
1618585484eSchristos 	int		pid;
162f003fb54Skardel 	const char *	nl_or_empty;
163f003fb54Skardel 	const char *	human_time;
164abb0f93cSkardel 
165f003fb54Skardel 	/* setup program basename static var prog if needed */
166f003fb54Skardel 	if (progname != prevcall_progname) {
167f003fb54Skardel 		prevcall_progname = progname;
168f003fb54Skardel 		prog = strrchr(progname, DIR_SEP);
169f003fb54Skardel 		if (prog != NULL)
170f003fb54Skardel 			prog++;
171f003fb54Skardel 		else
172f003fb54Skardel 			prog = progname;
173f003fb54Skardel 	}
174f003fb54Skardel 
175f003fb54Skardel 	log_to_term = msyslog_term;
176f003fb54Skardel 	log_to_file = FALSE;
177abb0f93cSkardel #if !defined(VMS) && !defined(SYS_VXWORKS)
178abb0f93cSkardel 	if (syslogit)
179f003fb54Skardel 		syslog(level, "%s", msg);
180abb0f93cSkardel 	else
181abb0f93cSkardel #endif
182f003fb54Skardel 		if (syslog_file != NULL)
183f003fb54Skardel 			log_to_file = TRUE;
184f003fb54Skardel 		else
185f003fb54Skardel 			log_to_term = TRUE;
186f003fb54Skardel #if DEBUG
187f003fb54Skardel 	if (debug > 0)
188f003fb54Skardel 		log_to_term = TRUE;
189f003fb54Skardel #endif
190f003fb54Skardel 	if (!(log_to_file || log_to_term))
191f003fb54Skardel 		return;
192f003fb54Skardel 
193f003fb54Skardel 	/* syslog() adds the timestamp, name, and pid */
1948585484eSchristos 	if (msyslog_include_timestamp)
195f003fb54Skardel 		human_time = humanlogtime();
1968585484eSchristos 	else	/* suppress gcc pot. uninit. warning */
1978585484eSchristos 		human_time = NULL;
1988585484eSchristos 	if (msyslog_term_pid || log_to_file)
1998585484eSchristos 		pid = getpid();
2008585484eSchristos 	else	/* suppress gcc pot. uninit. warning */
2018585484eSchristos 		pid = -1;
202f003fb54Skardel 
203f003fb54Skardel 	/* syslog() adds trailing \n if not present */
204f003fb54Skardel 	if ('\n' != msg[strlen(msg) - 1])
205f003fb54Skardel 		nl_or_empty = nl;
206f003fb54Skardel 	else
207f003fb54Skardel 		nl_or_empty = empty;
208f003fb54Skardel 
209f003fb54Skardel 	if (log_to_term) {
210f003fb54Skardel 		term_file = (level <= LOG_ERR)
211f003fb54Skardel 				? stderr
212f003fb54Skardel 				: stdout;
2138585484eSchristos 		if (msyslog_include_timestamp)
2148585484eSchristos 			fprintf(term_file, "%s ", human_time);
2158585484eSchristos 		if (msyslog_term_pid)
2168585484eSchristos 			fprintf(term_file, "%s[%d]: ", prog, pid);
2178585484eSchristos 		fprintf(term_file, "%s%s", msg, nl_or_empty);
218f003fb54Skardel 		fflush(term_file);
219abb0f93cSkardel 	}
220f003fb54Skardel 
221f003fb54Skardel 	if (log_to_file) {
2228585484eSchristos 		if (msyslog_include_timestamp)
2238585484eSchristos 			fprintf(syslog_file, "%s ", human_time);
2248585484eSchristos 		fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg,
2258585484eSchristos 			nl_or_empty);
226f003fb54Skardel 		fflush(syslog_file);
227f003fb54Skardel 	}
228f003fb54Skardel }
229f003fb54Skardel 
230f003fb54Skardel 
231f003fb54Skardel int
232f003fb54Skardel mvsnprintf(
233f003fb54Skardel 	char *		buf,
234f003fb54Skardel 	size_t		bufsiz,
235f003fb54Skardel 	const char *	fmt,
236f003fb54Skardel 	va_list		ap
237f003fb54Skardel 	)
238abb0f93cSkardel {
239f003fb54Skardel #ifndef VSNPRINTF_PERCENT_M
24022eebdc3Schristos 	char		fmtbuf[256];
241abb0f93cSkardel #endif
242abb0f93cSkardel 	int		errval;
243abb0f93cSkardel 
244abb0f93cSkardel 	/*
245abb0f93cSkardel 	 * Save the error value as soon as possible
246abb0f93cSkardel 	 */
247abb0f93cSkardel #ifdef SYS_WINNT
248abb0f93cSkardel 	errval = GetLastError();
249abb0f93cSkardel 	if (NO_ERROR == errval)
250abb0f93cSkardel #endif /* SYS_WINNT */
251f003fb54Skardel 		errval = errno;
252abb0f93cSkardel 
25322eebdc3Schristos #ifdef VSNPRINTF_PERCENT_M
254f003fb54Skardel 	errno = errval;
255f003fb54Skardel #endif
25622eebdc3Schristos 	return vsnprintf(buf, bufsiz,
25722eebdc3Schristos 	    format_errmsg(fmtbuf, sizeof(fmtbuf), fmt, errval), ap);
258f003fb54Skardel }
259abb0f93cSkardel 
260f003fb54Skardel 
261f003fb54Skardel int
262f003fb54Skardel mvfprintf(
263f003fb54Skardel 	FILE *		fp,
264f003fb54Skardel 	const char *	fmt,
265f003fb54Skardel 	va_list		ap
266f003fb54Skardel 	)
267f003fb54Skardel {
268f003fb54Skardel #ifndef VSNPRINTF_PERCENT_M
26922eebdc3Schristos 	char		fmtbuf[256];
270f003fb54Skardel #endif
271f003fb54Skardel 	int		errval;
272f003fb54Skardel 
273f003fb54Skardel 	/*
274f003fb54Skardel 	 * Save the error value as soon as possible
275f003fb54Skardel 	 */
276f003fb54Skardel #ifdef SYS_WINNT
277f003fb54Skardel 	errval = GetLastError();
278f003fb54Skardel 	if (NO_ERROR == errval)
279f003fb54Skardel #endif /* SYS_WINNT */
280f003fb54Skardel 		errval = errno;
281f003fb54Skardel 
28222eebdc3Schristos #ifdef VSNPRINTF_PERCENT_M
283f003fb54Skardel 	errno = errval;
284f003fb54Skardel #endif
28522eebdc3Schristos 	return vfprintf(fp,
28622eebdc3Schristos 	    format_errmsg(fmtbuf, sizeof(fmtbuf), fmt, errval), ap);
287f003fb54Skardel }
288f003fb54Skardel 
289f003fb54Skardel 
290f003fb54Skardel int
291f003fb54Skardel mfprintf(
292f003fb54Skardel 	FILE *		fp,
293f003fb54Skardel 	const char *	fmt,
294f003fb54Skardel 	...
295f003fb54Skardel 	)
296f003fb54Skardel {
297f003fb54Skardel 	va_list		ap;
298f003fb54Skardel 	int		rc;
299f003fb54Skardel 
300f003fb54Skardel 	va_start(ap, fmt);
301f003fb54Skardel 	rc = mvfprintf(fp, fmt, ap);
302abb0f93cSkardel 	va_end(ap);
303f003fb54Skardel 
304f003fb54Skardel 	return rc;
305f003fb54Skardel }
306f003fb54Skardel 
307f003fb54Skardel 
308f003fb54Skardel int
309f003fb54Skardel mprintf(
310f003fb54Skardel 	const char *	fmt,
311f003fb54Skardel 	...
312f003fb54Skardel 	)
313f003fb54Skardel {
314f003fb54Skardel 	va_list		ap;
315f003fb54Skardel 	int		rc;
316f003fb54Skardel 
317f003fb54Skardel 	va_start(ap, fmt);
318f003fb54Skardel 	rc = mvfprintf(stdout, fmt, ap);
319f003fb54Skardel 	va_end(ap);
320f003fb54Skardel 
321f003fb54Skardel 	return rc;
322f003fb54Skardel }
323f003fb54Skardel 
324f003fb54Skardel 
325f003fb54Skardel int
326f003fb54Skardel msnprintf(
327f003fb54Skardel 	char *		buf,
328f003fb54Skardel 	size_t		bufsiz,
329f003fb54Skardel 	const char *	fmt,
330f003fb54Skardel 	...
331f003fb54Skardel 	)
332f003fb54Skardel {
333f003fb54Skardel 	va_list	ap;
3348b8da087Schristos 	int	rc;
335f003fb54Skardel 
336f003fb54Skardel 	va_start(ap, fmt);
337f003fb54Skardel 	rc = mvsnprintf(buf, bufsiz, fmt, ap);
338f003fb54Skardel 	va_end(ap);
339f003fb54Skardel 
340f003fb54Skardel 	return rc;
341f003fb54Skardel }
342f003fb54Skardel 
343f003fb54Skardel 
344f003fb54Skardel void
345f003fb54Skardel msyslog(
346f003fb54Skardel 	int		level,
347f003fb54Skardel 	const char *	fmt,
348f003fb54Skardel 	...
349f003fb54Skardel 	)
350f003fb54Skardel {
351f003fb54Skardel 	va_list	ap;
352f003fb54Skardel 
353f003fb54Skardel 	va_start(ap, fmt);
354*eabc0478Schristos 	mvsyslog(level, fmt, ap);
355f003fb54Skardel 	va_end(ap);
356abb0f93cSkardel }
3578585484eSchristos 
358*eabc0478Schristos 
359af12ab5eSchristos void
360af12ab5eSchristos mvsyslog(
361af12ab5eSchristos 	int		level,
362af12ab5eSchristos 	const char *	fmt,
363af12ab5eSchristos 	va_list		ap
364af12ab5eSchristos 	)
365af12ab5eSchristos {
366af12ab5eSchristos 	char	buf[1024];
367*eabc0478Schristos 
368af12ab5eSchristos 	mvsnprintf(buf, sizeof(buf), fmt, ap);
369af12ab5eSchristos 	addto_syslog(level, buf);
370af12ab5eSchristos }
371af12ab5eSchristos 
3728585484eSchristos 
3738585484eSchristos /*
3748585484eSchristos  * Initialize the logging
3758585484eSchristos  *
3768585484eSchristos  * Called once per process, including forked children.
3778585484eSchristos  */
3788585484eSchristos void
3798585484eSchristos init_logging(
3808585484eSchristos 	const char *	name,
3818585484eSchristos 	u_int32		def_syslogmask,
3828585484eSchristos 	int		is_daemon
3838585484eSchristos 	)
3848585484eSchristos {
3858585484eSchristos 	static int	was_daemon;
386af12ab5eSchristos 	char *		cp;
3878585484eSchristos 	const char *	pname;
3888585484eSchristos 
3898585484eSchristos 	/*
3908585484eSchristos 	 * ntpd defaults to only logging sync-category events, when
3918585484eSchristos 	 * NLOG() is used to conditionalize.  Other libntp clients
3928585484eSchristos 	 * leave it alone so that all NLOG() conditionals will fire.
3938585484eSchristos 	 * This presumes all bits lit in ntp_syslogmask can't be
3948585484eSchristos 	 * configured via logconfig and all lit is thereby a sentinel
3958585484eSchristos 	 * that ntp_syslogmask is still at its default from libntp,
3968585484eSchristos 	 * keeping in mind this function is called in forked children
3978585484eSchristos 	 * where it has already been called in the parent earlier.
3988585484eSchristos 	 * Forked children pass 0 for def_syslogmask.
3998585484eSchristos 	 */
4008585484eSchristos 	if (INIT_NTP_SYSLOGMASK == ntp_syslogmask &&
4018585484eSchristos 	    0 != def_syslogmask)
4028585484eSchristos 		ntp_syslogmask = def_syslogmask; /* set more via logconfig */
4038585484eSchristos 
4048585484eSchristos 	/*
4058585484eSchristos 	 * Logging.  This may actually work on the gizmo board.  Find a name
4068585484eSchristos 	 * to log with by using the basename
4078585484eSchristos 	 */
4088585484eSchristos 	cp = strrchr(name, DIR_SEP);
4098585484eSchristos 	if (NULL == cp)
4108585484eSchristos 		pname = name;
4118585484eSchristos 	else
4128585484eSchristos 		pname = 1 + cp;	/* skip DIR_SEP */
4138585484eSchristos 	progname = estrdup(pname);
4148585484eSchristos #ifdef SYS_WINNT			/* strip ".exe" */
4158585484eSchristos 	cp = strrchr(progname, '.');
4168585484eSchristos 	if (NULL != cp && !strcasecmp(cp, ".exe"))
417af12ab5eSchristos 		*cp = '\0';
4188585484eSchristos #endif
4198585484eSchristos 
4208585484eSchristos #if !defined(VMS)
4218585484eSchristos 
4228585484eSchristos 	if (is_daemon)
4238585484eSchristos 		was_daemon = TRUE;
4248585484eSchristos # ifndef LOG_DAEMON
4258585484eSchristos 	openlog(progname, LOG_PID);
4268585484eSchristos # else /* LOG_DAEMON */
4278585484eSchristos 
4288585484eSchristos #  ifndef LOG_NTP
4298585484eSchristos #	define	LOG_NTP LOG_DAEMON
4308585484eSchristos #  endif
4318585484eSchristos 	openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon)
4328585484eSchristos 						    ? LOG_NTP
4338585484eSchristos 						    : 0);
4348585484eSchristos #  ifdef DEBUG
4358585484eSchristos 	if (debug)
4368585484eSchristos 		setlogmask(LOG_UPTO(LOG_DEBUG));
4378585484eSchristos 	else
4388585484eSchristos #  endif /* DEBUG */
4398585484eSchristos 		setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
4408585484eSchristos # endif /* LOG_DAEMON */
4418585484eSchristos #endif	/* !VMS */
4428585484eSchristos }
4438585484eSchristos 
4448585484eSchristos 
4458585484eSchristos /*
4468585484eSchristos  * change_logfile()
4478585484eSchristos  *
4488585484eSchristos  * Used to change from syslog to a logfile, or from one logfile to
4498585484eSchristos  * another, and to reopen logfiles after forking.  On systems where
4508585484eSchristos  * ntpd forks, deals with converting relative logfile paths to
4518585484eSchristos  * absolute (root-based) because we reopen logfiles after the current
4528585484eSchristos  * directory has changed.
4538585484eSchristos  */
4548585484eSchristos int
4558585484eSchristos change_logfile(
4568585484eSchristos 	const char *	fname,
4578585484eSchristos 	int		leave_crumbs
4588585484eSchristos 	)
4598585484eSchristos {
4608585484eSchristos 	FILE *		new_file;
4618585484eSchristos 	const char *	log_fname;
4628585484eSchristos 	char *		abs_fname;
4638585484eSchristos #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
4648585484eSchristos 	char		curdir[512];
4658585484eSchristos 	size_t		cd_octets;
4668585484eSchristos 	size_t		octets;
4678585484eSchristos #endif	/* POSIX */
4688585484eSchristos 
469af12ab5eSchristos 	REQUIRE(fname != NULL);
4708585484eSchristos 	log_fname = fname;
4718585484eSchristos 
4728585484eSchristos 	/*
4738585484eSchristos 	 * In a forked child of a parent which is logging to a file
4748585484eSchristos 	 * instead of syslog, syslog_file will be NULL and both
4758585484eSchristos 	 * syslog_fname and syslog_abs_fname will be non-NULL.
4768585484eSchristos 	 * If we are given the same filename previously opened
4778585484eSchristos 	 * and it's still open, there's nothing to do here.
4788585484eSchristos 	 */
4798585484eSchristos 	if (syslog_file != NULL && syslog_fname != NULL &&
4808585484eSchristos 	    0 == strcmp(syslog_fname, log_fname))
4818585484eSchristos 		return 0;
4828585484eSchristos 
4838585484eSchristos 	if (0 == strcmp(log_fname, "stderr")) {
4848585484eSchristos 		new_file = stderr;
4858585484eSchristos 		abs_fname = estrdup(log_fname);
4868585484eSchristos 	} else if (0 == strcmp(log_fname, "stdout")) {
4878585484eSchristos 		new_file = stdout;
4888585484eSchristos 		abs_fname = estrdup(log_fname);
4898585484eSchristos 	} else {
4908585484eSchristos 		if (syslog_fname != NULL &&
4918585484eSchristos 		    0 == strcmp(log_fname, syslog_fname))
4928585484eSchristos 			log_fname = syslog_abs_fname;
4938585484eSchristos #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
4948585484eSchristos 		if (log_fname != syslog_abs_fname &&
4958585484eSchristos 		    DIR_SEP != log_fname[0] &&
4968585484eSchristos 		    0 != strcmp(log_fname, "stderr") &&
4978585484eSchristos 		    0 != strcmp(log_fname, "stdout") &&
4988585484eSchristos 		    NULL != getcwd(curdir, sizeof(curdir))) {
4998585484eSchristos 			cd_octets = strlen(curdir);
5008585484eSchristos 			/* trim any trailing '/' */
5018585484eSchristos 			if (cd_octets > 1 &&
5028585484eSchristos 			    DIR_SEP == curdir[cd_octets - 1])
5038585484eSchristos 				cd_octets--;
5048585484eSchristos 			octets = cd_octets;
5058585484eSchristos 			octets += 1;	/* separator '/' */
5068585484eSchristos 			octets += strlen(log_fname);
5078585484eSchristos 			octets += 1;	/* NUL terminator */
5088585484eSchristos 			abs_fname = emalloc(octets);
5098585484eSchristos 			snprintf(abs_fname, octets, "%.*s%c%s",
5108585484eSchristos 				 (int)cd_octets, curdir, DIR_SEP,
5118585484eSchristos 				 log_fname);
5128585484eSchristos 		} else
5138585484eSchristos #endif
5148585484eSchristos 			abs_fname = estrdup(log_fname);
5158585484eSchristos 		TRACE(1, ("attempting to open log %s\n", abs_fname));
5168585484eSchristos 		new_file = fopen(abs_fname, "a");
5178585484eSchristos 	}
5188585484eSchristos 
5198585484eSchristos 	if (NULL == new_file) {
5208585484eSchristos 		free(abs_fname);
5218585484eSchristos 		return -1;
5228585484eSchristos 	}
5238585484eSchristos 
5248585484eSchristos 	/* leave a pointer in the old log */
5258585484eSchristos 	if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
5268585484eSchristos 		msyslog(LOG_NOTICE, "switching logging to file %s",
5278585484eSchristos 			abs_fname);
5288585484eSchristos 
5298585484eSchristos 	if (syslog_file != NULL &&
5308585484eSchristos 	    syslog_file != stderr && syslog_file != stdout &&
5318585484eSchristos 	    fileno(syslog_file) != fileno(new_file))
5328585484eSchristos 		fclose(syslog_file);
5338585484eSchristos 	syslog_file = new_file;
5348585484eSchristos 	if (log_fname == syslog_abs_fname) {
5358585484eSchristos 		free(abs_fname);
5368585484eSchristos 	} else {
5378585484eSchristos 		if (syslog_abs_fname != NULL &&
5388585484eSchristos 		    syslog_abs_fname != syslog_fname)
5398585484eSchristos 			free(syslog_abs_fname);
5408585484eSchristos 		if (syslog_fname != NULL)
5418585484eSchristos 			free(syslog_fname);
5428585484eSchristos 		syslog_fname = estrdup(log_fname);
5438585484eSchristos 		syslog_abs_fname = abs_fname;
5448585484eSchristos 	}
5458585484eSchristos 	syslogit = FALSE;
5468585484eSchristos 
5478585484eSchristos 	return 0;
5488585484eSchristos }
5498585484eSchristos 
5508585484eSchristos 
5518585484eSchristos /*
5528585484eSchristos  * setup_logfile()
5538585484eSchristos  *
5548585484eSchristos  * Redirect logging to a file if requested with -l/--logfile or via
5558585484eSchristos  * ntp.conf logfile directive.
5568585484eSchristos  *
5578585484eSchristos  * This routine is invoked three different times in the sequence of a
5588585484eSchristos  * typical daemon ntpd with DNS lookups to do.  First it is invoked in
5598585484eSchristos  * the original ntpd process, then again in the daemon after closing
5608585484eSchristos  * all descriptors.  In both of those cases, ntp.conf has not been
5618585484eSchristos  * processed, so only -l/--logfile will trigger logfile redirection in
5628585484eSchristos  * those invocations.  Finally, if DNS names are resolved, the worker
5638585484eSchristos  * child invokes this routine after its fork and close of all
5648585484eSchristos  * descriptors.  In this case, ntp.conf has been processed and any
5658585484eSchristos  * "logfile" directive needs to be honored in the child as well.
5668585484eSchristos  */
5678585484eSchristos void
5688585484eSchristos setup_logfile(
5698585484eSchristos 	const char *	name
5708585484eSchristos 	)
5718585484eSchristos {
5728585484eSchristos 	if (NULL == syslog_fname && NULL != name) {
5738585484eSchristos 		if (-1 == change_logfile(name, TRUE))
5748585484eSchristos 			msyslog(LOG_ERR, "Cannot open log file %s, %m",
5758585484eSchristos 				name);
5768585484eSchristos 		return ;
5778585484eSchristos 	}
5788585484eSchristos 	if (NULL == syslog_fname)
5798585484eSchristos 		return;
5808585484eSchristos 
5818585484eSchristos 	if (-1 == change_logfile(syslog_fname, FALSE))
5828585484eSchristos 		msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
5838585484eSchristos 			syslog_fname);
5848585484eSchristos }
585cdfa2a7eSchristos 
586*eabc0478Schristos /*
587*eabc0478Schristos  * Helper for unit tests, where stdout + stderr are piped to the same
588*eabc0478Schristos  * stream.  This works moderately reliably only if both streams are
589cdfa2a7eSchristos  * unbuffered or line buffered.  Unfortunately stdout can be fully
590cdfa2a7eSchristos  * buffered on pipes or files...
591cdfa2a7eSchristos  */
592cdfa2a7eSchristos int
593cdfa2a7eSchristos change_iobufs(
594cdfa2a7eSchristos 	int how
595cdfa2a7eSchristos 	)
596cdfa2a7eSchristos {
597cdfa2a7eSchristos 	int	retv = 0;
598cdfa2a7eSchristos 
599cdfa2a7eSchristos #   ifdef HAVE_SETVBUF
600cdfa2a7eSchristos 
601cdfa2a7eSchristos 	int mode;
602cdfa2a7eSchristos 
603cdfa2a7eSchristos 	switch (how) {
604cdfa2a7eSchristos 	case 0 : mode = _IONBF; break; /* no buffering   */
605cdfa2a7eSchristos 	case 1 : mode = _IOLBF; break; /* line buffering */
606cdfa2a7eSchristos 	case 2 : mode = _IOFBF; break; /* full buffering */
607cdfa2a7eSchristos 	default: mode = _IOLBF; break; /* line buffering */
608cdfa2a7eSchristos 	}
609cdfa2a7eSchristos 
610cdfa2a7eSchristos 	retv = 1;
611cdfa2a7eSchristos 	if (setvbuf(stdout, NULL, mode, BUFSIZ) != 0)
612cdfa2a7eSchristos 		retv = -1;
613cdfa2a7eSchristos 	if (setvbuf(stderr, NULL, mode, BUFSIZ) != 0)
614cdfa2a7eSchristos 		retv = -1;
615cdfa2a7eSchristos 
616cdfa2a7eSchristos #   else
617cdfa2a7eSchristos 
618cdfa2a7eSchristos 	UNUSED_ARG(how);
619cdfa2a7eSchristos 
620cdfa2a7eSchristos #   endif
621cdfa2a7eSchristos 
622cdfa2a7eSchristos 	return retv;
623cdfa2a7eSchristos }
624