xref: /illumos-gate/usr/src/lib/libresolv2/common/isc/logging.c (revision 458f44a49dc56cd17a39815122214e7a1b4793e3)
17c478bd9Sstevel@tonic-gate /*
2*9525b14bSRao Shoaib  * Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC")
3*9525b14bSRao Shoaib  * Copyright (C) 1996-1999, 2001, 2003  Internet Software Consortium.
47c478bd9Sstevel@tonic-gate  *
5*9525b14bSRao Shoaib  * Permission to use, copy, modify, and/or distribute this software for any
67c478bd9Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
77c478bd9Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
87c478bd9Sstevel@tonic-gate  *
9*9525b14bSRao Shoaib  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10*9525b14bSRao Shoaib  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11*9525b14bSRao Shoaib  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12*9525b14bSRao Shoaib  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13*9525b14bSRao Shoaib  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14*9525b14bSRao Shoaib  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15*9525b14bSRao Shoaib  * PERFORMANCE OF THIS SOFTWARE.
167c478bd9Sstevel@tonic-gate  */
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate #include "port_before.h"
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #include <sys/types.h>
217c478bd9Sstevel@tonic-gate #include <sys/time.h>
227c478bd9Sstevel@tonic-gate #include <sys/stat.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include <fcntl.h>
257c478bd9Sstevel@tonic-gate #include <limits.h>
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <stdarg.h>
307c478bd9Sstevel@tonic-gate #include <syslog.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate #include <time.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <isc/assertions.h>
367c478bd9Sstevel@tonic-gate #include <isc/logging.h>
377c478bd9Sstevel@tonic-gate #include <isc/memcluster.h>
387c478bd9Sstevel@tonic-gate #include <isc/misc.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "port_after.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include "logging_p.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static const int syslog_priority[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE,
457c478bd9Sstevel@tonic-gate 				       LOG_WARNING, LOG_ERR, LOG_CRIT };
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
487c478bd9Sstevel@tonic-gate 				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static const char *level_text[] = {
517c478bd9Sstevel@tonic-gate 	"info: ", "notice: ", "warning: ", "error: ", "critical: "
527c478bd9Sstevel@tonic-gate };
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static void
version_rename(log_channel chan)557c478bd9Sstevel@tonic-gate version_rename(log_channel chan) {
567c478bd9Sstevel@tonic-gate 	unsigned int ver;
577c478bd9Sstevel@tonic-gate 	char old_name[PATH_MAX+1];
587c478bd9Sstevel@tonic-gate 	char new_name[PATH_MAX+1];
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	ver = chan->out.file.versions;
617c478bd9Sstevel@tonic-gate 	if (ver < 1)
627c478bd9Sstevel@tonic-gate 		return;
637c478bd9Sstevel@tonic-gate 	if (ver > LOG_MAX_VERSIONS)
647c478bd9Sstevel@tonic-gate 		ver = LOG_MAX_VERSIONS;
657c478bd9Sstevel@tonic-gate 	/*
667c478bd9Sstevel@tonic-gate 	 * Need to have room for '.nn' (XXX assumes LOG_MAX_VERSIONS < 100)
677c478bd9Sstevel@tonic-gate 	 */
68*9525b14bSRao Shoaib 	if (strlen(chan->out.file.name) > (size_t)(PATH_MAX-3))
697c478bd9Sstevel@tonic-gate 		return;
707c478bd9Sstevel@tonic-gate 	for (ver--; ver > 0; ver--) {
717c478bd9Sstevel@tonic-gate 		sprintf(old_name, "%s.%d", chan->out.file.name, ver-1);
727c478bd9Sstevel@tonic-gate 		sprintf(new_name, "%s.%d", chan->out.file.name, ver);
73*9525b14bSRao Shoaib 		(void)isc_movefile(old_name, new_name);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 	sprintf(new_name, "%s.0", chan->out.file.name);
76*9525b14bSRao Shoaib 	(void)isc_movefile(chan->out.file.name, new_name);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate FILE *
log_open_stream(log_channel chan)807c478bd9Sstevel@tonic-gate log_open_stream(log_channel chan) {
817c478bd9Sstevel@tonic-gate 	FILE *stream;
827c478bd9Sstevel@tonic-gate 	int fd, flags;
837c478bd9Sstevel@tonic-gate 	struct stat sb;
847c478bd9Sstevel@tonic-gate 	int regular;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->type != log_file) {
877c478bd9Sstevel@tonic-gate 		errno = EINVAL;
887c478bd9Sstevel@tonic-gate 		return (NULL);
897c478bd9Sstevel@tonic-gate 	}
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	/*
927c478bd9Sstevel@tonic-gate 	 * Don't open already open streams
937c478bd9Sstevel@tonic-gate 	 */
947c478bd9Sstevel@tonic-gate 	if (chan->out.file.stream != NULL)
957c478bd9Sstevel@tonic-gate 		return (chan->out.file.stream);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (stat(chan->out.file.name, &sb) < 0) {
987c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) {
997c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
1007c478bd9Sstevel@tonic-gate 			       "log_open_stream: stat of %s failed: %s",
1017c478bd9Sstevel@tonic-gate 			       chan->out.file.name, strerror(errno));
1027c478bd9Sstevel@tonic-gate 			chan->flags |= LOG_CHANNEL_BROKEN;
1037c478bd9Sstevel@tonic-gate 			return (NULL);
1047c478bd9Sstevel@tonic-gate 		}
1057c478bd9Sstevel@tonic-gate 		regular = 1;
1067c478bd9Sstevel@tonic-gate 	} else
107*9525b14bSRao Shoaib 		regular = (sb.st_mode & S_IFREG);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	if (chan->out.file.versions) {
1107c478bd9Sstevel@tonic-gate 		if (!regular) {
1117c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
1127c478bd9Sstevel@tonic-gate        "log_open_stream: want versions but %s isn't a regular file",
1137c478bd9Sstevel@tonic-gate 			       chan->out.file.name);
1147c478bd9Sstevel@tonic-gate 			chan->flags |= LOG_CHANNEL_BROKEN;
1157c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1167c478bd9Sstevel@tonic-gate 			return (NULL);
1177c478bd9Sstevel@tonic-gate 		}
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	flags = O_WRONLY|O_CREAT|O_APPEND;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	if ((chan->flags & LOG_TRUNCATE) != 0) {
1237c478bd9Sstevel@tonic-gate 		if (regular) {
1247c478bd9Sstevel@tonic-gate 			(void)unlink(chan->out.file.name);
1257c478bd9Sstevel@tonic-gate 			flags |= O_EXCL;
1267c478bd9Sstevel@tonic-gate 		} else {
1277c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
1287c478bd9Sstevel@tonic-gate        "log_open_stream: want truncation but %s isn't a regular file",
1297c478bd9Sstevel@tonic-gate 			       chan->out.file.name);
1307c478bd9Sstevel@tonic-gate 			chan->flags |= LOG_CHANNEL_BROKEN;
1317c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1327c478bd9Sstevel@tonic-gate 			return (NULL);
1337c478bd9Sstevel@tonic-gate 		}
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	fd = open(chan->out.file.name, flags,
1377c478bd9Sstevel@tonic-gate 		  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1387c478bd9Sstevel@tonic-gate 	if (fd < 0) {
1397c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "log_open_stream: open(%s) failed: %s",
1407c478bd9Sstevel@tonic-gate 		       chan->out.file.name, strerror(errno));
1417c478bd9Sstevel@tonic-gate 		chan->flags |= LOG_CHANNEL_BROKEN;
1427c478bd9Sstevel@tonic-gate 		return (NULL);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 	stream = fdopen(fd, "a");
1457c478bd9Sstevel@tonic-gate 	if (stream == NULL) {
1467c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "log_open_stream: fdopen() failed");
1477c478bd9Sstevel@tonic-gate 		chan->flags |= LOG_CHANNEL_BROKEN;
1487c478bd9Sstevel@tonic-gate 		return (NULL);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 	(void) fchown(fd, chan->out.file.owner, chan->out.file.group);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	chan->out.file.stream = stream;
1537c478bd9Sstevel@tonic-gate 	return (stream);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate int
log_close_stream(log_channel chan)1577c478bd9Sstevel@tonic-gate log_close_stream(log_channel chan) {
1587c478bd9Sstevel@tonic-gate 	FILE *stream;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->type != log_file) {
1617c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1627c478bd9Sstevel@tonic-gate 		return (0);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	stream = chan->out.file.stream;
1657c478bd9Sstevel@tonic-gate 	chan->out.file.stream = NULL;
1667c478bd9Sstevel@tonic-gate 	if (stream != NULL && fclose(stream) == EOF)
1677c478bd9Sstevel@tonic-gate 		return (-1);
1687c478bd9Sstevel@tonic-gate 	return (0);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate void
log_close_debug_channels(log_context lc)1727c478bd9Sstevel@tonic-gate log_close_debug_channels(log_context lc) {
1737c478bd9Sstevel@tonic-gate 	log_channel_list lcl;
1747c478bd9Sstevel@tonic-gate 	int i;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	for (i = 0; i < lc->num_categories; i++)
1777c478bd9Sstevel@tonic-gate 		for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl->next)
1787c478bd9Sstevel@tonic-gate 			if (lcl->channel->type == log_file &&
1797c478bd9Sstevel@tonic-gate 			    lcl->channel->out.file.stream != NULL &&
1807c478bd9Sstevel@tonic-gate 			    lcl->channel->flags & LOG_REQUIRE_DEBUG)
1817c478bd9Sstevel@tonic-gate 				(void)log_close_stream(lcl->channel);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate FILE *
log_get_stream(log_channel chan)1857c478bd9Sstevel@tonic-gate log_get_stream(log_channel chan) {
1867c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->type != log_file) {
1877c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1887c478bd9Sstevel@tonic-gate 		return (NULL);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 	return (chan->out.file.stream);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate char *
log_get_filename(log_channel chan)1947c478bd9Sstevel@tonic-gate log_get_filename(log_channel chan) {
1957c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->type != log_file) {
1967c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1977c478bd9Sstevel@tonic-gate 		return (NULL);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	return (chan->out.file.name);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate int
log_check_channel(log_context lc,int level,log_channel chan)2037c478bd9Sstevel@tonic-gate log_check_channel(log_context lc, int level, log_channel chan) {
2047c478bd9Sstevel@tonic-gate 	int debugging, chan_level;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	REQUIRE(lc != NULL);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * If not debugging, short circuit debugging messages very early.
2127c478bd9Sstevel@tonic-gate 	 */
2137c478bd9Sstevel@tonic-gate 	if (level > 0 && !debugging)
2147c478bd9Sstevel@tonic-gate 		return (0);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if ((chan->flags & (LOG_CHANNEL_BROKEN|LOG_CHANNEL_OFF)) != 0)
2177c478bd9Sstevel@tonic-gate 		return (0);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* Some channels only log when debugging is on. */
2207c478bd9Sstevel@tonic-gate 	if ((chan->flags & LOG_REQUIRE_DEBUG) && !debugging)
2217c478bd9Sstevel@tonic-gate 		return (0);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/* Some channels use the global level. */
2247c478bd9Sstevel@tonic-gate 	if ((chan->flags & LOG_USE_CONTEXT_LEVEL) != 0) {
2257c478bd9Sstevel@tonic-gate 		chan_level = lc->level;
2267c478bd9Sstevel@tonic-gate 	} else
2277c478bd9Sstevel@tonic-gate 		chan_level = chan->level;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (level > chan_level)
2307c478bd9Sstevel@tonic-gate 		return (0);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (1);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate int
log_check(log_context lc,int category,int level)2367c478bd9Sstevel@tonic-gate log_check(log_context lc, int category, int level) {
2377c478bd9Sstevel@tonic-gate 	log_channel_list lcl;
2387c478bd9Sstevel@tonic-gate 	int debugging;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	REQUIRE(lc != NULL);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * If not debugging, short circuit debugging messages very early.
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (level > 0 && !debugging)
2487c478bd9Sstevel@tonic-gate 		return (0);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (category < 0 || category > lc->num_categories)
251*9525b14bSRao Shoaib 		category = 0;		/*%< use default */
2527c478bd9Sstevel@tonic-gate 	lcl = lc->categories[category];
2537c478bd9Sstevel@tonic-gate 	if (lcl == NULL) {
2547c478bd9Sstevel@tonic-gate 		category = 0;
2557c478bd9Sstevel@tonic-gate 		lcl = lc->categories[0];
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
2597c478bd9Sstevel@tonic-gate 		if (log_check_channel(lc, level, lcl->channel))
2607c478bd9Sstevel@tonic-gate 			return (1);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	return (0);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate void
log_vwrite(log_context lc,int category,int level,const char * format,va_list args)2667c478bd9Sstevel@tonic-gate log_vwrite(log_context lc, int category, int level, const char *format,
2677c478bd9Sstevel@tonic-gate 	   va_list args) {
2687c478bd9Sstevel@tonic-gate 	log_channel_list lcl;
2697c478bd9Sstevel@tonic-gate 	int pri, debugging, did_vsprintf = 0;
2707c478bd9Sstevel@tonic-gate 	int original_category;
2717c478bd9Sstevel@tonic-gate 	FILE *stream;
2727c478bd9Sstevel@tonic-gate 	log_channel chan;
2737c478bd9Sstevel@tonic-gate 	struct timeval tv;
2747c478bd9Sstevel@tonic-gate 	struct tm *local_tm;
2757c478bd9Sstevel@tonic-gate #ifdef HAVE_TIME_R
2767c478bd9Sstevel@tonic-gate 	struct tm tm_tmp;
2777c478bd9Sstevel@tonic-gate #endif
2787c478bd9Sstevel@tonic-gate 	time_t tt;
2797c478bd9Sstevel@tonic-gate 	const char *category_name;
2807c478bd9Sstevel@tonic-gate 	const char *level_str;
2817c478bd9Sstevel@tonic-gate 	char time_buf[256];
2827c478bd9Sstevel@tonic-gate 	char level_buf[256];
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	REQUIRE(lc != NULL);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	debugging = (lc->flags & LOG_OPTION_DEBUG);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * If not debugging, short circuit debugging messages very early.
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	if (level > 0 && !debugging)
2927c478bd9Sstevel@tonic-gate 		return;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (category < 0 || category > lc->num_categories)
295*9525b14bSRao Shoaib 		category = 0;		/*%< use default */
2967c478bd9Sstevel@tonic-gate 	original_category = category;
2977c478bd9Sstevel@tonic-gate 	lcl = lc->categories[category];
2987c478bd9Sstevel@tonic-gate 	if (lcl == NULL) {
2997c478bd9Sstevel@tonic-gate 		category = 0;
3007c478bd9Sstevel@tonic-gate 		lcl = lc->categories[0];
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/*
3047c478bd9Sstevel@tonic-gate 	 * Get the current time and format it.
3057c478bd9Sstevel@tonic-gate 	 */
3067c478bd9Sstevel@tonic-gate 	time_buf[0]='\0';
3077c478bd9Sstevel@tonic-gate 	if (gettimeofday(&tv, NULL) < 0) {
3087c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, "gettimeofday failed in log_vwrite()");
3097c478bd9Sstevel@tonic-gate 	} else {
3107c478bd9Sstevel@tonic-gate 		tt = tv.tv_sec;
3117c478bd9Sstevel@tonic-gate #ifdef HAVE_TIME_R
3127c478bd9Sstevel@tonic-gate 		local_tm = localtime_r(&tt, &tm_tmp);
3137c478bd9Sstevel@tonic-gate #else
3147c478bd9Sstevel@tonic-gate 		local_tm = localtime(&tt);
3157c478bd9Sstevel@tonic-gate #endif
3167c478bd9Sstevel@tonic-gate 		if (local_tm != NULL) {
3177c478bd9Sstevel@tonic-gate 			sprintf(time_buf, "%02d-%s-%4d %02d:%02d:%02d.%03ld ",
3187c478bd9Sstevel@tonic-gate 				local_tm->tm_mday, months[local_tm->tm_mon],
3197c478bd9Sstevel@tonic-gate 				local_tm->tm_year+1900, local_tm->tm_hour,
3207c478bd9Sstevel@tonic-gate 				local_tm->tm_min, local_tm->tm_sec,
3217c478bd9Sstevel@tonic-gate 				(long)tv.tv_usec/1000);
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * Make a string representation of the current category and level
3277c478bd9Sstevel@tonic-gate 	 */
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if (lc->category_names != NULL &&
3307c478bd9Sstevel@tonic-gate 	    lc->category_names[original_category] != NULL)
3317c478bd9Sstevel@tonic-gate 		category_name = lc->category_names[original_category];
3327c478bd9Sstevel@tonic-gate 	else
3337c478bd9Sstevel@tonic-gate 		category_name = "";
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	if (level >= log_critical) {
3367c478bd9Sstevel@tonic-gate 		if (level >= 0) {
3377c478bd9Sstevel@tonic-gate 			sprintf(level_buf, "debug %d: ", level);
3387c478bd9Sstevel@tonic-gate 			level_str = level_buf;
3397c478bd9Sstevel@tonic-gate 		} else
3407c478bd9Sstevel@tonic-gate 			level_str = level_text[-level-1];
3417c478bd9Sstevel@tonic-gate 	} else {
3427c478bd9Sstevel@tonic-gate 		sprintf(level_buf, "level %d: ", level);
3437c478bd9Sstevel@tonic-gate 		level_str = level_buf;
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/*
3477c478bd9Sstevel@tonic-gate 	 * Write the message to channels.
3487c478bd9Sstevel@tonic-gate 	 */
3497c478bd9Sstevel@tonic-gate 	for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
3507c478bd9Sstevel@tonic-gate 		chan = lcl->channel;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		if (!log_check_channel(lc, level, chan))
3537c478bd9Sstevel@tonic-gate 			continue;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		if (!did_vsprintf) {
356*9525b14bSRao Shoaib 			(void)vsprintf(lc->buffer, format, args);
357*9525b14bSRao Shoaib 			if (strlen(lc->buffer) > (size_t)LOG_BUFFER_SIZE) {
3587c478bd9Sstevel@tonic-gate 				syslog(LOG_CRIT,
3597c478bd9Sstevel@tonic-gate 				       "memory overrun in log_vwrite()");
3607c478bd9Sstevel@tonic-gate 				exit(1);
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 			did_vsprintf = 1;
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		switch (chan->type) {
3667c478bd9Sstevel@tonic-gate 		case log_syslog:
3677c478bd9Sstevel@tonic-gate 			if (level >= log_critical)
3687c478bd9Sstevel@tonic-gate 				pri = (level >= 0) ? 0 : -level;
3697c478bd9Sstevel@tonic-gate 			else
3707c478bd9Sstevel@tonic-gate 				pri = -log_critical;
3717c478bd9Sstevel@tonic-gate 			syslog(chan->out.facility|syslog_priority[pri],
3727c478bd9Sstevel@tonic-gate 			       "%s%s%s%s",
3737c478bd9Sstevel@tonic-gate 			       (chan->flags & LOG_TIMESTAMP) ?	time_buf : "",
3747c478bd9Sstevel@tonic-gate 			       (chan->flags & LOG_PRINT_CATEGORY) ?
3757c478bd9Sstevel@tonic-gate 			       category_name : "",
3767c478bd9Sstevel@tonic-gate 			       (chan->flags & LOG_PRINT_LEVEL) ?
3777c478bd9Sstevel@tonic-gate 			       level_str : "",
3787c478bd9Sstevel@tonic-gate 			       lc->buffer);
3797c478bd9Sstevel@tonic-gate 			break;
3807c478bd9Sstevel@tonic-gate 		case log_file:
3817c478bd9Sstevel@tonic-gate 			stream = chan->out.file.stream;
3827c478bd9Sstevel@tonic-gate 			if (stream == NULL) {
3837c478bd9Sstevel@tonic-gate 				stream = log_open_stream(chan);
3847c478bd9Sstevel@tonic-gate 				if (stream == NULL)
3857c478bd9Sstevel@tonic-gate 					break;
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 			if (chan->out.file.max_size != ULONG_MAX) {
3887c478bd9Sstevel@tonic-gate 				long pos;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 				pos = ftell(stream);
3917c478bd9Sstevel@tonic-gate 				if (pos >= 0 &&
3927c478bd9Sstevel@tonic-gate 				    (unsigned long)pos >
3937c478bd9Sstevel@tonic-gate 				    chan->out.file.max_size) {
3947c478bd9Sstevel@tonic-gate 					/*
3957c478bd9Sstevel@tonic-gate 					 * try to roll over the log files,
3967c478bd9Sstevel@tonic-gate 					 * ignoring all all return codes
3977c478bd9Sstevel@tonic-gate 					 * except the open (we don't want
3987c478bd9Sstevel@tonic-gate 					 * to write any more anyway)
3997c478bd9Sstevel@tonic-gate 					 */
4007c478bd9Sstevel@tonic-gate 					log_close_stream(chan);
4017c478bd9Sstevel@tonic-gate 					version_rename(chan);
4027c478bd9Sstevel@tonic-gate 					stream = log_open_stream(chan);
4037c478bd9Sstevel@tonic-gate 					if (stream == NULL)
4047c478bd9Sstevel@tonic-gate 						break;
4057c478bd9Sstevel@tonic-gate 				}
4067c478bd9Sstevel@tonic-gate 			}
4077c478bd9Sstevel@tonic-gate 			fprintf(stream, "%s%s%s%s\n",
4087c478bd9Sstevel@tonic-gate 				(chan->flags & LOG_TIMESTAMP) ?	time_buf : "",
4097c478bd9Sstevel@tonic-gate 				(chan->flags & LOG_PRINT_CATEGORY) ?
4107c478bd9Sstevel@tonic-gate 				category_name : "",
4117c478bd9Sstevel@tonic-gate 				(chan->flags & LOG_PRINT_LEVEL) ?
4127c478bd9Sstevel@tonic-gate 				level_str : "",
4137c478bd9Sstevel@tonic-gate 				lc->buffer);
4147c478bd9Sstevel@tonic-gate 			fflush(stream);
4157c478bd9Sstevel@tonic-gate 			break;
4167c478bd9Sstevel@tonic-gate 		case log_null:
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		default:
4197c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
4207c478bd9Sstevel@tonic-gate 			       "unknown channel type in log_vwrite()");
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate void
log_write(log_context lc,int category,int level,const char * format,...)4267c478bd9Sstevel@tonic-gate log_write(log_context lc, int category, int level, const char *format, ...) {
4277c478bd9Sstevel@tonic-gate 	va_list args;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	va_start(args, format);
4307c478bd9Sstevel@tonic-gate 	log_vwrite(lc, category, level, format, args);
4317c478bd9Sstevel@tonic-gate 	va_end(args);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
434*9525b14bSRao Shoaib /*%
4357c478bd9Sstevel@tonic-gate  * Functions to create, set, or destroy contexts
4367c478bd9Sstevel@tonic-gate  */
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate int
log_new_context(int num_categories,char ** category_names,log_context * lc)4397c478bd9Sstevel@tonic-gate log_new_context(int num_categories, char **category_names, log_context *lc) {
4407c478bd9Sstevel@tonic-gate 	log_context nlc;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	nlc = memget(sizeof (struct log_context));
4437c478bd9Sstevel@tonic-gate 	if (nlc == NULL) {
4447c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
4457c478bd9Sstevel@tonic-gate 		return (-1);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 	nlc->num_categories = num_categories;
4487c478bd9Sstevel@tonic-gate 	nlc->category_names = category_names;
4497c478bd9Sstevel@tonic-gate 	nlc->categories = memget(num_categories * sizeof (log_channel_list));
4507c478bd9Sstevel@tonic-gate 	if (nlc->categories == NULL) {
4517c478bd9Sstevel@tonic-gate 		memput(nlc, sizeof (struct log_context));
4527c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
4537c478bd9Sstevel@tonic-gate 		return (-1);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	memset(nlc->categories, '\0',
4567c478bd9Sstevel@tonic-gate 	       num_categories * sizeof (log_channel_list));
4577c478bd9Sstevel@tonic-gate 	nlc->flags = 0U;
4587c478bd9Sstevel@tonic-gate 	nlc->level = 0;
4597c478bd9Sstevel@tonic-gate 	*lc = nlc;
4607c478bd9Sstevel@tonic-gate 	return (0);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate void
log_free_context(log_context lc)4647c478bd9Sstevel@tonic-gate log_free_context(log_context lc) {
4657c478bd9Sstevel@tonic-gate 	log_channel_list lcl, lcl_next;
4667c478bd9Sstevel@tonic-gate 	log_channel chan;
4677c478bd9Sstevel@tonic-gate 	int i;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	REQUIRE(lc != NULL);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	for (i = 0; i < lc->num_categories; i++)
4727c478bd9Sstevel@tonic-gate 		for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl_next) {
4737c478bd9Sstevel@tonic-gate 			lcl_next = lcl->next;
4747c478bd9Sstevel@tonic-gate 			chan = lcl->channel;
4757c478bd9Sstevel@tonic-gate 			(void)log_free_channel(chan);
4767c478bd9Sstevel@tonic-gate 			memput(lcl, sizeof (struct log_channel_list));
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 	memput(lc->categories,
4797c478bd9Sstevel@tonic-gate 	       lc->num_categories * sizeof (log_channel_list));
4807c478bd9Sstevel@tonic-gate 	memput(lc, sizeof (struct log_context));
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate int
log_add_channel(log_context lc,int category,log_channel chan)4847c478bd9Sstevel@tonic-gate log_add_channel(log_context lc, int category, log_channel chan) {
4857c478bd9Sstevel@tonic-gate 	log_channel_list lcl;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (lc == NULL || category < 0 || category >= lc->num_categories) {
4887c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4897c478bd9Sstevel@tonic-gate 		return (-1);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	lcl = memget(sizeof (struct log_channel_list));
4937c478bd9Sstevel@tonic-gate 	if (lcl == NULL) {
4947c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
4957c478bd9Sstevel@tonic-gate 		return(-1);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 	lcl->channel = chan;
4987c478bd9Sstevel@tonic-gate 	lcl->next = lc->categories[category];
4997c478bd9Sstevel@tonic-gate 	lc->categories[category] = lcl;
5007c478bd9Sstevel@tonic-gate 	chan->references++;
5017c478bd9Sstevel@tonic-gate 	return (0);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate int
log_remove_channel(log_context lc,int category,log_channel chan)5057c478bd9Sstevel@tonic-gate log_remove_channel(log_context lc, int category, log_channel chan) {
5067c478bd9Sstevel@tonic-gate 	log_channel_list lcl, prev_lcl, next_lcl;
5077c478bd9Sstevel@tonic-gate 	int found = 0;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if (lc == NULL || category < 0 || category >= lc->num_categories) {
5107c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5117c478bd9Sstevel@tonic-gate 		return (-1);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	for (prev_lcl = NULL, lcl = lc->categories[category];
5157c478bd9Sstevel@tonic-gate 	     lcl != NULL;
5167c478bd9Sstevel@tonic-gate 	     lcl = next_lcl) {
5177c478bd9Sstevel@tonic-gate 		next_lcl = lcl->next;
5187c478bd9Sstevel@tonic-gate 		if (lcl->channel == chan) {
5197c478bd9Sstevel@tonic-gate 			log_free_channel(chan);
5207c478bd9Sstevel@tonic-gate 			if (prev_lcl != NULL)
5217c478bd9Sstevel@tonic-gate 				prev_lcl->next = next_lcl;
5227c478bd9Sstevel@tonic-gate 			else
5237c478bd9Sstevel@tonic-gate 				lc->categories[category] = next_lcl;
5247c478bd9Sstevel@tonic-gate 			memput(lcl, sizeof (struct log_channel_list));
5257c478bd9Sstevel@tonic-gate 			/*
5267c478bd9Sstevel@tonic-gate 			 * We just set found instead of returning because
5277c478bd9Sstevel@tonic-gate 			 * the channel might be on the list more than once.
5287c478bd9Sstevel@tonic-gate 			 */
5297c478bd9Sstevel@tonic-gate 			found = 1;
5307c478bd9Sstevel@tonic-gate 		} else
5317c478bd9Sstevel@tonic-gate 			prev_lcl = lcl;
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 	if (!found) {
5347c478bd9Sstevel@tonic-gate 		errno = ENOENT;
5357c478bd9Sstevel@tonic-gate 		return (-1);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	return (0);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate int
log_option(log_context lc,int option,int value)5417c478bd9Sstevel@tonic-gate log_option(log_context lc, int option, int value) {
5427c478bd9Sstevel@tonic-gate 	if (lc == NULL) {
5437c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5447c478bd9Sstevel@tonic-gate 		return (-1);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 	switch (option) {
5477c478bd9Sstevel@tonic-gate 	case LOG_OPTION_DEBUG:
5487c478bd9Sstevel@tonic-gate 		if (value)
5497c478bd9Sstevel@tonic-gate 			lc->flags |= option;
5507c478bd9Sstevel@tonic-gate 		else
5517c478bd9Sstevel@tonic-gate 			lc->flags &= ~option;
5527c478bd9Sstevel@tonic-gate 		break;
5537c478bd9Sstevel@tonic-gate 	case LOG_OPTION_LEVEL:
5547c478bd9Sstevel@tonic-gate 		lc->level = value;
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 	default:
5577c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5587c478bd9Sstevel@tonic-gate 		return (-1);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 	return (0);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate int
log_category_is_active(log_context lc,int category)5647c478bd9Sstevel@tonic-gate log_category_is_active(log_context lc, int category) {
5657c478bd9Sstevel@tonic-gate 	if (lc == NULL) {
5667c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5677c478bd9Sstevel@tonic-gate 		return (-1);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	if (category >= 0 && category < lc->num_categories &&
5707c478bd9Sstevel@tonic-gate 	    lc->categories[category] != NULL)
5717c478bd9Sstevel@tonic-gate 		return (1);
5727c478bd9Sstevel@tonic-gate 	return (0);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate log_channel
log_new_syslog_channel(unsigned int flags,int level,int facility)5767c478bd9Sstevel@tonic-gate log_new_syslog_channel(unsigned int flags, int level, int facility) {
5777c478bd9Sstevel@tonic-gate 	log_channel chan;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	chan = memget(sizeof (struct log_channel));
5807c478bd9Sstevel@tonic-gate 	if (chan == NULL) {
5817c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
5827c478bd9Sstevel@tonic-gate 		return (NULL);
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	chan->type = log_syslog;
5857c478bd9Sstevel@tonic-gate 	chan->flags = flags;
5867c478bd9Sstevel@tonic-gate 	chan->level = level;
5877c478bd9Sstevel@tonic-gate 	chan->out.facility = facility;
5887c478bd9Sstevel@tonic-gate 	chan->references = 0;
5897c478bd9Sstevel@tonic-gate 	return (chan);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate log_channel
log_new_file_channel(unsigned int flags,int level,const char * name,FILE * stream,unsigned int versions,unsigned long max_size)5937c478bd9Sstevel@tonic-gate log_new_file_channel(unsigned int flags, int level,
5947c478bd9Sstevel@tonic-gate 		     const char *name, FILE *stream, unsigned int versions,
5957c478bd9Sstevel@tonic-gate 		     unsigned long max_size) {
5967c478bd9Sstevel@tonic-gate 	log_channel chan;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	chan = memget(sizeof (struct log_channel));
5997c478bd9Sstevel@tonic-gate 	if (chan == NULL) {
6007c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6017c478bd9Sstevel@tonic-gate 		return (NULL);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 	chan->type = log_file;
6047c478bd9Sstevel@tonic-gate 	chan->flags = flags;
6057c478bd9Sstevel@tonic-gate 	chan->level = level;
6067c478bd9Sstevel@tonic-gate 	if (name != NULL) {
6077c478bd9Sstevel@tonic-gate 		size_t len;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		len = strlen(name);
6107c478bd9Sstevel@tonic-gate 		/*
6117c478bd9Sstevel@tonic-gate 		 * Quantize length to a multiple of 256.  There's space for the
6127c478bd9Sstevel@tonic-gate 		 * NUL, since if len is a multiple of 256, the size chosen will
6137c478bd9Sstevel@tonic-gate 		 * be the next multiple.
6147c478bd9Sstevel@tonic-gate 		 */
6157c478bd9Sstevel@tonic-gate 		chan->out.file.name_size = ((len / 256) + 1) * 256;
6167c478bd9Sstevel@tonic-gate 		chan->out.file.name = memget(chan->out.file.name_size);
6177c478bd9Sstevel@tonic-gate 		if (chan->out.file.name == NULL) {
6187c478bd9Sstevel@tonic-gate 			memput(chan, sizeof (struct log_channel));
6197c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
6207c478bd9Sstevel@tonic-gate 			return (NULL);
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 		/* This is safe. */
6237c478bd9Sstevel@tonic-gate 		strcpy(chan->out.file.name, name);
6247c478bd9Sstevel@tonic-gate 	} else {
6257c478bd9Sstevel@tonic-gate 		chan->out.file.name_size = 0;
6267c478bd9Sstevel@tonic-gate 		chan->out.file.name = NULL;
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	chan->out.file.stream = stream;
6297c478bd9Sstevel@tonic-gate 	chan->out.file.versions = versions;
6307c478bd9Sstevel@tonic-gate 	chan->out.file.max_size = max_size;
6317c478bd9Sstevel@tonic-gate 	chan->out.file.owner = getuid();
6327c478bd9Sstevel@tonic-gate 	chan->out.file.group = getgid();
6337c478bd9Sstevel@tonic-gate 	chan->references = 0;
6347c478bd9Sstevel@tonic-gate 	return (chan);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate int
log_set_file_owner(log_channel chan,uid_t owner,gid_t group)6387c478bd9Sstevel@tonic-gate log_set_file_owner(log_channel chan, uid_t owner, gid_t group) {
6397c478bd9Sstevel@tonic-gate 	if (chan->type != log_file) {
6407c478bd9Sstevel@tonic-gate 		errno = EBADF;
6417c478bd9Sstevel@tonic-gate 		return (-1);
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 	chan->out.file.owner = owner;
6447c478bd9Sstevel@tonic-gate 	chan->out.file.group = group;
6457c478bd9Sstevel@tonic-gate 	return (0);
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate log_channel
log_new_null_channel()6497c478bd9Sstevel@tonic-gate log_new_null_channel() {
6507c478bd9Sstevel@tonic-gate 	log_channel chan;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	chan = memget(sizeof (struct log_channel));
6537c478bd9Sstevel@tonic-gate 	if (chan == NULL) {
6547c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6557c478bd9Sstevel@tonic-gate 		return (NULL);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 	chan->type = log_null;
6587c478bd9Sstevel@tonic-gate 	chan->flags = LOG_CHANNEL_OFF;
6597c478bd9Sstevel@tonic-gate 	chan->level = log_info;
6607c478bd9Sstevel@tonic-gate 	chan->references = 0;
6617c478bd9Sstevel@tonic-gate 	return (chan);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate int
log_inc_references(log_channel chan)6657c478bd9Sstevel@tonic-gate log_inc_references(log_channel chan) {
6667c478bd9Sstevel@tonic-gate 	if (chan == NULL) {
6677c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6687c478bd9Sstevel@tonic-gate 		return (-1);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 	chan->references++;
6717c478bd9Sstevel@tonic-gate 	return (0);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate int
log_dec_references(log_channel chan)6757c478bd9Sstevel@tonic-gate log_dec_references(log_channel chan) {
6767c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->references <= 0) {
6777c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6787c478bd9Sstevel@tonic-gate 		return (-1);
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 	chan->references--;
6817c478bd9Sstevel@tonic-gate 	return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate log_channel_type
log_get_channel_type(log_channel chan)6857c478bd9Sstevel@tonic-gate log_get_channel_type(log_channel chan) {
6867c478bd9Sstevel@tonic-gate 	REQUIRE(chan != NULL);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	return (chan->type);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate int
log_free_channel(log_channel chan)6927c478bd9Sstevel@tonic-gate log_free_channel(log_channel chan) {
6937c478bd9Sstevel@tonic-gate 	if (chan == NULL || chan->references <= 0) {
6947c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6957c478bd9Sstevel@tonic-gate 		return (-1);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 	chan->references--;
6987c478bd9Sstevel@tonic-gate 	if (chan->references == 0) {
6997c478bd9Sstevel@tonic-gate 		if (chan->type == log_file) {
7007c478bd9Sstevel@tonic-gate 			if ((chan->flags & LOG_CLOSE_STREAM) &&
7017c478bd9Sstevel@tonic-gate 			    chan->out.file.stream != NULL)
7027c478bd9Sstevel@tonic-gate 				(void)fclose(chan->out.file.stream);
7037c478bd9Sstevel@tonic-gate 			if (chan->out.file.name != NULL)
7047c478bd9Sstevel@tonic-gate 				memput(chan->out.file.name,
7057c478bd9Sstevel@tonic-gate 				       chan->out.file.name_size);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		memput(chan, sizeof (struct log_channel));
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	return (0);
7107c478bd9Sstevel@tonic-gate }
711*9525b14bSRao Shoaib 
712*9525b14bSRao Shoaib /*! \file */
713