154359Sroberto/*
254359Sroberto * msyslog - either send a message to the terminal or print it on
354359Sroberto *	     the standard output.
454359Sroberto *
554359Sroberto * Converted to use varargs, much better ... jks
654359Sroberto */
754359Sroberto
854359Sroberto#ifdef HAVE_CONFIG_H
954359Sroberto# include <config.h>
1054359Sroberto#endif
1154359Sroberto
12280849Scy#include <sys/types.h>
1354359Sroberto#ifdef HAVE_UNISTD_H
1454359Sroberto# include <unistd.h>
1554359Sroberto#endif
1654359Sroberto#include <stdio.h>
1754359Sroberto
1854359Sroberto#include "ntp_string.h"
19280849Scy#include "ntp.h"
20280849Scy#include "ntp_debug.h"
2182498Sroberto#include "ntp_syslog.h"
2254359Sroberto
2354359Sroberto#ifdef SYS_WINNT
24132451Sroberto# include <stdarg.h>
2554359Sroberto# include "..\ports\winnt\libntp\messages.h"
2654359Sroberto#endif
2754359Sroberto
2854359Sroberto
29280849Scyint	syslogit = TRUE;
30280849Scyint	msyslog_term = FALSE;	/* duplicate to stdout/err */
31280849Scyint	msyslog_term_pid = TRUE;
32280849Scyint	msyslog_include_timestamp = TRUE;
33280849ScyFILE *	syslog_file;
34280849Scychar *	syslog_fname;
35280849Scychar *	syslog_abs_fname;
3654359Sroberto
37280849Scy/* libntp default ntp_syslogmask is all bits lit */
38280849Scy#define INIT_NTP_SYSLOGMASK	~(u_int32)0
39280849Scyu_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK;
4054359Sroberto
41289764Sglebiusextern char const * progname;
4254359Sroberto
43132451Sroberto/* Declare the local functions */
44280849Scyvoid	addto_syslog	(int, const char *);
45280849Scy#ifndef VSNPRINTF_PERCENT_M
46280849Scyvoid	format_errmsg	(char *, size_t, const char *, int);
47132451Sroberto
48280849Scy/* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */
49132451Srobertovoid
50280849Scyformat_errmsg(
51280849Scy	char *		nfmt,
52280849Scy	size_t		lennfmt,
53280849Scy	const char *	fmt,
54280849Scy	int		errval
55280849Scy	)
5654359Sroberto{
57280849Scy	char errmsg[256];
58280849Scy	char c;
59280849Scy	char *n;
60280849Scy	const char *f;
61280849Scy	size_t len;
62132451Sroberto
6354359Sroberto	n = nfmt;
6454359Sroberto	f = fmt;
65280849Scy	while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) {
6654359Sroberto		if (c != '%') {
6754359Sroberto			*n++ = c;
6854359Sroberto			continue;
6954359Sroberto		}
7054359Sroberto		if ((c = *f++) != 'm') {
7154359Sroberto			*n++ = '%';
72280849Scy			if ('\0' == c)
73280849Scy				break;
7454359Sroberto			*n++ = c;
7554359Sroberto			continue;
7654359Sroberto		}
77280849Scy		errno_to_str(errval, errmsg, sizeof(errmsg));
78280849Scy		len = strlen(errmsg);
79280849Scy
80132451Sroberto		/* Make sure we have enough space for the error message */
81280849Scy		if ((n + len) < (nfmt + lennfmt - 1)) {
82280849Scy			memcpy(n, errmsg, len);
83280849Scy			n += len;
8454359Sroberto		}
8554359Sroberto	}
8654359Sroberto	*n = '\0';
87132451Sroberto}
88280849Scy#endif	/* VSNPRINTF_PERCENT_M */
8954359Sroberto
90280849Scy
91132451Sroberto/*
92280849Scy * errno_to_str() - a thread-safe strerror() replacement.
93280849Scy *		    Hides the varied signatures of strerror_r().
94280849Scy *		    For Windows, we have:
95280849Scy *			#define errno_to_str isc_strerror
96132451Sroberto */
97280849Scy#ifndef errno_to_str
98280849Scyvoid
99280849Scyerrno_to_str(
100280849Scy	int	err,
101280849Scy	char *	buf,
102280849Scy	size_t	bufsiz
103280849Scy	)
104280849Scy{
105280849Scy# if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R
106280849Scy	char *	pstatic;
107132451Sroberto
108280849Scy	buf[0] = '\0';
109280849Scy#  ifdef STRERROR_R_CHAR_P
110280849Scy	pstatic = strerror_r(err, buf, bufsiz);
111280849Scy#  else
112280849Scy	pstatic = strerror(err);
113280849Scy#  endif
114280849Scy	if (NULL == pstatic && '\0' == buf[0])
115280849Scy		snprintf(buf, bufsiz, "%s(%d): errno %d",
116280849Scy#  ifdef STRERROR_R_CHAR_P
117280849Scy			 "strerror_r",
118280849Scy#  else
119280849Scy			 "strerror",
120280849Scy#  endif
121280849Scy			 err, errno);
122280849Scy	/* protect against believing an int return is a pointer */
123280849Scy	else if (pstatic != buf && pstatic > (char *)bufsiz)
124280849Scy		strlcpy(buf, pstatic, bufsiz);
125280849Scy# else
126280849Scy	int	rc;
127280849Scy
128280849Scy	rc = strerror_r(err, buf, bufsiz);
129280849Scy	if (rc < 0)
130280849Scy		snprintf(buf, bufsiz, "strerror_r(%d): errno %d",
131280849Scy			 err, errno);
132280849Scy# endif
133280849Scy}
134280849Scy#endif	/* errno_to_str */
135280849Scy
136280849Scy
137280849Scy/*
138280849Scy * addto_syslog()
139280849Scy * This routine adds the contents of a buffer to the syslog or an
140280849Scy * application-specific logfile.
141280849Scy */
142280849Scyvoid
143280849Scyaddto_syslog(
144280849Scy	int		level,
145280849Scy	const char *	msg
146280849Scy	)
147132451Sroberto{
148289764Sglebius	static char const *	prevcall_progname;
149289764Sglebius	static char const *	prog;
150280849Scy	const char	nl[] = "\n";
151280849Scy	const char	empty[] = "";
152280849Scy	FILE *		term_file;
153280849Scy	int		log_to_term;
154280849Scy	int		log_to_file;
155280849Scy	int		pid;
156280849Scy	const char *	nl_or_empty;
157280849Scy	const char *	human_time;
158280849Scy
159280849Scy	/* setup program basename static var prog if needed */
160280849Scy	if (progname != prevcall_progname) {
161280849Scy		prevcall_progname = progname;
162280849Scy		prog = strrchr(progname, DIR_SEP);
163280849Scy		if (prog != NULL)
164280849Scy			prog++;
165280849Scy		else
166280849Scy			prog = progname;
167280849Scy	}
168280849Scy
169280849Scy	log_to_term = msyslog_term;
170280849Scy	log_to_file = FALSE;
171280849Scy#if !defined(VMS) && !defined(SYS_VXWORKS)
172280849Scy	if (syslogit)
173280849Scy		syslog(level, "%s", msg);
174280849Scy	else
175280849Scy#endif
176280849Scy		if (syslog_file != NULL)
177280849Scy			log_to_file = TRUE;
178280849Scy		else
179280849Scy			log_to_term = TRUE;
180280849Scy#if DEBUG
181280849Scy	if (debug > 0)
182280849Scy		log_to_term = TRUE;
183280849Scy#endif
184280849Scy	if (!(log_to_file || log_to_term))
185280849Scy		return;
186280849Scy
187280849Scy	/* syslog() adds the timestamp, name, and pid */
188280849Scy	if (msyslog_include_timestamp)
189280849Scy		human_time = humanlogtime();
190280849Scy	else	/* suppress gcc pot. uninit. warning */
191280849Scy		human_time = NULL;
192280849Scy	if (msyslog_term_pid || log_to_file)
193280849Scy		pid = getpid();
194280849Scy	else	/* suppress gcc pot. uninit. warning */
195280849Scy		pid = -1;
196280849Scy
197280849Scy	/* syslog() adds trailing \n if not present */
198280849Scy	if ('\n' != msg[strlen(msg) - 1])
199280849Scy		nl_or_empty = nl;
200280849Scy	else
201280849Scy		nl_or_empty = empty;
202280849Scy
203280849Scy	if (log_to_term) {
204280849Scy		term_file = (level <= LOG_ERR)
205280849Scy				? stderr
206280849Scy				: stdout;
207280849Scy		if (msyslog_include_timestamp)
208280849Scy			fprintf(term_file, "%s ", human_time);
209280849Scy		if (msyslog_term_pid)
210280849Scy			fprintf(term_file, "%s[%d]: ", prog, pid);
211280849Scy		fprintf(term_file, "%s%s", msg, nl_or_empty);
212280849Scy		fflush(term_file);
213280849Scy	}
214280849Scy
215280849Scy	if (log_to_file) {
216280849Scy		if (msyslog_include_timestamp)
217280849Scy			fprintf(syslog_file, "%s ", human_time);
218280849Scy		fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg,
219280849Scy			nl_or_empty);
220280849Scy		fflush(syslog_file);
221280849Scy	}
222280849Scy}
223280849Scy
224280849Scy
225280849Scyint
226280849Scymvsnprintf(
227280849Scy	char *		buf,
228280849Scy	size_t		bufsiz,
229280849Scy	const char *	fmt,
230280849Scy	va_list		ap
231280849Scy	)
232280849Scy{
233280849Scy#ifndef VSNPRINTF_PERCENT_M
234280849Scy	char		nfmt[256];
235132451Sroberto#else
236280849Scy	const char *	nfmt = fmt;
237132451Sroberto#endif
238280849Scy	int		errval;
239132451Sroberto
240132451Sroberto	/*
241132451Sroberto	 * Save the error value as soon as possible
242132451Sroberto	 */
243132451Sroberto#ifdef SYS_WINNT
244280849Scy	errval = GetLastError();
245280849Scy	if (NO_ERROR == errval)
246280849Scy#endif /* SYS_WINNT */
247280849Scy		errval = errno;
248280849Scy
249280849Scy#ifndef VSNPRINTF_PERCENT_M
250280849Scy	format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
251132451Sroberto#else
252280849Scy	errno = errval;
253132451Sroberto#endif
254280849Scy	return vsnprintf(buf, bufsiz, nfmt, ap);
255280849Scy}
256132451Sroberto
257132451Sroberto
258280849Scyint
259280849Scymvfprintf(
260280849Scy	FILE *		fp,
261280849Scy	const char *	fmt,
262280849Scy	va_list		ap
263280849Scy	)
264132451Sroberto{
265280849Scy#ifndef VSNPRINTF_PERCENT_M
266280849Scy	char		nfmt[256];
26754359Sroberto#else
268280849Scy	const char *	nfmt = fmt;
269132451Sroberto#endif
270280849Scy	int		errval;
27154359Sroberto
272132451Sroberto	/*
273132451Sroberto	 * Save the error value as soon as possible
274132451Sroberto	 */
275132451Sroberto#ifdef SYS_WINNT
276280849Scy	errval = GetLastError();
277280849Scy	if (NO_ERROR == errval)
278280849Scy#endif /* SYS_WINNT */
279280849Scy		errval = errno;
280280849Scy
281280849Scy#ifndef VSNPRINTF_PERCENT_M
282280849Scy	format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
283132451Sroberto#else
284280849Scy	errno = errval;
285132451Sroberto#endif
286280849Scy	return vfprintf(fp, nfmt, ap);
287280849Scy}
288132451Sroberto
289280849Scy
290280849Scyint
291280849Scymfprintf(
292280849Scy	FILE *		fp,
293280849Scy	const char *	fmt,
294280849Scy	...
295280849Scy	)
296280849Scy{
297280849Scy	va_list		ap;
298280849Scy	int		rc;
299280849Scy
300132451Sroberto	va_start(ap, fmt);
301280849Scy	rc = mvfprintf(fp, fmt, ap);
302280849Scy	va_end(ap);
303132451Sroberto
304280849Scy	return rc;
305280849Scy}
306132451Sroberto
307280849Scy
308280849Scyint
309280849Scymprintf(
310280849Scy	const char *	fmt,
311280849Scy	...
312280849Scy	)
313280849Scy{
314280849Scy	va_list		ap;
315280849Scy	int		rc;
316280849Scy
317280849Scy	va_start(ap, fmt);
318280849Scy	rc = mvfprintf(stdout, fmt, ap);
31954359Sroberto	va_end(ap);
320280849Scy
321280849Scy	return rc;
32254359Sroberto}
323280849Scy
324280849Scy
325280849Scyint
326280849Scymsnprintf(
327280849Scy	char *		buf,
328280849Scy	size_t		bufsiz,
329280849Scy	const char *	fmt,
330280849Scy	...
331280849Scy	)
332280849Scy{
333280849Scy	va_list	ap;
334293423Sdelphij	int	rc;
335280849Scy
336280849Scy	va_start(ap, fmt);
337280849Scy	rc = mvsnprintf(buf, bufsiz, fmt, ap);
338280849Scy	va_end(ap);
339280849Scy
340280849Scy	return rc;
341280849Scy}
342280849Scy
343280849Scy
344280849Scyvoid
345280849Scymsyslog(
346280849Scy	int		level,
347280849Scy	const char *	fmt,
348280849Scy	...
349280849Scy	)
350280849Scy{
351280849Scy	char	buf[1024];
352280849Scy	va_list	ap;
353280849Scy
354280849Scy	va_start(ap, fmt);
355280849Scy	mvsnprintf(buf, sizeof(buf), fmt, ap);
356280849Scy	va_end(ap);
357280849Scy	addto_syslog(level, buf);
358280849Scy}
359280849Scy
360289764Sglebiusvoid
361289764Sglebiusmvsyslog(
362289764Sglebius	int		level,
363289764Sglebius	const char *	fmt,
364289764Sglebius	va_list		ap
365289764Sglebius	)
366289764Sglebius{
367289764Sglebius	char	buf[1024];
368289764Sglebius	mvsnprintf(buf, sizeof(buf), fmt, ap);
369289764Sglebius	addto_syslog(level, buf);
370289764Sglebius}
371280849Scy
372289764Sglebius
373280849Scy/*
374280849Scy * Initialize the logging
375280849Scy *
376280849Scy * Called once per process, including forked children.
377280849Scy */
378280849Scyvoid
379280849Scyinit_logging(
380280849Scy	const char *	name,
381280849Scy	u_int32		def_syslogmask,
382280849Scy	int		is_daemon
383280849Scy	)
384280849Scy{
385280849Scy	static int	was_daemon;
386289764Sglebius	char *		cp;
387280849Scy	const char *	pname;
388280849Scy
389280849Scy	/*
390280849Scy	 * ntpd defaults to only logging sync-category events, when
391280849Scy	 * NLOG() is used to conditionalize.  Other libntp clients
392280849Scy	 * leave it alone so that all NLOG() conditionals will fire.
393280849Scy	 * This presumes all bits lit in ntp_syslogmask can't be
394280849Scy	 * configured via logconfig and all lit is thereby a sentinel
395280849Scy	 * that ntp_syslogmask is still at its default from libntp,
396280849Scy	 * keeping in mind this function is called in forked children
397280849Scy	 * where it has already been called in the parent earlier.
398280849Scy	 * Forked children pass 0 for def_syslogmask.
399280849Scy	 */
400280849Scy	if (INIT_NTP_SYSLOGMASK == ntp_syslogmask &&
401280849Scy	    0 != def_syslogmask)
402280849Scy		ntp_syslogmask = def_syslogmask; /* set more via logconfig */
403280849Scy
404280849Scy	/*
405280849Scy	 * Logging.  This may actually work on the gizmo board.  Find a name
406280849Scy	 * to log with by using the basename
407280849Scy	 */
408280849Scy	cp = strrchr(name, DIR_SEP);
409280849Scy	if (NULL == cp)
410280849Scy		pname = name;
411280849Scy	else
412280849Scy		pname = 1 + cp;	/* skip DIR_SEP */
413280849Scy	progname = estrdup(pname);
414280849Scy#ifdef SYS_WINNT			/* strip ".exe" */
415280849Scy	cp = strrchr(progname, '.');
416280849Scy	if (NULL != cp && !strcasecmp(cp, ".exe"))
417289764Sglebius		*cp = '\0';
418280849Scy#endif
419280849Scy
420280849Scy#if !defined(VMS)
421280849Scy
422280849Scy	if (is_daemon)
423280849Scy		was_daemon = TRUE;
424280849Scy# ifndef LOG_DAEMON
425280849Scy	openlog(progname, LOG_PID);
426280849Scy# else /* LOG_DAEMON */
427280849Scy
428280849Scy#  ifndef LOG_NTP
429280849Scy#	define	LOG_NTP LOG_DAEMON
430280849Scy#  endif
431280849Scy	openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon)
432280849Scy						    ? LOG_NTP
433280849Scy						    : 0);
434280849Scy#  ifdef DEBUG
435280849Scy	if (debug)
436280849Scy		setlogmask(LOG_UPTO(LOG_DEBUG));
437280849Scy	else
438280849Scy#  endif /* DEBUG */
439280849Scy		setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
440280849Scy# endif /* LOG_DAEMON */
441280849Scy#endif	/* !VMS */
442280849Scy}
443280849Scy
444280849Scy
445280849Scy/*
446280849Scy * change_logfile()
447280849Scy *
448280849Scy * Used to change from syslog to a logfile, or from one logfile to
449280849Scy * another, and to reopen logfiles after forking.  On systems where
450280849Scy * ntpd forks, deals with converting relative logfile paths to
451280849Scy * absolute (root-based) because we reopen logfiles after the current
452280849Scy * directory has changed.
453280849Scy */
454280849Scyint
455280849Scychange_logfile(
456280849Scy	const char *	fname,
457280849Scy	int		leave_crumbs
458280849Scy	)
459280849Scy{
460280849Scy	FILE *		new_file;
461280849Scy	const char *	log_fname;
462280849Scy	char *		abs_fname;
463280849Scy#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
464280849Scy	char		curdir[512];
465280849Scy	size_t		cd_octets;
466280849Scy	size_t		octets;
467280849Scy#endif	/* POSIX */
468280849Scy
469289764Sglebius	REQUIRE(fname != NULL);
470280849Scy	log_fname = fname;
471280849Scy
472280849Scy	/*
473280849Scy	 * In a forked child of a parent which is logging to a file
474280849Scy	 * instead of syslog, syslog_file will be NULL and both
475280849Scy	 * syslog_fname and syslog_abs_fname will be non-NULL.
476280849Scy	 * If we are given the same filename previously opened
477280849Scy	 * and it's still open, there's nothing to do here.
478280849Scy	 */
479280849Scy	if (syslog_file != NULL && syslog_fname != NULL &&
480280849Scy	    0 == strcmp(syslog_fname, log_fname))
481280849Scy		return 0;
482280849Scy
483280849Scy	if (0 == strcmp(log_fname, "stderr")) {
484280849Scy		new_file = stderr;
485280849Scy		abs_fname = estrdup(log_fname);
486280849Scy	} else if (0 == strcmp(log_fname, "stdout")) {
487280849Scy		new_file = stdout;
488280849Scy		abs_fname = estrdup(log_fname);
489280849Scy	} else {
490280849Scy		if (syslog_fname != NULL &&
491280849Scy		    0 == strcmp(log_fname, syslog_fname))
492280849Scy			log_fname = syslog_abs_fname;
493280849Scy#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
494280849Scy		if (log_fname != syslog_abs_fname &&
495280849Scy		    DIR_SEP != log_fname[0] &&
496280849Scy		    0 != strcmp(log_fname, "stderr") &&
497280849Scy		    0 != strcmp(log_fname, "stdout") &&
498280849Scy		    NULL != getcwd(curdir, sizeof(curdir))) {
499280849Scy			cd_octets = strlen(curdir);
500280849Scy			/* trim any trailing '/' */
501280849Scy			if (cd_octets > 1 &&
502280849Scy			    DIR_SEP == curdir[cd_octets - 1])
503280849Scy				cd_octets--;
504280849Scy			octets = cd_octets;
505280849Scy			octets += 1;	/* separator '/' */
506280849Scy			octets += strlen(log_fname);
507280849Scy			octets += 1;	/* NUL terminator */
508280849Scy			abs_fname = emalloc(octets);
509280849Scy			snprintf(abs_fname, octets, "%.*s%c%s",
510280849Scy				 (int)cd_octets, curdir, DIR_SEP,
511280849Scy				 log_fname);
512280849Scy		} else
513280849Scy#endif
514280849Scy			abs_fname = estrdup(log_fname);
515280849Scy		TRACE(1, ("attempting to open log %s\n", abs_fname));
516280849Scy		new_file = fopen(abs_fname, "a");
517280849Scy	}
518280849Scy
519280849Scy	if (NULL == new_file) {
520280849Scy		free(abs_fname);
521280849Scy		return -1;
522280849Scy	}
523280849Scy
524280849Scy	/* leave a pointer in the old log */
525280849Scy	if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
526280849Scy		msyslog(LOG_NOTICE, "switching logging to file %s",
527280849Scy			abs_fname);
528280849Scy
529280849Scy	if (syslog_file != NULL &&
530280849Scy	    syslog_file != stderr && syslog_file != stdout &&
531280849Scy	    fileno(syslog_file) != fileno(new_file))
532280849Scy		fclose(syslog_file);
533280849Scy	syslog_file = new_file;
534280849Scy	if (log_fname == syslog_abs_fname) {
535280849Scy		free(abs_fname);
536280849Scy	} else {
537280849Scy		if (syslog_abs_fname != NULL &&
538280849Scy		    syslog_abs_fname != syslog_fname)
539280849Scy			free(syslog_abs_fname);
540280849Scy		if (syslog_fname != NULL)
541280849Scy			free(syslog_fname);
542280849Scy		syslog_fname = estrdup(log_fname);
543280849Scy		syslog_abs_fname = abs_fname;
544280849Scy	}
545280849Scy	syslogit = FALSE;
546280849Scy
547280849Scy	return 0;
548280849Scy}
549280849Scy
550280849Scy
551280849Scy/*
552280849Scy * setup_logfile()
553280849Scy *
554280849Scy * Redirect logging to a file if requested with -l/--logfile or via
555280849Scy * ntp.conf logfile directive.
556280849Scy *
557280849Scy * This routine is invoked three different times in the sequence of a
558280849Scy * typical daemon ntpd with DNS lookups to do.  First it is invoked in
559280849Scy * the original ntpd process, then again in the daemon after closing
560280849Scy * all descriptors.  In both of those cases, ntp.conf has not been
561280849Scy * processed, so only -l/--logfile will trigger logfile redirection in
562280849Scy * those invocations.  Finally, if DNS names are resolved, the worker
563280849Scy * child invokes this routine after its fork and close of all
564280849Scy * descriptors.  In this case, ntp.conf has been processed and any
565280849Scy * "logfile" directive needs to be honored in the child as well.
566280849Scy */
567280849Scyvoid
568280849Scysetup_logfile(
569280849Scy	const char *	name
570280849Scy	)
571280849Scy{
572280849Scy	if (NULL == syslog_fname && NULL != name) {
573280849Scy		if (-1 == change_logfile(name, TRUE))
574280849Scy			msyslog(LOG_ERR, "Cannot open log file %s, %m",
575280849Scy				name);
576280849Scy		return ;
577280849Scy	}
578280849Scy	if (NULL == syslog_fname)
579280849Scy		return;
580280849Scy
581280849Scy	if (-1 == change_logfile(syslog_fname, FALSE))
582280849Scy		msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
583280849Scy			syslog_fname);
584280849Scy}
585358659Scy
586358659Scy/* Helper for unit tests, where stdout + stderr are piped to the same
587358659Scy * stream.  This works moderately reliable only if both streams are
588358659Scy * unbuffered or line buffered.  Unfortunately stdout can be fully
589358659Scy * buffered on pipes or files...
590358659Scy */
591358659Scyint
592358659Scychange_iobufs(
593358659Scy	int how
594358659Scy	)
595358659Scy{
596358659Scy	int	retv = 0;
597358659Scy
598358659Scy#   ifdef HAVE_SETVBUF
599358659Scy
600358659Scy	int mode;
601358659Scy
602358659Scy	switch (how) {
603358659Scy	case 0 : mode = _IONBF; break; /* no buffering   */
604358659Scy	case 1 : mode = _IOLBF; break; /* line buffering */
605358659Scy	case 2 : mode = _IOFBF; break; /* full buffering */
606358659Scy	default: mode = _IOLBF; break; /* line buffering */
607358659Scy	}
608358659Scy
609358659Scy	retv = 1;
610358659Scy	if (setvbuf(stdout, NULL, mode, BUFSIZ) != 0)
611358659Scy		retv = -1;
612358659Scy	if (setvbuf(stderr, NULL, mode, BUFSIZ) != 0)
613358659Scy		retv = -1;
614358659Scy
615358659Scy#   else
616358659Scy
617358659Scy	UNUSED_ARG(how);
618358659Scy
619358659Scy#   endif
620358659Scy
621358659Scy	return retv;
622358659Scy}
623