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 9354d6518cSrm88369 * 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 9754d6518cSrm88369 * 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 1283efb42ecSrm88369 /* 1293efb42ecSrm88369 * This parameter can be modified using mdb to turn on & off extended 1303efb42ecSrm88369 * internal debug logging. Although a performance loss can be expected. 1313efb42ecSrm88369 */ 1323efb42ecSrm88369 static int internal_debug_flags = 0x0; 1333efb42ecSrm88369 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 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 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, <ime)); 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 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 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 2347c478bd9Sstevel@tonic-gate /* 2353efb42ecSrm88369 * log_framework2() differs from log_framework() by the fact that 2363efb42ecSrm88369 * some checking are done before logging the messages in the internal 2373efb42ecSrm88369 * buffer for performance reasons. 2383efb42ecSrm88369 * The messages aren't logged if: 2393efb42ecSrm88369 * - severity >= LOG_DEBUG and 2403efb42ecSrm88369 * - st_log_level_min < LOG_DEBUG and 2413efb42ecSrm88369 * - internal_debug_flags is not set for 'flags' 2423efb42ecSrm88369 */ 2433efb42ecSrm88369 void 2443efb42ecSrm88369 log_framework2(int severity, int flags, const char *format, ...) 2453efb42ecSrm88369 { 2463efb42ecSrm88369 va_list args; 2473efb42ecSrm88369 2483efb42ecSrm88369 if ((severity < LOG_DEBUG) || 2493efb42ecSrm88369 (internal_debug_flags & flags) || 2503efb42ecSrm88369 st->st_log_level_min >= LOG_DEBUG) { 2513efb42ecSrm88369 va_start(args, format); 2523efb42ecSrm88369 vlog_prefix(severity, "", format, args); 2533efb42ecSrm88369 va_end(args); 2543efb42ecSrm88369 } 2553efb42ecSrm88369 } 2563efb42ecSrm88369 2573efb42ecSrm88369 /* 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 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 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 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 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, <ime)); 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 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 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 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)", 4657c478bd9Sstevel@tonic-gate 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 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 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