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