xref: /illumos-gate/usr/src/cmd/svc/startd/log.c (revision 57b10af7)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
599b44c3bSlianep  * Common Development and Distribution License (the "License").
699b44c3bSlianep  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22fbe4944aSPetr Sumbera  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*57b10af7SShampavman  * Copyright 2011 Nexenta Systems. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * log.c - debugging and logging functions
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * Logging destinations
317c478bd9Sstevel@tonic-gate  *   svc.startd(1M) supports three logging destinations:  the system log, a
327c478bd9Sstevel@tonic-gate  *   daemon-specific log (in the /var/svc/log hierarchy by default), and to the
3399b44c3bSlianep  *   standard output (redirected to the /var/svc/log/svc.startd.log file by
3499b44c3bSlianep  *   default).  Any or all of these destinations may be used to
357c478bd9Sstevel@tonic-gate  *   communicate a specific message; the audiences for each destination differ.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  *   Generic messages associated with svc.startd(1M) are made by the
387c478bd9Sstevel@tonic-gate  *   log_framework() and log_error() functions.  For these messages, svc.startd
397c478bd9Sstevel@tonic-gate  *   logs under its own name and under the LOG_DAEMON facility when issuing
407c478bd9Sstevel@tonic-gate  *   events to the system log.  By design, severities below LOG_NOTICE are never
417c478bd9Sstevel@tonic-gate  *   issued to the system log.
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  *   Messages associated with a specific service instance are logged using the
447c478bd9Sstevel@tonic-gate  *   log_instance() or log_instance_fmri() functions.  These messages are always
457c478bd9Sstevel@tonic-gate  *   sent to the appropriate per-instance log file.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *   In the case of verbose or debug boot, the log_transition() function
487c478bd9Sstevel@tonic-gate  *   displays messages regarding instance transitions to the system console,
497c478bd9Sstevel@tonic-gate  *   until the expected login services are available.
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  *   Finally, log_console() displays messages to the system consoles and
527c478bd9Sstevel@tonic-gate  *   the master restarter log file.  This is used when booting to a milestone
537c478bd9Sstevel@tonic-gate  *   other than 'all'.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * Logging detail
567c478bd9Sstevel@tonic-gate  *   The constants for severity from <syslog.h> are reused, with a specific
577c478bd9Sstevel@tonic-gate  *   convention here.  (It is worth noting that the #define values for the LOG_
587c478bd9Sstevel@tonic-gate  *   levels are such that more important severities have lower values.)  The
597c478bd9Sstevel@tonic-gate  *   severity determines the importance of the event, and its addressibility by
607c478bd9Sstevel@tonic-gate  *   the administrator.  Each severity level's use is defined below, along with
617c478bd9Sstevel@tonic-gate  *   an illustrative example.
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  *   LOG_EMERG		Not used presently.
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  *   LOG_ALERT		An unrecoverable operation requiring external
667c478bd9Sstevel@tonic-gate  *			intervention has occurred.   Includes an inability to
677c478bd9Sstevel@tonic-gate  *			write to the smf(5) repository (due to svc.configd(1M)
687c478bd9Sstevel@tonic-gate  *			absence, due to permissions failures, etc.).  Message
697c478bd9Sstevel@tonic-gate  *			should identify component at fault.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  *   LOG_CRIT		An unrecoverable operation internal to svc.startd(1M)
727c478bd9Sstevel@tonic-gate  *			has occurred.  Failure should be recoverable by restart
737c478bd9Sstevel@tonic-gate  *			of svc.startd(1M).
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  *   LOG_ERR		An smf(5) event requiring administrative intervention
767c478bd9Sstevel@tonic-gate  *			has occurred.  Includes instance being moved to the
777c478bd9Sstevel@tonic-gate  *			maintenance state.
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  *   LOG_WARNING	A potentially destabilizing smf(5) event not requiring
807c478bd9Sstevel@tonic-gate  *			administrative intervention has occurred.
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  *   LOG_NOTICE		A noteworthy smf(5) event has occurred.  Includes
837c478bd9Sstevel@tonic-gate  *			individual instance failures.
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  *   LOG_INFO		A noteworthy operation internal to svc.startd(1M) has
867c478bd9Sstevel@tonic-gate  *			occurred.  Includes recoverable failures or otherwise
877c478bd9Sstevel@tonic-gate  *			unexpected outcomes.
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  *   LOG_DEBUG		An internal operation only of interest to a
907c478bd9Sstevel@tonic-gate  *			svc.startd(1M) developer has occurred.
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  *  Logging configuration
9354d6518cSrm  *    The preferred approach is to set the logging property values
947c478bd9Sstevel@tonic-gate  *    in the options property group of the svc.startd default instance.  The
957c478bd9Sstevel@tonic-gate  *    valid values are "quiet", "verbose", and "debug".  "quiet" is the default;
967c478bd9Sstevel@tonic-gate  *    "verbose" and "debug" allow LOG_INFO and LOG_DEBUG logging requests to
9754d6518cSrm  *    reach the svc.startd.log file, respectively.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #include <sys/stat.h>
1017c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
1027c478bd9Sstevel@tonic-gate #include <sys/time.h>
1037c478bd9Sstevel@tonic-gate #include <sys/types.h>
1047c478bd9Sstevel@tonic-gate #include <assert.h>
1057c478bd9Sstevel@tonic-gate #include <errno.h>
1067c478bd9Sstevel@tonic-gate #include <fcntl.h>
1077c478bd9Sstevel@tonic-gate #include <kstat.h>
1087c478bd9Sstevel@tonic-gate #include <libgen.h>
1097c478bd9Sstevel@tonic-gate #include <libintl.h>
1107c478bd9Sstevel@tonic-gate #include <libuutil.h>
1117c478bd9Sstevel@tonic-gate #include <locale.h>
1127c478bd9Sstevel@tonic-gate #include <malloc.h>
1137c478bd9Sstevel@tonic-gate #include <pthread.h>
1147c478bd9Sstevel@tonic-gate #include <stdarg.h>
1157c478bd9Sstevel@tonic-gate #include <stdio.h>
1167c478bd9Sstevel@tonic-gate #include <strings.h>
1177c478bd9Sstevel@tonic-gate #include <syslog.h>
1187c478bd9Sstevel@tonic-gate #include <unistd.h>
1197c478bd9Sstevel@tonic-gate #include <zone.h>
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #include "startd.h"
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #define	LOGBUF_SZ	(60 * 80)			/* 60 lines */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static FILE *logfile = NULL;
1277c478bd9Sstevel@tonic-gate 
1283efb42ecSrm /*
1293efb42ecSrm  * This parameter can be modified using mdb to turn on & off extended
1303efb42ecSrm  * internal debug logging. Although a performance loss can be expected.
1313efb42ecSrm  */
1323efb42ecSrm static int internal_debug_flags = 0x0;
1333efb42ecSrm 
1347c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate  * This is a circular buffer for all (even those not emitted externally)
1377c478bd9Sstevel@tonic-gate  * logging messages.  To read it properly you should start after the first
1387c478bd9Sstevel@tonic-gate  * null, go until the second, and then go back to the beginning until the
1397c478bd9Sstevel@tonic-gate  * first null.  Or use ::startd_log in mdb.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate static char logbuf[LOGBUF_SZ] = "";
1427c478bd9Sstevel@tonic-gate static pthread_mutex_t logbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
1437c478bd9Sstevel@tonic-gate #endif
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate static void
xstrftime_poststart(char * buf,size_t bufsize,struct timeval * time)1467c478bd9Sstevel@tonic-gate xstrftime_poststart(char *buf, size_t bufsize, struct timeval *time)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	long sec, usec;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	sec = time->tv_sec - st->st_start_time.tv_sec;
1517c478bd9Sstevel@tonic-gate 	usec = time->tv_usec - st->st_start_time.tv_usec;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (usec < 0) {
1547c478bd9Sstevel@tonic-gate 		sec -= 1;
1557c478bd9Sstevel@tonic-gate 		usec += 1000000;
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, bufsize, "start + %d.%02ds", sec, usec / 10000);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static void
vlog_prefix(int severity,const char * prefix,const char * format,va_list args)1627c478bd9Sstevel@tonic-gate vlog_prefix(int severity, const char *prefix, const char *format, va_list args)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	char buf[512], *cp;
1657c478bd9Sstevel@tonic-gate 	char timebuf[LOG_DATE_SIZE];
1667c478bd9Sstevel@tonic-gate 	struct timeval now;
1677c478bd9Sstevel@tonic-gate 	struct tm ltime;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate #ifdef NDEBUG
1707c478bd9Sstevel@tonic-gate 	if (severity > st->st_log_level_min)
1717c478bd9Sstevel@tonic-gate 		return;
1727c478bd9Sstevel@tonic-gate #endif
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) != 0)
1757c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "gettimeofday(3C) failed: %s\n",
1767c478bd9Sstevel@tonic-gate 		    strerror(errno));
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (st->st_log_timezone_known)
1797c478bd9Sstevel@tonic-gate 		(void) strftime(timebuf, sizeof (timebuf), "%b %e %T",
1807c478bd9Sstevel@tonic-gate 		    localtime_r(&now.tv_sec, &ltime));
1817c478bd9Sstevel@tonic-gate 	else
1827c478bd9Sstevel@tonic-gate 		xstrftime_poststart(timebuf, sizeof (timebuf), &now);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s/%d%s: ", timebuf, pthread_self(),
1857c478bd9Sstevel@tonic-gate 	    prefix);
1867c478bd9Sstevel@tonic-gate 	cp = strchr(buf, '\0');
1877c478bd9Sstevel@tonic-gate 	(void) vsnprintf(cp, sizeof (buf) - (cp - buf), format, args);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1907c478bd9Sstevel@tonic-gate 	/* Copy into logbuf. */
1917c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&logbuf_mutex);
1927c478bd9Sstevel@tonic-gate 	if (strlen(logbuf) + strlen(buf) + 1 <= sizeof (logbuf))
1937c478bd9Sstevel@tonic-gate 		(void) strcat(logbuf, buf);
1947c478bd9Sstevel@tonic-gate 	else
1957c478bd9Sstevel@tonic-gate 		(void) strlcpy(logbuf, buf, sizeof (logbuf));
1967c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&logbuf_mutex);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (severity > st->st_log_level_min)
1997c478bd9Sstevel@tonic-gate 		return;
2007c478bd9Sstevel@tonic-gate #endif
2017c478bd9Sstevel@tonic-gate 
20299b44c3bSlianep 	if (st->st_log_flags & STARTD_LOG_FILE && logfile) {
2037c478bd9Sstevel@tonic-gate 		(void) fputs(buf, logfile);
20499b44c3bSlianep 		(void) fflush(logfile);
20599b44c3bSlianep 	}
2067c478bd9Sstevel@tonic-gate 	if (st->st_log_flags & STARTD_LOG_TERMINAL)
2077c478bd9Sstevel@tonic-gate 		(void) fputs(buf, stdout);
20899b44c3bSlianep 	if (st->st_log_flags & STARTD_LOG_SYSLOG && st->st_log_timezone_known)
2097c478bd9Sstevel@tonic-gate 		vsyslog(severity, format, args);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2137c478bd9Sstevel@tonic-gate void
log_error(int severity,const char * format,...)2147c478bd9Sstevel@tonic-gate log_error(int severity, const char *format, ...)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	va_list args;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	va_start(args, format);
2197c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, " ERROR", format, args);
2207c478bd9Sstevel@tonic-gate 	va_end(args);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2247c478bd9Sstevel@tonic-gate void
log_framework(int severity,const char * format,...)2257c478bd9Sstevel@tonic-gate log_framework(int severity, const char *format, ...)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	va_list args;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	va_start(args, format);
2307c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, "", format, args);
2317c478bd9Sstevel@tonic-gate 	va_end(args);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2343efb42ecSrm /*
2353efb42ecSrm  * log_framework2() differs from log_framework() by the fact that
2363efb42ecSrm  * some checking are done before logging the messages in the internal
2373efb42ecSrm  * buffer for performance reasons.
2383efb42ecSrm  * The messages aren't logged if:
2393efb42ecSrm  * - severity >= LOG_DEBUG and
2403efb42ecSrm  * - st_log_level_min < LOG_DEBUG and
2413efb42ecSrm  * - internal_debug_flags is not set for 'flags'
2423efb42ecSrm  */
2433efb42ecSrm void
log_framework2(int severity,int flags,const char * format,...)2443efb42ecSrm log_framework2(int severity, int flags, const char *format, ...)
2453efb42ecSrm {
2463efb42ecSrm 	va_list args;
2473efb42ecSrm 
2483efb42ecSrm 	if ((severity < LOG_DEBUG) ||
2493efb42ecSrm 	    (internal_debug_flags & flags) ||
2503efb42ecSrm 	    st->st_log_level_min >= LOG_DEBUG) {
2513efb42ecSrm 		va_start(args, format);
2523efb42ecSrm 		vlog_prefix(severity, "", format, args);
2533efb42ecSrm 		va_end(args);
2543efb42ecSrm 	}
2553efb42ecSrm }
2563efb42ecSrm 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * void log_preexec()
2597c478bd9Sstevel@tonic-gate  *
2607c478bd9Sstevel@tonic-gate  * log_preexec() should be invoked prior to any exec(2) calls, to prevent the
2617c478bd9Sstevel@tonic-gate  * logfile and syslogd file descriptors from being leaked to child processes.
2627c478bd9Sstevel@tonic-gate  * Why openlog(3C) lacks a close-on-exec option is a minor mystery.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate void
log_preexec()2657c478bd9Sstevel@tonic-gate log_preexec()
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	closelog();
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate  * void setlog()
2727c478bd9Sstevel@tonic-gate  *   Close file descriptors and redirect output.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate void
setlog(const char * logstem)2757c478bd9Sstevel@tonic-gate setlog(const char *logstem)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	int fd;
2787c478bd9Sstevel@tonic-gate 	char logfile[PATH_MAX];
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	closefrom(0);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	(void) open("/dev/null", O_RDONLY);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	(void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix, logstem);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
2877c478bd9Sstevel@tonic-gate 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,
2887c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
2897c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (fd == -1)
2927c478bd9Sstevel@tonic-gate 		return;
2937c478bd9Sstevel@tonic-gate 
2942f1b831aSacruz 	(void) dup2(fd, STDOUT_FILENO);
2952f1b831aSacruz 	(void) dup2(fd, STDERR_FILENO);
2967c478bd9Sstevel@tonic-gate 
2972f1b831aSacruz 	if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
2987c478bd9Sstevel@tonic-gate 		startd_close(fd);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate static int
log_dir_writeable(const char * path)3027c478bd9Sstevel@tonic-gate log_dir_writeable(const char *path)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	int fd;
3057c478bd9Sstevel@tonic-gate 	struct statvfs svb;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if ((fd = open(path, O_RDONLY, 0644)) == -1)
3087c478bd9Sstevel@tonic-gate 		return (-1);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if (fstatvfs(fd, &svb) == -1)
3117c478bd9Sstevel@tonic-gate 		return (-1);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (svb.f_flag & ST_RDONLY) {
3147c478bd9Sstevel@tonic-gate 		(void) close(fd);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 		fd = -1;
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	return (fd);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate static void
vlog_instance(const char * fmri,const char * logstem,boolean_t canlog,const char * format,va_list args)3237c478bd9Sstevel@tonic-gate vlog_instance(const char *fmri, const char *logstem, boolean_t canlog,
3247c478bd9Sstevel@tonic-gate     const char *format, va_list args)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	char logfile[PATH_MAX];
3277c478bd9Sstevel@tonic-gate 	char *message;
3287c478bd9Sstevel@tonic-gate 	char omessage[1024];
3297c478bd9Sstevel@tonic-gate 	int fd, err;
3307c478bd9Sstevel@tonic-gate 	char timebuf[LOG_DATE_SIZE];
3317c478bd9Sstevel@tonic-gate 	struct tm ltime;
3327c478bd9Sstevel@tonic-gate 	struct timeval now;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	(void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix,
3357c478bd9Sstevel@tonic-gate 	    logstem);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
3387c478bd9Sstevel@tonic-gate 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,
3397c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
3407c478bd9Sstevel@tonic-gate 	err = errno;
3417c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3447c478bd9Sstevel@tonic-gate 		if (canlog)
3457c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: open(%s) "
3467c478bd9Sstevel@tonic-gate 			    "failed with %s.\n", fmri, logfile, strerror(err));
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 		return;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	(void) vsnprintf(omessage, sizeof (omessage), format, args);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) != 0)
3547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "gettimeofday(3C) failed: %s\n",
3557c478bd9Sstevel@tonic-gate 		    strerror(errno));
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	if (st->st_log_timezone_known)
3587c478bd9Sstevel@tonic-gate 		(void) strftime(timebuf, sizeof (timebuf), "%b %e %T",
3597c478bd9Sstevel@tonic-gate 		    localtime_r(&now.tv_sec, &ltime));
3607c478bd9Sstevel@tonic-gate 	else
3617c478bd9Sstevel@tonic-gate 		xstrftime_poststart(timebuf, sizeof (timebuf), &now);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	message = uu_msprintf("[ %s %s ]\n", timebuf, omessage);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (message == NULL) {
3667c478bd9Sstevel@tonic-gate 		if (canlog)
3677c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: %s.\n",
3687c478bd9Sstevel@tonic-gate 			    fmri, uu_strerror(uu_error()));
3697c478bd9Sstevel@tonic-gate 	} else {
3707c478bd9Sstevel@tonic-gate 		if (write(fd, message, strlen(message)) < 0 && canlog)
3717c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: write(%d) "
3727c478bd9Sstevel@tonic-gate 			    "failed with %s.\n", fmri, fd,
3737c478bd9Sstevel@tonic-gate 			    strerror(errno));
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 		uu_free(message);
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	if (close(fd) != 0 && canlog)
3797c478bd9Sstevel@tonic-gate 		log_framework(LOG_NOTICE, "close(%d) failed: %s.\n", fd,
3807c478bd9Sstevel@tonic-gate 		    strerror(errno));
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * void log_instance(const restarter_inst_t *, boolean_t, const char *, ...)
3857c478bd9Sstevel@tonic-gate  *
3867c478bd9Sstevel@tonic-gate  * The log_instance() format is "[ month day time message ]".  (The
3877c478bd9Sstevel@tonic-gate  * brackets distinguish svc.startd messages from method output.)  We avoid
3887c478bd9Sstevel@tonic-gate  * calling log_*() functions on error when canlog is not set, since we may
3897c478bd9Sstevel@tonic-gate  * be called from a child process.
3907c478bd9Sstevel@tonic-gate  *
3917c478bd9Sstevel@tonic-gate  * When adding new calls to this function, consider: If this is called before
3927c478bd9Sstevel@tonic-gate  * any instances have started, then it should be called with canlog clear,
3937c478bd9Sstevel@tonic-gate  * lest we spew errors to the console when booted on the miniroot.
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
3967c478bd9Sstevel@tonic-gate void
log_instance(const restarter_inst_t * inst,boolean_t canlog,const char * format,...)3977c478bd9Sstevel@tonic-gate log_instance(const restarter_inst_t *inst, boolean_t canlog,
3987c478bd9Sstevel@tonic-gate     const char *format, ...)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	va_list args;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	va_start(args, format);
4037c478bd9Sstevel@tonic-gate 	vlog_instance(inst->ri_i.i_fmri, inst->ri_logstem, canlog, format,
4047c478bd9Sstevel@tonic-gate 	    args);
4057c478bd9Sstevel@tonic-gate 	va_end(args);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * void log_instance_fmri(const char *, const char *,boolean_t, const char *,
4107c478bd9Sstevel@tonic-gate  *    ...)
4117c478bd9Sstevel@tonic-gate  *
4127c478bd9Sstevel@tonic-gate  * The log_instance_fmri() format is "[ month day time message ]".  (The
4137c478bd9Sstevel@tonic-gate  * brackets distinguish svc.startd messages from method output.)  We avoid
4147c478bd9Sstevel@tonic-gate  * calling log_*() functions on error when canlog is not set, since we may
4157c478bd9Sstevel@tonic-gate  * be called from a child process.
4167c478bd9Sstevel@tonic-gate  *
4177c478bd9Sstevel@tonic-gate  * For new calls to this function, see the warning in log_instance()'s
4187c478bd9Sstevel@tonic-gate  * comment.
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
4217c478bd9Sstevel@tonic-gate void
log_instance_fmri(const char * fmri,const char * logstem,boolean_t canlog,const char * format,...)4227c478bd9Sstevel@tonic-gate log_instance_fmri(const char *fmri, const char *logstem, boolean_t canlog,
4237c478bd9Sstevel@tonic-gate     const char *format, ...)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	va_list args;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	va_start(args, format);
4287c478bd9Sstevel@tonic-gate 	vlog_instance(fmri, logstem, canlog, format, args);
4297c478bd9Sstevel@tonic-gate 	va_end(args);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate  * void log_transition(const restarter_inst_t *, start_outcome_t)
4347c478bd9Sstevel@tonic-gate  *
4357c478bd9Sstevel@tonic-gate  * The log_transition() format is
4367c478bd9Sstevel@tonic-gate  *
4377c478bd9Sstevel@tonic-gate  *   [ _service_fmri_ _participle_ (_common_name_) ]
4387c478bd9Sstevel@tonic-gate  *
4397c478bd9Sstevel@tonic-gate  * Again, brackets separate messages from specific service instance output to
4407c478bd9Sstevel@tonic-gate  * the console.
4417c478bd9Sstevel@tonic-gate  */
4427c478bd9Sstevel@tonic-gate void
log_transition(const restarter_inst_t * inst,start_outcome_t outcome)4437c478bd9Sstevel@tonic-gate log_transition(const restarter_inst_t *inst, start_outcome_t outcome)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	char *message;
4467c478bd9Sstevel@tonic-gate 	char omessage[1024];
4477c478bd9Sstevel@tonic-gate 	char *action;
4487c478bd9Sstevel@tonic-gate 	int severity;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if (outcome == START_REQUESTED) {
4517c478bd9Sstevel@tonic-gate 		char *cname = NULL;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		cname = inst->ri_common_name;
4547c478bd9Sstevel@tonic-gate 		if (cname == NULL)
4557c478bd9Sstevel@tonic-gate 			cname = inst->ri_C_common_name;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		if (!(st->st_boot_flags & STARTD_BOOT_VERBOSE))
4587c478bd9Sstevel@tonic-gate 			return;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		if (inst->ri_start_index > 1)
4617c478bd9Sstevel@tonic-gate 			return;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 		if (cname)
4647c478bd9Sstevel@tonic-gate 			(void) snprintf(omessage, sizeof (omessage), " (%s)",
4652f1b831aSacruz 			    cname);
4667c478bd9Sstevel@tonic-gate 		else
4677c478bd9Sstevel@tonic-gate 			*omessage = '\0';
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		action = gettext("starting");
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		message = uu_msprintf("[ %s %s%s ]\n",
4727c478bd9Sstevel@tonic-gate 		    inst->ri_i.i_fmri + strlen("svc:/"), action,
4737c478bd9Sstevel@tonic-gate 		    omessage);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		severity = LOG_INFO;
4767c478bd9Sstevel@tonic-gate 	} else {
4777c478bd9Sstevel@tonic-gate 		switch (outcome) {
47899b44c3bSlianep 		case MAINT_REQUESTED:
47999b44c3bSlianep 			action = gettext("transitioned to maintenance by "
48099b44c3bSlianep 			    "request (see 'svcs -xv' for details)");
48199b44c3bSlianep 			break;
4827c478bd9Sstevel@tonic-gate 		case START_FAILED_REPEATEDLY:
48399b44c3bSlianep 			action = gettext("failed repeatedly: transitioned to "
48499b44c3bSlianep 			    "maintenance (see 'svcs -xv' for details)");
4857c478bd9Sstevel@tonic-gate 			break;
4867c478bd9Sstevel@tonic-gate 		case START_FAILED_CONFIGURATION:
48799b44c3bSlianep 			action = gettext("misconfigured: transitioned to "
48899b44c3bSlianep 			    "maintenance (see 'svcs -xv' for details)");
4897c478bd9Sstevel@tonic-gate 			break;
4907c478bd9Sstevel@tonic-gate 		case START_FAILED_FATAL:
49199b44c3bSlianep 			action = gettext("failed fatally: transitioned to "
49299b44c3bSlianep 			    "maintenance (see 'svcs -xv' for details)");
4937c478bd9Sstevel@tonic-gate 			break;
4947c478bd9Sstevel@tonic-gate 		case START_FAILED_TIMEOUT_FATAL:
49599b44c3bSlianep 			action = gettext("timed out: transitioned to "
49699b44c3bSlianep 			    "maintenance (see 'svcs -xv' for details)");
4977c478bd9Sstevel@tonic-gate 			break;
4987c478bd9Sstevel@tonic-gate 		case START_FAILED_OTHER:
49999b44c3bSlianep 			action = gettext("failed: transitioned to "
50099b44c3bSlianep 			    "maintenance (see 'svcs -xv' for details)");
5017c478bd9Sstevel@tonic-gate 			break;
5027c478bd9Sstevel@tonic-gate 		case START_REQUESTED:
5037c478bd9Sstevel@tonic-gate 			assert(outcome != START_REQUESTED);
5047c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
5057c478bd9Sstevel@tonic-gate 		default:
5067c478bd9Sstevel@tonic-gate 			action = gettext("outcome unknown?");
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 
50999b44c3bSlianep 		message = uu_msprintf("[ %s %s ]\n",
51099b44c3bSlianep 		    inst->ri_i.i_fmri + strlen("svc:/"), action);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		severity = LOG_ERR;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	if (message == NULL) {
5177c478bd9Sstevel@tonic-gate 		log_error(LOG_NOTICE,
5187c478bd9Sstevel@tonic-gate 		    "Could not log boot message for %s: %s.\n",
5197c478bd9Sstevel@tonic-gate 		    inst->ri_i.i_fmri, uu_strerror(uu_error()));
5207c478bd9Sstevel@tonic-gate 	} else {
52199b44c3bSlianep 		/*
52299b44c3bSlianep 		 * All significant errors should to go to syslog to
52399b44c3bSlianep 		 * communicate appropriate information even for systems
52499b44c3bSlianep 		 * without a console connected during boot.  Send the
52599b44c3bSlianep 		 * message to stderr only if the severity is lower than
52699b44c3bSlianep 		 * (indicated by >) LOG_ERR.
52799b44c3bSlianep 		 */
52899b44c3bSlianep 		if (!st->st_log_login_reached && severity > LOG_ERR) {
5297c478bd9Sstevel@tonic-gate 			/*LINTED*/
5307c478bd9Sstevel@tonic-gate 			if (fprintf(stderr, message) < 0)
5317c478bd9Sstevel@tonic-gate 				log_error(LOG_NOTICE, "Could not log for %s: "
5327c478bd9Sstevel@tonic-gate 				    "fprintf() failed with %s.\n",
5337c478bd9Sstevel@tonic-gate 				    inst->ri_i.i_fmri, strerror(errno));
5347c478bd9Sstevel@tonic-gate 		} else {
5357c478bd9Sstevel@tonic-gate 			log_framework(severity, "%s %s\n",
5367c478bd9Sstevel@tonic-gate 			    inst->ri_i.i_fmri + strlen("svc:/"), action);
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		uu_free(message);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate  * log_console - log a message to the consoles and to syslog
5457c478bd9Sstevel@tonic-gate  *
5467c478bd9Sstevel@tonic-gate  * This logs a message as-is to the console (and auxiliary consoles),
5477c478bd9Sstevel@tonic-gate  * as well as to the master restarter log.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
5507c478bd9Sstevel@tonic-gate void
log_console(int severity,const char * format,...)5517c478bd9Sstevel@tonic-gate log_console(int severity, const char *format, ...)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	va_list args;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	va_start(args, format);
5567c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, "", format, args);
5577c478bd9Sstevel@tonic-gate 	va_end(args);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	va_start(args, format);
5607c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, format, args);
5617c478bd9Sstevel@tonic-gate 	va_end(args);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate  * void log_init()
5667c478bd9Sstevel@tonic-gate  *
5677c478bd9Sstevel@tonic-gate  * Set up the log files, if necessary, for the current invocation.  This
5687c478bd9Sstevel@tonic-gate  * function should be called before any other functions in this file.  Set the
5697c478bd9Sstevel@tonic-gate  * syslog(3C) logging mask such that severities of the importance of
5707c478bd9Sstevel@tonic-gate  * LOG_NOTICE and above are passed through, but lower severity messages are
5717c478bd9Sstevel@tonic-gate  * masked out.
5727c478bd9Sstevel@tonic-gate  *
5737c478bd9Sstevel@tonic-gate  * It may be called multiple times to change the logging configuration due to
5747c478bd9Sstevel@tonic-gate  * administrative request.
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate void
log_init()5777c478bd9Sstevel@tonic-gate log_init()
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	int dirfd, logfd;
5807c478bd9Sstevel@tonic-gate 	char *dir;
5817c478bd9Sstevel@tonic-gate 	struct stat sb;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (st->st_start_time.tv_sec == 0) {
5847c478bd9Sstevel@tonic-gate 		if (getzoneid() != GLOBAL_ZONEID) {
5857c478bd9Sstevel@tonic-gate 			st->st_start_time.tv_sec = time(NULL);
5867c478bd9Sstevel@tonic-gate 		} else {
5877c478bd9Sstevel@tonic-gate 			/*
5887c478bd9Sstevel@tonic-gate 			 * We need to special-case the BOOT_TIME utmp entry, and
5897c478bd9Sstevel@tonic-gate 			 * drag that value out of the kernel if it's there.
5907c478bd9Sstevel@tonic-gate 			 */
5917c478bd9Sstevel@tonic-gate 			kstat_ctl_t *kc;
5927c478bd9Sstevel@tonic-gate 			kstat_t *ks;
5937c478bd9Sstevel@tonic-gate 			kstat_named_t *boot;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 			if (((kc = kstat_open()) != 0) &&
5967c478bd9Sstevel@tonic-gate 			    ((ks = kstat_lookup(kc, "unix", 0, "system_misc"))
5977c478bd9Sstevel@tonic-gate 			    != NULL) &&
5987c478bd9Sstevel@tonic-gate 			    (kstat_read(kc, ks, NULL) != -1) &&
5997c478bd9Sstevel@tonic-gate 			    ((boot = kstat_data_lookup(ks, "boot_time")) !=
6007c478bd9Sstevel@tonic-gate 			    NULL)) {
6017c478bd9Sstevel@tonic-gate 				/*
6027c478bd9Sstevel@tonic-gate 				 * If we're here, then we've successfully found
6037c478bd9Sstevel@tonic-gate 				 * the boot_time kstat... use its value.
6047c478bd9Sstevel@tonic-gate 				 */
6057c478bd9Sstevel@tonic-gate 				st->st_start_time.tv_sec = boot->value.ul;
6067c478bd9Sstevel@tonic-gate 			} else {
6077c478bd9Sstevel@tonic-gate 				st->st_start_time.tv_sec = time(NULL);
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 			if (kc)
6117c478bd9Sstevel@tonic-gate 				(void) kstat_close(kc);
6127c478bd9Sstevel@tonic-gate 		}
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	/*
6167c478bd9Sstevel@tonic-gate 	 * Establish our timezone if the appropriate directory is available.
6177c478bd9Sstevel@tonic-gate 	 */
6187c478bd9Sstevel@tonic-gate 	if (!st->st_log_timezone_known && stat(FS_TIMEZONE_DIR, &sb) == 0) {
6197c478bd9Sstevel@tonic-gate 		tzset();
6207c478bd9Sstevel@tonic-gate 		st->st_log_timezone_known = 1;
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	/*
6247c478bd9Sstevel@tonic-gate 	 * Establish our locale if the appropriate directory is available.  Set
6257c478bd9Sstevel@tonic-gate 	 * the locale string from the environment so we can extract template
6267c478bd9Sstevel@tonic-gate 	 * information correctly, if the locale directories aren't yet
6277c478bd9Sstevel@tonic-gate 	 * available.
6287c478bd9Sstevel@tonic-gate 	 */
6297c478bd9Sstevel@tonic-gate 	if (st->st_locale != NULL)
6307c478bd9Sstevel@tonic-gate 		free(st->st_locale);
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if ((st->st_locale = getenv("LC_ALL")) == NULL)
6337c478bd9Sstevel@tonic-gate 		if ((st->st_locale = getenv("LC_MESSAGES")) == NULL)
6347c478bd9Sstevel@tonic-gate 			st->st_locale = getenv("LANG");
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (!st->st_log_locale_known && stat(FS_LOCALE_DIR, &sb) == 0) {
6377c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_ALL, "");
638*57b10af7SShampavman 		st->st_locale = setlocale(LC_MESSAGES, NULL);
6397c478bd9Sstevel@tonic-gate 		if (st->st_locale)
6407c478bd9Sstevel@tonic-gate 			st->st_log_locale_known = 1;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		(void) textdomain(TEXT_DOMAIN);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (st->st_locale) {
6467c478bd9Sstevel@tonic-gate 		st->st_locale = safe_strdup(st->st_locale);
6477c478bd9Sstevel@tonic-gate 		xstr_sanitize(st->st_locale);
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (logfile) {
6517c478bd9Sstevel@tonic-gate 		(void) fclose(logfile);
6527c478bd9Sstevel@tonic-gate 		logfile = NULL;
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * Set syslog(3C) behaviour in all cases.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	closelog();
6597c478bd9Sstevel@tonic-gate 	openlog("svc.startd", LOG_PID | LOG_CONS, LOG_DAEMON);
6607c478bd9Sstevel@tonic-gate 	(void) setlogmask(LOG_UPTO(LOG_NOTICE));
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if ((dirfd = log_dir_writeable(LOG_PREFIX_NORMAL)) == -1) {
6637c478bd9Sstevel@tonic-gate 		if ((dirfd = log_dir_writeable(LOG_PREFIX_EARLY)) == -1)
6647c478bd9Sstevel@tonic-gate 			return;
6657c478bd9Sstevel@tonic-gate 		else
6667c478bd9Sstevel@tonic-gate 			dir = LOG_PREFIX_EARLY;
6677c478bd9Sstevel@tonic-gate 	} else {
6687c478bd9Sstevel@tonic-gate 		dir = LOG_PREFIX_NORMAL;
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	st->st_log_prefix = dir;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
674fbe4944aSPetr Sumbera 	if ((logfd = openat(dirfd, STARTD_DEFAULT_LOG,
675fbe4944aSPetr Sumbera 	    O_CREAT | O_RDWR | O_APPEND, 0644)) == -1) {
6767c478bd9Sstevel@tonic-gate 		(void) close(dirfd);
6777c478bd9Sstevel@tonic-gate 		(void) umask(dmask);
6787c478bd9Sstevel@tonic-gate 		return;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	(void) close(dirfd);
6827c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	if ((logfile = fdopen(logfd, "a")) == NULL)
6857c478bd9Sstevel@tonic-gate 		if (errno != EROFS)
6867c478bd9Sstevel@tonic-gate 			log_error(LOG_WARNING, "can't open logfile %s/%s",
6877c478bd9Sstevel@tonic-gate 			    dir, STARTD_DEFAULT_LOG);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (logfile &&
6907c478bd9Sstevel@tonic-gate 	    fcntl(fileno(logfile), F_SETFD, FD_CLOEXEC) == -1)
6917c478bd9Sstevel@tonic-gate 		log_error(LOG_WARNING,
6927c478bd9Sstevel@tonic-gate 		    "couldn't mark logfile close-on-exec: %s\n",
6937c478bd9Sstevel@tonic-gate 		    strerror(errno));
6947c478bd9Sstevel@tonic-gate }
695