xref: /illumos-gate/usr/src/cmd/svc/startd/log.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * log.c - debugging and logging functions
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Logging destinations
33*7c478bd9Sstevel@tonic-gate  *   svc.startd(1M) supports three logging destinations:  the system log, a
34*7c478bd9Sstevel@tonic-gate  *   daemon-specific log (in the /var/svc/log hierarchy by default), and to the
35*7c478bd9Sstevel@tonic-gate  *   standard output.  Any or all of these destinations may be used to
36*7c478bd9Sstevel@tonic-gate  *   communicate a specific message; the audiences for each destination differ.
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  *   Generic messages associated with svc.startd(1M) are made by the
39*7c478bd9Sstevel@tonic-gate  *   log_framework() and log_error() functions.  For these messages, svc.startd
40*7c478bd9Sstevel@tonic-gate  *   logs under its own name and under the LOG_DAEMON facility when issuing
41*7c478bd9Sstevel@tonic-gate  *   events to the system log.  By design, severities below LOG_NOTICE are never
42*7c478bd9Sstevel@tonic-gate  *   issued to the system log.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  *   Messages associated with a specific service instance are logged using the
45*7c478bd9Sstevel@tonic-gate  *   log_instance() or log_instance_fmri() functions.  These messages are always
46*7c478bd9Sstevel@tonic-gate  *   sent to the appropriate per-instance log file.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  *   In the case of verbose or debug boot, the log_transition() function
49*7c478bd9Sstevel@tonic-gate  *   displays messages regarding instance transitions to the system console,
50*7c478bd9Sstevel@tonic-gate  *   until the expected login services are available.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  *   Finally, log_console() displays messages to the system consoles and
53*7c478bd9Sstevel@tonic-gate  *   the master restarter log file.  This is used when booting to a milestone
54*7c478bd9Sstevel@tonic-gate  *   other than 'all'.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * Logging detail
57*7c478bd9Sstevel@tonic-gate  *   The constants for severity from <syslog.h> are reused, with a specific
58*7c478bd9Sstevel@tonic-gate  *   convention here.  (It is worth noting that the #define values for the LOG_
59*7c478bd9Sstevel@tonic-gate  *   levels are such that more important severities have lower values.)  The
60*7c478bd9Sstevel@tonic-gate  *   severity determines the importance of the event, and its addressibility by
61*7c478bd9Sstevel@tonic-gate  *   the administrator.  Each severity level's use is defined below, along with
62*7c478bd9Sstevel@tonic-gate  *   an illustrative example.
63*7c478bd9Sstevel@tonic-gate  *
64*7c478bd9Sstevel@tonic-gate  *   LOG_EMERG		Not used presently.
65*7c478bd9Sstevel@tonic-gate  *
66*7c478bd9Sstevel@tonic-gate  *   LOG_ALERT		An unrecoverable operation requiring external
67*7c478bd9Sstevel@tonic-gate  *			intervention has occurred.   Includes an inability to
68*7c478bd9Sstevel@tonic-gate  *			write to the smf(5) repository (due to svc.configd(1M)
69*7c478bd9Sstevel@tonic-gate  *			absence, due to permissions failures, etc.).  Message
70*7c478bd9Sstevel@tonic-gate  *			should identify component at fault.
71*7c478bd9Sstevel@tonic-gate  *
72*7c478bd9Sstevel@tonic-gate  *   LOG_CRIT		An unrecoverable operation internal to svc.startd(1M)
73*7c478bd9Sstevel@tonic-gate  *			has occurred.  Failure should be recoverable by restart
74*7c478bd9Sstevel@tonic-gate  *			of svc.startd(1M).
75*7c478bd9Sstevel@tonic-gate  *
76*7c478bd9Sstevel@tonic-gate  *   LOG_ERR		An smf(5) event requiring administrative intervention
77*7c478bd9Sstevel@tonic-gate  *			has occurred.  Includes instance being moved to the
78*7c478bd9Sstevel@tonic-gate  *			maintenance state.
79*7c478bd9Sstevel@tonic-gate  *
80*7c478bd9Sstevel@tonic-gate  *   LOG_WARNING	A potentially destabilizing smf(5) event not requiring
81*7c478bd9Sstevel@tonic-gate  *			administrative intervention has occurred.
82*7c478bd9Sstevel@tonic-gate  *
83*7c478bd9Sstevel@tonic-gate  *   LOG_NOTICE		A noteworthy smf(5) event has occurred.  Includes
84*7c478bd9Sstevel@tonic-gate  *			individual instance failures.
85*7c478bd9Sstevel@tonic-gate  *
86*7c478bd9Sstevel@tonic-gate  *   LOG_INFO		A noteworthy operation internal to svc.startd(1M) has
87*7c478bd9Sstevel@tonic-gate  *			occurred.  Includes recoverable failures or otherwise
88*7c478bd9Sstevel@tonic-gate  *			unexpected outcomes.
89*7c478bd9Sstevel@tonic-gate  *
90*7c478bd9Sstevel@tonic-gate  *   LOG_DEBUG		An internal operation only of interest to a
91*7c478bd9Sstevel@tonic-gate  *			svc.startd(1M) developer has occurred.
92*7c478bd9Sstevel@tonic-gate  *
93*7c478bd9Sstevel@tonic-gate  *  Logging configuration
94*7c478bd9Sstevel@tonic-gate  *    While the logging output can be configured using the -d and -v flags at
95*7c478bd9Sstevel@tonic-gate  *    invocation, the preferred approach is to set the logging property values
96*7c478bd9Sstevel@tonic-gate  *    in the options property group of the svc.startd default instance.  The
97*7c478bd9Sstevel@tonic-gate  *    valid values are "quiet", "verbose", and "debug".  "quiet" is the default;
98*7c478bd9Sstevel@tonic-gate  *    "verbose" and "debug" allow LOG_INFO and LOG_DEBUG logging requests to
99*7c478bd9Sstevel@tonic-gate  *    reach the daemon-specific log, respectively.
100*7c478bd9Sstevel@tonic-gate  */
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
103*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
104*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
105*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
106*7c478bd9Sstevel@tonic-gate #include <assert.h>
107*7c478bd9Sstevel@tonic-gate #include <errno.h>
108*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
109*7c478bd9Sstevel@tonic-gate #include <kstat.h>
110*7c478bd9Sstevel@tonic-gate #include <libgen.h>
111*7c478bd9Sstevel@tonic-gate #include <libintl.h>
112*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
113*7c478bd9Sstevel@tonic-gate #include <locale.h>
114*7c478bd9Sstevel@tonic-gate #include <malloc.h>
115*7c478bd9Sstevel@tonic-gate #include <pthread.h>
116*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
117*7c478bd9Sstevel@tonic-gate #include <stdio.h>
118*7c478bd9Sstevel@tonic-gate #include <strings.h>
119*7c478bd9Sstevel@tonic-gate #include <syslog.h>
120*7c478bd9Sstevel@tonic-gate #include <unistd.h>
121*7c478bd9Sstevel@tonic-gate #include <zone.h>
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate #include "startd.h"
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate #define	LOGBUF_SZ	(60 * 80)			/* 60 lines */
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate static FILE *logfile = NULL;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * This is a circular buffer for all (even those not emitted externally)
133*7c478bd9Sstevel@tonic-gate  * logging messages.  To read it properly you should start after the first
134*7c478bd9Sstevel@tonic-gate  * null, go until the second, and then go back to the beginning until the
135*7c478bd9Sstevel@tonic-gate  * first null.  Or use ::startd_log in mdb.
136*7c478bd9Sstevel@tonic-gate  */
137*7c478bd9Sstevel@tonic-gate /* LINTED unused */
138*7c478bd9Sstevel@tonic-gate static const size_t logbuf_sz = LOGBUF_SZ;		/* For mdb */
139*7c478bd9Sstevel@tonic-gate static char logbuf[LOGBUF_SZ] = "";
140*7c478bd9Sstevel@tonic-gate static pthread_mutex_t logbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
141*7c478bd9Sstevel@tonic-gate #endif
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate static void
144*7c478bd9Sstevel@tonic-gate xstrftime_poststart(char *buf, size_t bufsize, struct timeval *time)
145*7c478bd9Sstevel@tonic-gate {
146*7c478bd9Sstevel@tonic-gate 	long sec, usec;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	sec = time->tv_sec - st->st_start_time.tv_sec;
149*7c478bd9Sstevel@tonic-gate 	usec = time->tv_usec - st->st_start_time.tv_usec;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (usec < 0) {
152*7c478bd9Sstevel@tonic-gate 		sec -= 1;
153*7c478bd9Sstevel@tonic-gate 		usec += 1000000;
154*7c478bd9Sstevel@tonic-gate 	}
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, bufsize, "start + %d.%02ds", sec, usec / 10000);
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static void
160*7c478bd9Sstevel@tonic-gate vlog_prefix(int severity, const char *prefix, const char *format, va_list args)
161*7c478bd9Sstevel@tonic-gate {
162*7c478bd9Sstevel@tonic-gate 	char buf[512], *cp;
163*7c478bd9Sstevel@tonic-gate 	char timebuf[LOG_DATE_SIZE];
164*7c478bd9Sstevel@tonic-gate 	struct timeval now;
165*7c478bd9Sstevel@tonic-gate 	struct tm ltime;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate #ifdef NDEBUG
168*7c478bd9Sstevel@tonic-gate 	if (severity > st->st_log_level_min)
169*7c478bd9Sstevel@tonic-gate 		return;
170*7c478bd9Sstevel@tonic-gate #endif
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) != 0)
173*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "gettimeofday(3C) failed: %s\n",
174*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (st->st_log_timezone_known)
177*7c478bd9Sstevel@tonic-gate 		(void) strftime(timebuf, sizeof (timebuf), "%b %e %T",
178*7c478bd9Sstevel@tonic-gate 		    localtime_r(&now.tv_sec, &ltime));
179*7c478bd9Sstevel@tonic-gate 	else
180*7c478bd9Sstevel@tonic-gate 		xstrftime_poststart(timebuf, sizeof (timebuf), &now);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s/%d%s: ", timebuf, pthread_self(),
183*7c478bd9Sstevel@tonic-gate 	    prefix);
184*7c478bd9Sstevel@tonic-gate 	cp = strchr(buf, '\0');
185*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(cp, sizeof (buf) - (cp - buf), format, args);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
188*7c478bd9Sstevel@tonic-gate 	/* Copy into logbuf. */
189*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&logbuf_mutex);
190*7c478bd9Sstevel@tonic-gate 	if (strlen(logbuf) + strlen(buf) + 1 <= sizeof (logbuf))
191*7c478bd9Sstevel@tonic-gate 		(void) strcat(logbuf, buf);
192*7c478bd9Sstevel@tonic-gate 	else
193*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(logbuf, buf, sizeof (logbuf));
194*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&logbuf_mutex);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	if (severity > st->st_log_level_min)
197*7c478bd9Sstevel@tonic-gate 		return;
198*7c478bd9Sstevel@tonic-gate #endif
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	if (st->st_log_flags & STARTD_LOG_FILE && logfile)
201*7c478bd9Sstevel@tonic-gate 		(void) fputs(buf, logfile);
202*7c478bd9Sstevel@tonic-gate 	if (st->st_log_flags & STARTD_LOG_TERMINAL)
203*7c478bd9Sstevel@tonic-gate 		(void) fputs(buf, stdout);
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	if (st->st_log_timezone_known)
206*7c478bd9Sstevel@tonic-gate 		vsyslog(severity, format, args);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	if (st->st_log_flags & STARTD_LOG_FILE && logfile)
209*7c478bd9Sstevel@tonic-gate 		(void) fflush(logfile);
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
213*7c478bd9Sstevel@tonic-gate void
214*7c478bd9Sstevel@tonic-gate log_error(int severity, const char *format, ...)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	va_list args;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
219*7c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, " ERROR", format, args);
220*7c478bd9Sstevel@tonic-gate 	va_end(args);
221*7c478bd9Sstevel@tonic-gate }
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
224*7c478bd9Sstevel@tonic-gate void
225*7c478bd9Sstevel@tonic-gate log_framework(int severity, const char *format, ...)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	va_list args;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
230*7c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, "", format, args);
231*7c478bd9Sstevel@tonic-gate 	va_end(args);
232*7c478bd9Sstevel@tonic-gate }
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate /*
235*7c478bd9Sstevel@tonic-gate  * void log_preexec()
236*7c478bd9Sstevel@tonic-gate  *
237*7c478bd9Sstevel@tonic-gate  * log_preexec() should be invoked prior to any exec(2) calls, to prevent the
238*7c478bd9Sstevel@tonic-gate  * logfile and syslogd file descriptors from being leaked to child processes.
239*7c478bd9Sstevel@tonic-gate  * Why openlog(3C) lacks a close-on-exec option is a minor mystery.
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate void
242*7c478bd9Sstevel@tonic-gate log_preexec()
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate 	closelog();
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate /*
248*7c478bd9Sstevel@tonic-gate  * void setlog()
249*7c478bd9Sstevel@tonic-gate  *   Close file descriptors and redirect output.
250*7c478bd9Sstevel@tonic-gate  */
251*7c478bd9Sstevel@tonic-gate void
252*7c478bd9Sstevel@tonic-gate setlog(const char *logstem)
253*7c478bd9Sstevel@tonic-gate {
254*7c478bd9Sstevel@tonic-gate 	int fd;
255*7c478bd9Sstevel@tonic-gate 	char logfile[PATH_MAX];
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	closefrom(0);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	(void) open("/dev/null", O_RDONLY);
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	(void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix, logstem);
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
264*7c478bd9Sstevel@tonic-gate 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,
265*7c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
266*7c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
269*7c478bd9Sstevel@tonic-gate 		return;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	(void) dup2(fd, 1);
272*7c478bd9Sstevel@tonic-gate 	(void) dup2(fd, 2);
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	if (fd != 1 && fd != 2)
275*7c478bd9Sstevel@tonic-gate 		startd_close(fd);
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate static int
279*7c478bd9Sstevel@tonic-gate log_dir_writeable(const char *path)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	int fd;
282*7c478bd9Sstevel@tonic-gate 	struct statvfs svb;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	if ((fd = open(path, O_RDONLY, 0644)) == -1)
285*7c478bd9Sstevel@tonic-gate 		return (-1);
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	if (fstatvfs(fd, &svb) == -1)
288*7c478bd9Sstevel@tonic-gate 		return (-1);
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	if (svb.f_flag & ST_RDONLY) {
291*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 		fd = -1;
294*7c478bd9Sstevel@tonic-gate 	}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	return (fd);
297*7c478bd9Sstevel@tonic-gate }
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate static void
300*7c478bd9Sstevel@tonic-gate vlog_instance(const char *fmri, const char *logstem, boolean_t canlog,
301*7c478bd9Sstevel@tonic-gate     const char *format, va_list args)
302*7c478bd9Sstevel@tonic-gate {
303*7c478bd9Sstevel@tonic-gate 	char logfile[PATH_MAX];
304*7c478bd9Sstevel@tonic-gate 	char *message;
305*7c478bd9Sstevel@tonic-gate 	char omessage[1024];
306*7c478bd9Sstevel@tonic-gate 	int fd, err;
307*7c478bd9Sstevel@tonic-gate 	char timebuf[LOG_DATE_SIZE];
308*7c478bd9Sstevel@tonic-gate 	struct tm ltime;
309*7c478bd9Sstevel@tonic-gate 	struct timeval now;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	(void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix,
312*7c478bd9Sstevel@tonic-gate 	    logstem);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
315*7c478bd9Sstevel@tonic-gate 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,
316*7c478bd9Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
317*7c478bd9Sstevel@tonic-gate 	err = errno;
318*7c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
321*7c478bd9Sstevel@tonic-gate 		if (canlog)
322*7c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: open(%s) "
323*7c478bd9Sstevel@tonic-gate 			    "failed with %s.\n", fmri, logfile, strerror(err));
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 		return;
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(omessage, sizeof (omessage), format, args);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) != 0)
331*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "gettimeofday(3C) failed: %s\n",
332*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	if (st->st_log_timezone_known)
335*7c478bd9Sstevel@tonic-gate 		(void) strftime(timebuf, sizeof (timebuf), "%b %e %T",
336*7c478bd9Sstevel@tonic-gate 		    localtime_r(&now.tv_sec, &ltime));
337*7c478bd9Sstevel@tonic-gate 	else
338*7c478bd9Sstevel@tonic-gate 		xstrftime_poststart(timebuf, sizeof (timebuf), &now);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	message = uu_msprintf("[ %s %s ]\n", timebuf, omessage);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (message == NULL) {
343*7c478bd9Sstevel@tonic-gate 		if (canlog)
344*7c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: %s.\n",
345*7c478bd9Sstevel@tonic-gate 			    fmri, uu_strerror(uu_error()));
346*7c478bd9Sstevel@tonic-gate 	} else {
347*7c478bd9Sstevel@tonic-gate 		if (write(fd, message, strlen(message)) < 0 && canlog)
348*7c478bd9Sstevel@tonic-gate 			log_error(LOG_NOTICE, "Could not log for %s: write(%d) "
349*7c478bd9Sstevel@tonic-gate 			    "failed with %s.\n", fmri, fd,
350*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 		uu_free(message);
353*7c478bd9Sstevel@tonic-gate 	}
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	if (close(fd) != 0 && canlog)
356*7c478bd9Sstevel@tonic-gate 		log_framework(LOG_NOTICE, "close(%d) failed: %s.\n", fd,
357*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate /*
361*7c478bd9Sstevel@tonic-gate  * void log_instance(const restarter_inst_t *, boolean_t, const char *, ...)
362*7c478bd9Sstevel@tonic-gate  *
363*7c478bd9Sstevel@tonic-gate  * The log_instance() format is "[ month day time message ]".  (The
364*7c478bd9Sstevel@tonic-gate  * brackets distinguish svc.startd messages from method output.)  We avoid
365*7c478bd9Sstevel@tonic-gate  * calling log_*() functions on error when canlog is not set, since we may
366*7c478bd9Sstevel@tonic-gate  * be called from a child process.
367*7c478bd9Sstevel@tonic-gate  *
368*7c478bd9Sstevel@tonic-gate  * When adding new calls to this function, consider: If this is called before
369*7c478bd9Sstevel@tonic-gate  * any instances have started, then it should be called with canlog clear,
370*7c478bd9Sstevel@tonic-gate  * lest we spew errors to the console when booted on the miniroot.
371*7c478bd9Sstevel@tonic-gate  */
372*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
373*7c478bd9Sstevel@tonic-gate void
374*7c478bd9Sstevel@tonic-gate log_instance(const restarter_inst_t *inst, boolean_t canlog,
375*7c478bd9Sstevel@tonic-gate     const char *format, ...)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	va_list args;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
380*7c478bd9Sstevel@tonic-gate 	vlog_instance(inst->ri_i.i_fmri, inst->ri_logstem, canlog, format,
381*7c478bd9Sstevel@tonic-gate 	    args);
382*7c478bd9Sstevel@tonic-gate 	va_end(args);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * void log_instance_fmri(const char *, const char *,boolean_t, const char *,
387*7c478bd9Sstevel@tonic-gate  *    ...)
388*7c478bd9Sstevel@tonic-gate  *
389*7c478bd9Sstevel@tonic-gate  * The log_instance_fmri() format is "[ month day time message ]".  (The
390*7c478bd9Sstevel@tonic-gate  * brackets distinguish svc.startd messages from method output.)  We avoid
391*7c478bd9Sstevel@tonic-gate  * calling log_*() functions on error when canlog is not set, since we may
392*7c478bd9Sstevel@tonic-gate  * be called from a child process.
393*7c478bd9Sstevel@tonic-gate  *
394*7c478bd9Sstevel@tonic-gate  * For new calls to this function, see the warning in log_instance()'s
395*7c478bd9Sstevel@tonic-gate  * comment.
396*7c478bd9Sstevel@tonic-gate  */
397*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
398*7c478bd9Sstevel@tonic-gate void
399*7c478bd9Sstevel@tonic-gate log_instance_fmri(const char *fmri, const char *logstem, boolean_t canlog,
400*7c478bd9Sstevel@tonic-gate     const char *format, ...)
401*7c478bd9Sstevel@tonic-gate {
402*7c478bd9Sstevel@tonic-gate 	va_list args;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
405*7c478bd9Sstevel@tonic-gate 	vlog_instance(fmri, logstem, canlog, format, args);
406*7c478bd9Sstevel@tonic-gate 	va_end(args);
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate /*
410*7c478bd9Sstevel@tonic-gate  * void log_transition(const restarter_inst_t *, start_outcome_t)
411*7c478bd9Sstevel@tonic-gate  *
412*7c478bd9Sstevel@tonic-gate  * The log_transition() format is
413*7c478bd9Sstevel@tonic-gate  *
414*7c478bd9Sstevel@tonic-gate  *   [ _service_fmri_ _participle_ (_common_name_) ]
415*7c478bd9Sstevel@tonic-gate  *
416*7c478bd9Sstevel@tonic-gate  * Again, brackets separate messages from specific service instance output to
417*7c478bd9Sstevel@tonic-gate  * the console.
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate void
420*7c478bd9Sstevel@tonic-gate log_transition(const restarter_inst_t *inst, start_outcome_t outcome)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	char *message;
423*7c478bd9Sstevel@tonic-gate 	char omessage[1024];
424*7c478bd9Sstevel@tonic-gate 	char *action;
425*7c478bd9Sstevel@tonic-gate 	int severity;
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	if (outcome == START_REQUESTED) {
428*7c478bd9Sstevel@tonic-gate 		char *cname = NULL;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 		cname = inst->ri_common_name;
431*7c478bd9Sstevel@tonic-gate 		if (cname == NULL)
432*7c478bd9Sstevel@tonic-gate 			cname = inst->ri_C_common_name;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if (!(st->st_boot_flags & STARTD_BOOT_VERBOSE))
435*7c478bd9Sstevel@tonic-gate 			return;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		if (inst->ri_start_index > 1)
438*7c478bd9Sstevel@tonic-gate 			return;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		if (cname)
441*7c478bd9Sstevel@tonic-gate 			(void) snprintf(omessage, sizeof (omessage), " (%s)",
442*7c478bd9Sstevel@tonic-gate 			cname);
443*7c478bd9Sstevel@tonic-gate 		else
444*7c478bd9Sstevel@tonic-gate 			*omessage = '\0';
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		action = gettext("starting");
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 		message = uu_msprintf("[ %s %s%s ]\n",
449*7c478bd9Sstevel@tonic-gate 		    inst->ri_i.i_fmri + strlen("svc:/"), action,
450*7c478bd9Sstevel@tonic-gate 		    omessage);
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		severity = LOG_INFO;
453*7c478bd9Sstevel@tonic-gate 	} else {
454*7c478bd9Sstevel@tonic-gate 		switch (outcome) {
455*7c478bd9Sstevel@tonic-gate 		case START_FAILED_REPEATEDLY:
456*7c478bd9Sstevel@tonic-gate 			action = gettext("failed repeatedly");
457*7c478bd9Sstevel@tonic-gate 			break;
458*7c478bd9Sstevel@tonic-gate 		case START_FAILED_CONFIGURATION:
459*7c478bd9Sstevel@tonic-gate 			action = gettext("misconfigured");
460*7c478bd9Sstevel@tonic-gate 			break;
461*7c478bd9Sstevel@tonic-gate 		case START_FAILED_FATAL:
462*7c478bd9Sstevel@tonic-gate 			action = gettext("failed fatally");
463*7c478bd9Sstevel@tonic-gate 			break;
464*7c478bd9Sstevel@tonic-gate 		case START_FAILED_TIMEOUT_FATAL:
465*7c478bd9Sstevel@tonic-gate 			action = gettext("timed out, fault threshold reached");
466*7c478bd9Sstevel@tonic-gate 			break;
467*7c478bd9Sstevel@tonic-gate 		case START_FAILED_OTHER:
468*7c478bd9Sstevel@tonic-gate 			action = gettext("failed");
469*7c478bd9Sstevel@tonic-gate 			break;
470*7c478bd9Sstevel@tonic-gate 		case START_REQUESTED:
471*7c478bd9Sstevel@tonic-gate 			assert(outcome != START_REQUESTED);
472*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
473*7c478bd9Sstevel@tonic-gate 		default:
474*7c478bd9Sstevel@tonic-gate 			action = gettext("outcome unknown?");
475*7c478bd9Sstevel@tonic-gate 		}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 		message = uu_msprintf("[ %s %s %s ]\n",
478*7c478bd9Sstevel@tonic-gate 		    inst->ri_i.i_fmri + strlen("svc:/"), action,
479*7c478bd9Sstevel@tonic-gate 		    gettext("(see 'svcs -x' for details)"));
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 		severity = LOG_ERR;
482*7c478bd9Sstevel@tonic-gate 	}
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if (message == NULL) {
486*7c478bd9Sstevel@tonic-gate 		log_error(LOG_NOTICE,
487*7c478bd9Sstevel@tonic-gate 		    "Could not log boot message for %s: %s.\n",
488*7c478bd9Sstevel@tonic-gate 		    inst->ri_i.i_fmri, uu_strerror(uu_error()));
489*7c478bd9Sstevel@tonic-gate 	} else {
490*7c478bd9Sstevel@tonic-gate 		if (!st->st_log_login_reached) {
491*7c478bd9Sstevel@tonic-gate 			/*LINTED*/
492*7c478bd9Sstevel@tonic-gate 			if (fprintf(stderr, message) < 0)
493*7c478bd9Sstevel@tonic-gate 				log_error(LOG_NOTICE, "Could not log for %s: "
494*7c478bd9Sstevel@tonic-gate 				    "fprintf() failed with %s.\n",
495*7c478bd9Sstevel@tonic-gate 				    inst->ri_i.i_fmri, strerror(errno));
496*7c478bd9Sstevel@tonic-gate 		} else {
497*7c478bd9Sstevel@tonic-gate 			log_framework(severity, "%s %s\n",
498*7c478bd9Sstevel@tonic-gate 			    inst->ri_i.i_fmri + strlen("svc:/"), action);
499*7c478bd9Sstevel@tonic-gate 		}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 		uu_free(message);
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate }
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate /*
506*7c478bd9Sstevel@tonic-gate  * log_console - log a message to the consoles and to syslog
507*7c478bd9Sstevel@tonic-gate  *
508*7c478bd9Sstevel@tonic-gate  * This logs a message as-is to the console (and auxiliary consoles),
509*7c478bd9Sstevel@tonic-gate  * as well as to the master restarter log.
510*7c478bd9Sstevel@tonic-gate  */
511*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
512*7c478bd9Sstevel@tonic-gate void
513*7c478bd9Sstevel@tonic-gate log_console(int severity, const char *format, ...)
514*7c478bd9Sstevel@tonic-gate {
515*7c478bd9Sstevel@tonic-gate 	va_list args;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
518*7c478bd9Sstevel@tonic-gate 	vlog_prefix(severity, "", format, args);
519*7c478bd9Sstevel@tonic-gate 	va_end(args);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
522*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, format, args);
523*7c478bd9Sstevel@tonic-gate 	va_end(args);
524*7c478bd9Sstevel@tonic-gate }
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate /*
527*7c478bd9Sstevel@tonic-gate  * void log_init()
528*7c478bd9Sstevel@tonic-gate  *
529*7c478bd9Sstevel@tonic-gate  * Set up the log files, if necessary, for the current invocation.  This
530*7c478bd9Sstevel@tonic-gate  * function should be called before any other functions in this file.  Set the
531*7c478bd9Sstevel@tonic-gate  * syslog(3C) logging mask such that severities of the importance of
532*7c478bd9Sstevel@tonic-gate  * LOG_NOTICE and above are passed through, but lower severity messages are
533*7c478bd9Sstevel@tonic-gate  * masked out.
534*7c478bd9Sstevel@tonic-gate  *
535*7c478bd9Sstevel@tonic-gate  * It may be called multiple times to change the logging configuration due to
536*7c478bd9Sstevel@tonic-gate  * administrative request.
537*7c478bd9Sstevel@tonic-gate  */
538*7c478bd9Sstevel@tonic-gate void
539*7c478bd9Sstevel@tonic-gate log_init()
540*7c478bd9Sstevel@tonic-gate {
541*7c478bd9Sstevel@tonic-gate 	int dirfd, logfd;
542*7c478bd9Sstevel@tonic-gate 	char *dir;
543*7c478bd9Sstevel@tonic-gate 	struct stat sb;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	if (st->st_start_time.tv_sec == 0) {
546*7c478bd9Sstevel@tonic-gate 		if (getzoneid() != GLOBAL_ZONEID) {
547*7c478bd9Sstevel@tonic-gate 			st->st_start_time.tv_sec = time(NULL);
548*7c478bd9Sstevel@tonic-gate 		} else {
549*7c478bd9Sstevel@tonic-gate 			/*
550*7c478bd9Sstevel@tonic-gate 			 * We need to special-case the BOOT_TIME utmp entry, and
551*7c478bd9Sstevel@tonic-gate 			 * drag that value out of the kernel if it's there.
552*7c478bd9Sstevel@tonic-gate 			 */
553*7c478bd9Sstevel@tonic-gate 			kstat_ctl_t *kc;
554*7c478bd9Sstevel@tonic-gate 			kstat_t *ks;
555*7c478bd9Sstevel@tonic-gate 			kstat_named_t *boot;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 			if (((kc = kstat_open()) != 0) &&
558*7c478bd9Sstevel@tonic-gate 			    ((ks = kstat_lookup(kc, "unix", 0, "system_misc"))
559*7c478bd9Sstevel@tonic-gate 			    != NULL) &&
560*7c478bd9Sstevel@tonic-gate 			    (kstat_read(kc, ks, NULL) != -1) &&
561*7c478bd9Sstevel@tonic-gate 			    ((boot = kstat_data_lookup(ks, "boot_time")) !=
562*7c478bd9Sstevel@tonic-gate 			    NULL)) {
563*7c478bd9Sstevel@tonic-gate 				/*
564*7c478bd9Sstevel@tonic-gate 				 * If we're here, then we've successfully found
565*7c478bd9Sstevel@tonic-gate 				 * the boot_time kstat... use its value.
566*7c478bd9Sstevel@tonic-gate 				 */
567*7c478bd9Sstevel@tonic-gate 				st->st_start_time.tv_sec = boot->value.ul;
568*7c478bd9Sstevel@tonic-gate 			} else {
569*7c478bd9Sstevel@tonic-gate 				st->st_start_time.tv_sec = time(NULL);
570*7c478bd9Sstevel@tonic-gate 			}
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 			if (kc)
573*7c478bd9Sstevel@tonic-gate 				(void) kstat_close(kc);
574*7c478bd9Sstevel@tonic-gate 		}
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	/*
578*7c478bd9Sstevel@tonic-gate 	 * Establish our timezone if the appropriate directory is available.
579*7c478bd9Sstevel@tonic-gate 	 */
580*7c478bd9Sstevel@tonic-gate 	if (!st->st_log_timezone_known && stat(FS_TIMEZONE_DIR, &sb) == 0) {
581*7c478bd9Sstevel@tonic-gate 		tzset();
582*7c478bd9Sstevel@tonic-gate 		st->st_log_timezone_known = 1;
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/*
586*7c478bd9Sstevel@tonic-gate 	 * Establish our locale if the appropriate directory is available.  Set
587*7c478bd9Sstevel@tonic-gate 	 * the locale string from the environment so we can extract template
588*7c478bd9Sstevel@tonic-gate 	 * information correctly, if the locale directories aren't yet
589*7c478bd9Sstevel@tonic-gate 	 * available.
590*7c478bd9Sstevel@tonic-gate 	 */
591*7c478bd9Sstevel@tonic-gate 	if (st->st_locale != NULL)
592*7c478bd9Sstevel@tonic-gate 		free(st->st_locale);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	if ((st->st_locale = getenv("LC_ALL")) == NULL)
595*7c478bd9Sstevel@tonic-gate 		if ((st->st_locale = getenv("LC_MESSAGES")) == NULL)
596*7c478bd9Sstevel@tonic-gate 			st->st_locale = getenv("LANG");
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	if (!st->st_log_locale_known && stat(FS_LOCALE_DIR, &sb) == 0) {
599*7c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_ALL, "");
600*7c478bd9Sstevel@tonic-gate 		st->st_locale = setlocale(LC_MESSAGES, "");
601*7c478bd9Sstevel@tonic-gate 		if (st->st_locale)
602*7c478bd9Sstevel@tonic-gate 			st->st_log_locale_known = 1;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		(void) textdomain(TEXT_DOMAIN);
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (st->st_locale) {
608*7c478bd9Sstevel@tonic-gate 		st->st_locale = safe_strdup(st->st_locale);
609*7c478bd9Sstevel@tonic-gate 		xstr_sanitize(st->st_locale);
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	if (logfile) {
613*7c478bd9Sstevel@tonic-gate 		(void) fclose(logfile);
614*7c478bd9Sstevel@tonic-gate 		logfile = NULL;
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	/*
618*7c478bd9Sstevel@tonic-gate 	 * Set syslog(3C) behaviour in all cases.
619*7c478bd9Sstevel@tonic-gate 	 */
620*7c478bd9Sstevel@tonic-gate 	closelog();
621*7c478bd9Sstevel@tonic-gate 	openlog("svc.startd", LOG_PID | LOG_CONS, LOG_DAEMON);
622*7c478bd9Sstevel@tonic-gate 	(void) setlogmask(LOG_UPTO(LOG_NOTICE));
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	if ((dirfd = log_dir_writeable(LOG_PREFIX_NORMAL)) == -1) {
625*7c478bd9Sstevel@tonic-gate 		if ((dirfd = log_dir_writeable(LOG_PREFIX_EARLY)) == -1)
626*7c478bd9Sstevel@tonic-gate 			return;
627*7c478bd9Sstevel@tonic-gate 		else
628*7c478bd9Sstevel@tonic-gate 			dir = LOG_PREFIX_EARLY;
629*7c478bd9Sstevel@tonic-gate 	} else {
630*7c478bd9Sstevel@tonic-gate 		dir = LOG_PREFIX_NORMAL;
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	st->st_log_prefix = dir;
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	(void) umask(fmask);
636*7c478bd9Sstevel@tonic-gate 	if ((logfd = openat(dirfd, STARTD_DEFAULT_LOG, O_CREAT | O_RDWR,
637*7c478bd9Sstevel@tonic-gate 	    0644)) == -1) {
638*7c478bd9Sstevel@tonic-gate 		(void) close(dirfd);
639*7c478bd9Sstevel@tonic-gate 		(void) umask(dmask);
640*7c478bd9Sstevel@tonic-gate 		return;
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	(void) close(dirfd);
644*7c478bd9Sstevel@tonic-gate 	(void) umask(dmask);
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	if ((logfile = fdopen(logfd, "a")) == NULL)
647*7c478bd9Sstevel@tonic-gate 		if (errno != EROFS)
648*7c478bd9Sstevel@tonic-gate 			log_error(LOG_WARNING, "can't open logfile %s/%s",
649*7c478bd9Sstevel@tonic-gate 			    dir, STARTD_DEFAULT_LOG);
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if (logfile &&
652*7c478bd9Sstevel@tonic-gate 	    fcntl(fileno(logfile), F_SETFD, FD_CLOEXEC) == -1)
653*7c478bd9Sstevel@tonic-gate 		log_error(LOG_WARNING,
654*7c478bd9Sstevel@tonic-gate 		    "couldn't mark logfile close-on-exec: %s\n",
655*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
656*7c478bd9Sstevel@tonic-gate }
657