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 /* 22*2f1b831aSacruz * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * log.c - debugging and logging functions 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * Logging destinations 327c478bd9Sstevel@tonic-gate * svc.startd(1M) supports three logging destinations: the system log, a 337c478bd9Sstevel@tonic-gate * daemon-specific log (in the /var/svc/log hierarchy by default), and to the 3499b44c3bSlianep * standard output (redirected to the /var/svc/log/svc.startd.log file by 3599b44c3bSlianep * default). Any or all of these destinations may be used to 367c478bd9Sstevel@tonic-gate * communicate a specific message; the audiences for each destination differ. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Generic messages associated with svc.startd(1M) are made by the 397c478bd9Sstevel@tonic-gate * log_framework() and log_error() functions. For these messages, svc.startd 407c478bd9Sstevel@tonic-gate * logs under its own name and under the LOG_DAEMON facility when issuing 417c478bd9Sstevel@tonic-gate * events to the system log. By design, severities below LOG_NOTICE are never 427c478bd9Sstevel@tonic-gate * issued to the system log. 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * Messages associated with a specific service instance are logged using the 457c478bd9Sstevel@tonic-gate * log_instance() or log_instance_fmri() functions. These messages are always 467c478bd9Sstevel@tonic-gate * sent to the appropriate per-instance log file. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * In the case of verbose or debug boot, the log_transition() function 497c478bd9Sstevel@tonic-gate * displays messages regarding instance transitions to the system console, 507c478bd9Sstevel@tonic-gate * until the expected login services are available. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Finally, log_console() displays messages to the system consoles and 537c478bd9Sstevel@tonic-gate * the master restarter log file. This is used when booting to a milestone 547c478bd9Sstevel@tonic-gate * other than 'all'. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * Logging detail 577c478bd9Sstevel@tonic-gate * The constants for severity from <syslog.h> are reused, with a specific 587c478bd9Sstevel@tonic-gate * convention here. (It is worth noting that the #define values for the LOG_ 597c478bd9Sstevel@tonic-gate * levels are such that more important severities have lower values.) The 607c478bd9Sstevel@tonic-gate * severity determines the importance of the event, and its addressibility by 617c478bd9Sstevel@tonic-gate * the administrator. Each severity level's use is defined below, along with 627c478bd9Sstevel@tonic-gate * an illustrative example. 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * LOG_EMERG Not used presently. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * LOG_ALERT An unrecoverable operation requiring external 677c478bd9Sstevel@tonic-gate * intervention has occurred. Includes an inability to 687c478bd9Sstevel@tonic-gate * write to the smf(5) repository (due to svc.configd(1M) 697c478bd9Sstevel@tonic-gate * absence, due to permissions failures, etc.). Message 707c478bd9Sstevel@tonic-gate * should identify component at fault. 717c478bd9Sstevel@tonic-gate * 727c478bd9Sstevel@tonic-gate * LOG_CRIT An unrecoverable operation internal to svc.startd(1M) 737c478bd9Sstevel@tonic-gate * has occurred. Failure should be recoverable by restart 747c478bd9Sstevel@tonic-gate * of svc.startd(1M). 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * LOG_ERR An smf(5) event requiring administrative intervention 777c478bd9Sstevel@tonic-gate * has occurred. Includes instance being moved to the 787c478bd9Sstevel@tonic-gate * maintenance state. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * LOG_WARNING A potentially destabilizing smf(5) event not requiring 817c478bd9Sstevel@tonic-gate * administrative intervention has occurred. 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * LOG_NOTICE A noteworthy smf(5) event has occurred. Includes 847c478bd9Sstevel@tonic-gate * individual instance failures. 857c478bd9Sstevel@tonic-gate * 867c478bd9Sstevel@tonic-gate * LOG_INFO A noteworthy operation internal to svc.startd(1M) has 877c478bd9Sstevel@tonic-gate * occurred. Includes recoverable failures or otherwise 887c478bd9Sstevel@tonic-gate * unexpected outcomes. 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * LOG_DEBUG An internal operation only of interest to a 917c478bd9Sstevel@tonic-gate * svc.startd(1M) developer has occurred. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * Logging configuration 9454d6518cSrm88369 * The preferred approach is to set the logging property values 957c478bd9Sstevel@tonic-gate * in the options property group of the svc.startd default instance. The 967c478bd9Sstevel@tonic-gate * valid values are "quiet", "verbose", and "debug". "quiet" is the default; 977c478bd9Sstevel@tonic-gate * "verbose" and "debug" allow LOG_INFO and LOG_DEBUG logging requests to 9854d6518cSrm88369 * reach the svc.startd.log file, respectively. 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate #include <sys/stat.h> 1027c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 1037c478bd9Sstevel@tonic-gate #include <sys/time.h> 1047c478bd9Sstevel@tonic-gate #include <sys/types.h> 1057c478bd9Sstevel@tonic-gate #include <assert.h> 1067c478bd9Sstevel@tonic-gate #include <errno.h> 1077c478bd9Sstevel@tonic-gate #include <fcntl.h> 1087c478bd9Sstevel@tonic-gate #include <kstat.h> 1097c478bd9Sstevel@tonic-gate #include <libgen.h> 1107c478bd9Sstevel@tonic-gate #include <libintl.h> 1117c478bd9Sstevel@tonic-gate #include <libuutil.h> 1127c478bd9Sstevel@tonic-gate #include <locale.h> 1137c478bd9Sstevel@tonic-gate #include <malloc.h> 1147c478bd9Sstevel@tonic-gate #include <pthread.h> 1157c478bd9Sstevel@tonic-gate #include <stdarg.h> 1167c478bd9Sstevel@tonic-gate #include <stdio.h> 1177c478bd9Sstevel@tonic-gate #include <strings.h> 1187c478bd9Sstevel@tonic-gate #include <syslog.h> 1197c478bd9Sstevel@tonic-gate #include <unistd.h> 1207c478bd9Sstevel@tonic-gate #include <zone.h> 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate #include "startd.h" 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #define LOGBUF_SZ (60 * 80) /* 60 lines */ 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static FILE *logfile = NULL; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate #ifndef NDEBUG 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * This is a circular buffer for all (even those not emitted externally) 1327c478bd9Sstevel@tonic-gate * logging messages. To read it properly you should start after the first 1337c478bd9Sstevel@tonic-gate * null, go until the second, and then go back to the beginning until the 1347c478bd9Sstevel@tonic-gate * first null. Or use ::startd_log in mdb. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate static char logbuf[LOGBUF_SZ] = ""; 1377c478bd9Sstevel@tonic-gate static pthread_mutex_t logbuf_mutex = PTHREAD_MUTEX_INITIALIZER; 1387c478bd9Sstevel@tonic-gate #endif 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate static void 1417c478bd9Sstevel@tonic-gate xstrftime_poststart(char *buf, size_t bufsize, struct timeval *time) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate long sec, usec; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate sec = time->tv_sec - st->st_start_time.tv_sec; 1467c478bd9Sstevel@tonic-gate usec = time->tv_usec - st->st_start_time.tv_usec; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate if (usec < 0) { 1497c478bd9Sstevel@tonic-gate sec -= 1; 1507c478bd9Sstevel@tonic-gate usec += 1000000; 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate (void) snprintf(buf, bufsize, "start + %d.%02ds", sec, usec / 10000); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static void 1577c478bd9Sstevel@tonic-gate vlog_prefix(int severity, const char *prefix, const char *format, va_list args) 1587c478bd9Sstevel@tonic-gate { 1597c478bd9Sstevel@tonic-gate char buf[512], *cp; 1607c478bd9Sstevel@tonic-gate char timebuf[LOG_DATE_SIZE]; 1617c478bd9Sstevel@tonic-gate struct timeval now; 1627c478bd9Sstevel@tonic-gate struct tm ltime; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate #ifdef NDEBUG 1657c478bd9Sstevel@tonic-gate if (severity > st->st_log_level_min) 1667c478bd9Sstevel@tonic-gate return; 1677c478bd9Sstevel@tonic-gate #endif 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (gettimeofday(&now, NULL) != 0) 1707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "gettimeofday(3C) failed: %s\n", 1717c478bd9Sstevel@tonic-gate strerror(errno)); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if (st->st_log_timezone_known) 1747c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), "%b %e %T", 1757c478bd9Sstevel@tonic-gate localtime_r(&now.tv_sec, <ime)); 1767c478bd9Sstevel@tonic-gate else 1777c478bd9Sstevel@tonic-gate xstrftime_poststart(timebuf, sizeof (timebuf), &now); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s/%d%s: ", timebuf, pthread_self(), 1807c478bd9Sstevel@tonic-gate prefix); 1817c478bd9Sstevel@tonic-gate cp = strchr(buf, '\0'); 1827c478bd9Sstevel@tonic-gate (void) vsnprintf(cp, sizeof (buf) - (cp - buf), format, args); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate #ifndef NDEBUG 1857c478bd9Sstevel@tonic-gate /* Copy into logbuf. */ 1867c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&logbuf_mutex); 1877c478bd9Sstevel@tonic-gate if (strlen(logbuf) + strlen(buf) + 1 <= sizeof (logbuf)) 1887c478bd9Sstevel@tonic-gate (void) strcat(logbuf, buf); 1897c478bd9Sstevel@tonic-gate else 1907c478bd9Sstevel@tonic-gate (void) strlcpy(logbuf, buf, sizeof (logbuf)); 1917c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&logbuf_mutex); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (severity > st->st_log_level_min) 1947c478bd9Sstevel@tonic-gate return; 1957c478bd9Sstevel@tonic-gate #endif 1967c478bd9Sstevel@tonic-gate 19799b44c3bSlianep if (st->st_log_flags & STARTD_LOG_FILE && logfile) { 1987c478bd9Sstevel@tonic-gate (void) fputs(buf, logfile); 19999b44c3bSlianep (void) fflush(logfile); 20099b44c3bSlianep } 2017c478bd9Sstevel@tonic-gate if (st->st_log_flags & STARTD_LOG_TERMINAL) 2027c478bd9Sstevel@tonic-gate (void) fputs(buf, stdout); 20399b44c3bSlianep if (st->st_log_flags & STARTD_LOG_SYSLOG && st->st_log_timezone_known) 2047c478bd9Sstevel@tonic-gate vsyslog(severity, format, args); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 2087c478bd9Sstevel@tonic-gate void 2097c478bd9Sstevel@tonic-gate log_error(int severity, const char *format, ...) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate va_list args; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate va_start(args, format); 2147c478bd9Sstevel@tonic-gate vlog_prefix(severity, " ERROR", format, args); 2157c478bd9Sstevel@tonic-gate va_end(args); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 2197c478bd9Sstevel@tonic-gate void 2207c478bd9Sstevel@tonic-gate log_framework(int severity, const char *format, ...) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate va_list args; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate va_start(args, format); 2257c478bd9Sstevel@tonic-gate vlog_prefix(severity, "", format, args); 2267c478bd9Sstevel@tonic-gate va_end(args); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * void log_preexec() 2317c478bd9Sstevel@tonic-gate * 2327c478bd9Sstevel@tonic-gate * log_preexec() should be invoked prior to any exec(2) calls, to prevent the 2337c478bd9Sstevel@tonic-gate * logfile and syslogd file descriptors from being leaked to child processes. 2347c478bd9Sstevel@tonic-gate * Why openlog(3C) lacks a close-on-exec option is a minor mystery. 2357c478bd9Sstevel@tonic-gate */ 2367c478bd9Sstevel@tonic-gate void 2377c478bd9Sstevel@tonic-gate log_preexec() 2387c478bd9Sstevel@tonic-gate { 2397c478bd9Sstevel@tonic-gate closelog(); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * void setlog() 2447c478bd9Sstevel@tonic-gate * Close file descriptors and redirect output. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate void 2477c478bd9Sstevel@tonic-gate setlog(const char *logstem) 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate int fd; 2507c478bd9Sstevel@tonic-gate char logfile[PATH_MAX]; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate closefrom(0); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate (void) open("/dev/null", O_RDONLY); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate (void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix, logstem); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate (void) umask(fmask); 2597c478bd9Sstevel@tonic-gate fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 2607c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 2617c478bd9Sstevel@tonic-gate (void) umask(dmask); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if (fd == -1) 2647c478bd9Sstevel@tonic-gate return; 2657c478bd9Sstevel@tonic-gate 266*2f1b831aSacruz (void) dup2(fd, STDOUT_FILENO); 267*2f1b831aSacruz (void) dup2(fd, STDERR_FILENO); 2687c478bd9Sstevel@tonic-gate 269*2f1b831aSacruz if (fd != STDOUT_FILENO && fd != STDERR_FILENO) 2707c478bd9Sstevel@tonic-gate startd_close(fd); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate static int 2747c478bd9Sstevel@tonic-gate log_dir_writeable(const char *path) 2757c478bd9Sstevel@tonic-gate { 2767c478bd9Sstevel@tonic-gate int fd; 2777c478bd9Sstevel@tonic-gate struct statvfs svb; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY, 0644)) == -1) 2807c478bd9Sstevel@tonic-gate return (-1); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (fstatvfs(fd, &svb) == -1) 2837c478bd9Sstevel@tonic-gate return (-1); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if (svb.f_flag & ST_RDONLY) { 2867c478bd9Sstevel@tonic-gate (void) close(fd); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate fd = -1; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate return (fd); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate static void 2957c478bd9Sstevel@tonic-gate vlog_instance(const char *fmri, const char *logstem, boolean_t canlog, 2967c478bd9Sstevel@tonic-gate const char *format, va_list args) 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate char logfile[PATH_MAX]; 2997c478bd9Sstevel@tonic-gate char *message; 3007c478bd9Sstevel@tonic-gate char omessage[1024]; 3017c478bd9Sstevel@tonic-gate int fd, err; 3027c478bd9Sstevel@tonic-gate char timebuf[LOG_DATE_SIZE]; 3037c478bd9Sstevel@tonic-gate struct tm ltime; 3047c478bd9Sstevel@tonic-gate struct timeval now; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate (void) snprintf(logfile, PATH_MAX, "%s/%s", st->st_log_prefix, 3077c478bd9Sstevel@tonic-gate logstem); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate (void) umask(fmask); 3107c478bd9Sstevel@tonic-gate fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 3117c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 3127c478bd9Sstevel@tonic-gate err = errno; 3137c478bd9Sstevel@tonic-gate (void) umask(dmask); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate if (fd == -1) { 3167c478bd9Sstevel@tonic-gate if (canlog) 3177c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not log for %s: open(%s) " 3187c478bd9Sstevel@tonic-gate "failed with %s.\n", fmri, logfile, strerror(err)); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate return; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate (void) vsnprintf(omessage, sizeof (omessage), format, args); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (gettimeofday(&now, NULL) != 0) 3267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "gettimeofday(3C) failed: %s\n", 3277c478bd9Sstevel@tonic-gate strerror(errno)); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (st->st_log_timezone_known) 3307c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), "%b %e %T", 3317c478bd9Sstevel@tonic-gate localtime_r(&now.tv_sec, <ime)); 3327c478bd9Sstevel@tonic-gate else 3337c478bd9Sstevel@tonic-gate xstrftime_poststart(timebuf, sizeof (timebuf), &now); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate message = uu_msprintf("[ %s %s ]\n", timebuf, omessage); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (message == NULL) { 3387c478bd9Sstevel@tonic-gate if (canlog) 3397c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not log for %s: %s.\n", 3407c478bd9Sstevel@tonic-gate fmri, uu_strerror(uu_error())); 3417c478bd9Sstevel@tonic-gate } else { 3427c478bd9Sstevel@tonic-gate if (write(fd, message, strlen(message)) < 0 && canlog) 3437c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not log for %s: write(%d) " 3447c478bd9Sstevel@tonic-gate "failed with %s.\n", fmri, fd, 3457c478bd9Sstevel@tonic-gate strerror(errno)); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate uu_free(message); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (close(fd) != 0 && canlog) 3517c478bd9Sstevel@tonic-gate log_framework(LOG_NOTICE, "close(%d) failed: %s.\n", fd, 3527c478bd9Sstevel@tonic-gate strerror(errno)); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * void log_instance(const restarter_inst_t *, boolean_t, const char *, ...) 3577c478bd9Sstevel@tonic-gate * 3587c478bd9Sstevel@tonic-gate * The log_instance() format is "[ month day time message ]". (The 3597c478bd9Sstevel@tonic-gate * brackets distinguish svc.startd messages from method output.) We avoid 3607c478bd9Sstevel@tonic-gate * calling log_*() functions on error when canlog is not set, since we may 3617c478bd9Sstevel@tonic-gate * be called from a child process. 3627c478bd9Sstevel@tonic-gate * 3637c478bd9Sstevel@tonic-gate * When adding new calls to this function, consider: If this is called before 3647c478bd9Sstevel@tonic-gate * any instances have started, then it should be called with canlog clear, 3657c478bd9Sstevel@tonic-gate * lest we spew errors to the console when booted on the miniroot. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 3687c478bd9Sstevel@tonic-gate void 3697c478bd9Sstevel@tonic-gate log_instance(const restarter_inst_t *inst, boolean_t canlog, 3707c478bd9Sstevel@tonic-gate const char *format, ...) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate va_list args; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate va_start(args, format); 3757c478bd9Sstevel@tonic-gate vlog_instance(inst->ri_i.i_fmri, inst->ri_logstem, canlog, format, 3767c478bd9Sstevel@tonic-gate args); 3777c478bd9Sstevel@tonic-gate va_end(args); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * void log_instance_fmri(const char *, const char *,boolean_t, const char *, 3827c478bd9Sstevel@tonic-gate * ...) 3837c478bd9Sstevel@tonic-gate * 3847c478bd9Sstevel@tonic-gate * The log_instance_fmri() format is "[ month day time message ]". (The 3857c478bd9Sstevel@tonic-gate * brackets distinguish svc.startd messages from method output.) We avoid 3867c478bd9Sstevel@tonic-gate * calling log_*() functions on error when canlog is not set, since we may 3877c478bd9Sstevel@tonic-gate * be called from a child process. 3887c478bd9Sstevel@tonic-gate * 3897c478bd9Sstevel@tonic-gate * For new calls to this function, see the warning in log_instance()'s 3907c478bd9Sstevel@tonic-gate * comment. 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/ 3937c478bd9Sstevel@tonic-gate void 3947c478bd9Sstevel@tonic-gate log_instance_fmri(const char *fmri, const char *logstem, boolean_t canlog, 3957c478bd9Sstevel@tonic-gate const char *format, ...) 3967c478bd9Sstevel@tonic-gate { 3977c478bd9Sstevel@tonic-gate va_list args; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate va_start(args, format); 4007c478bd9Sstevel@tonic-gate vlog_instance(fmri, logstem, canlog, format, args); 4017c478bd9Sstevel@tonic-gate va_end(args); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * void log_transition(const restarter_inst_t *, start_outcome_t) 4067c478bd9Sstevel@tonic-gate * 4077c478bd9Sstevel@tonic-gate * The log_transition() format is 4087c478bd9Sstevel@tonic-gate * 4097c478bd9Sstevel@tonic-gate * [ _service_fmri_ _participle_ (_common_name_) ] 4107c478bd9Sstevel@tonic-gate * 4117c478bd9Sstevel@tonic-gate * Again, brackets separate messages from specific service instance output to 4127c478bd9Sstevel@tonic-gate * the console. 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate void 4157c478bd9Sstevel@tonic-gate log_transition(const restarter_inst_t *inst, start_outcome_t outcome) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate char *message; 4187c478bd9Sstevel@tonic-gate char omessage[1024]; 4197c478bd9Sstevel@tonic-gate char *action; 4207c478bd9Sstevel@tonic-gate int severity; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if (outcome == START_REQUESTED) { 4237c478bd9Sstevel@tonic-gate char *cname = NULL; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate cname = inst->ri_common_name; 4267c478bd9Sstevel@tonic-gate if (cname == NULL) 4277c478bd9Sstevel@tonic-gate cname = inst->ri_C_common_name; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate if (!(st->st_boot_flags & STARTD_BOOT_VERBOSE)) 4307c478bd9Sstevel@tonic-gate return; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if (inst->ri_start_index > 1) 4337c478bd9Sstevel@tonic-gate return; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if (cname) 4367c478bd9Sstevel@tonic-gate (void) snprintf(omessage, sizeof (omessage), " (%s)", 4377c478bd9Sstevel@tonic-gate cname); 4387c478bd9Sstevel@tonic-gate else 4397c478bd9Sstevel@tonic-gate *omessage = '\0'; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate action = gettext("starting"); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate message = uu_msprintf("[ %s %s%s ]\n", 4447c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri + strlen("svc:/"), action, 4457c478bd9Sstevel@tonic-gate omessage); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate severity = LOG_INFO; 4487c478bd9Sstevel@tonic-gate } else { 4497c478bd9Sstevel@tonic-gate switch (outcome) { 45099b44c3bSlianep case MAINT_REQUESTED: 45199b44c3bSlianep action = gettext("transitioned to maintenance by " 45299b44c3bSlianep "request (see 'svcs -xv' for details)"); 45399b44c3bSlianep break; 4547c478bd9Sstevel@tonic-gate case START_FAILED_REPEATEDLY: 45599b44c3bSlianep action = gettext("failed repeatedly: transitioned to " 45699b44c3bSlianep "maintenance (see 'svcs -xv' for details)"); 4577c478bd9Sstevel@tonic-gate break; 4587c478bd9Sstevel@tonic-gate case START_FAILED_CONFIGURATION: 45999b44c3bSlianep action = gettext("misconfigured: transitioned to " 46099b44c3bSlianep "maintenance (see 'svcs -xv' for details)"); 4617c478bd9Sstevel@tonic-gate break; 4627c478bd9Sstevel@tonic-gate case START_FAILED_FATAL: 46399b44c3bSlianep action = gettext("failed fatally: transitioned to " 46499b44c3bSlianep "maintenance (see 'svcs -xv' for details)"); 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate case START_FAILED_TIMEOUT_FATAL: 46799b44c3bSlianep action = gettext("timed out: transitioned to " 46899b44c3bSlianep "maintenance (see 'svcs -xv' for details)"); 4697c478bd9Sstevel@tonic-gate break; 4707c478bd9Sstevel@tonic-gate case START_FAILED_OTHER: 47199b44c3bSlianep action = gettext("failed: transitioned to " 47299b44c3bSlianep "maintenance (see 'svcs -xv' for details)"); 4737c478bd9Sstevel@tonic-gate break; 4747c478bd9Sstevel@tonic-gate case START_REQUESTED: 4757c478bd9Sstevel@tonic-gate assert(outcome != START_REQUESTED); 4767c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 4777c478bd9Sstevel@tonic-gate default: 4787c478bd9Sstevel@tonic-gate action = gettext("outcome unknown?"); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 48199b44c3bSlianep message = uu_msprintf("[ %s %s ]\n", 48299b44c3bSlianep inst->ri_i.i_fmri + strlen("svc:/"), action); 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate severity = LOG_ERR; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if (message == NULL) { 4897c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, 4907c478bd9Sstevel@tonic-gate "Could not log boot message for %s: %s.\n", 4917c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri, uu_strerror(uu_error())); 4927c478bd9Sstevel@tonic-gate } else { 49399b44c3bSlianep /* 49499b44c3bSlianep * All significant errors should to go to syslog to 49599b44c3bSlianep * communicate appropriate information even for systems 49699b44c3bSlianep * without a console connected during boot. Send the 49799b44c3bSlianep * message to stderr only if the severity is lower than 49899b44c3bSlianep * (indicated by >) LOG_ERR. 49999b44c3bSlianep */ 50099b44c3bSlianep if (!st->st_log_login_reached && severity > LOG_ERR) { 5017c478bd9Sstevel@tonic-gate /*LINTED*/ 5027c478bd9Sstevel@tonic-gate if (fprintf(stderr, message) < 0) 5037c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not log for %s: " 5047c478bd9Sstevel@tonic-gate "fprintf() failed with %s.\n", 5057c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri, strerror(errno)); 5067c478bd9Sstevel@tonic-gate } else { 5077c478bd9Sstevel@tonic-gate log_framework(severity, "%s %s\n", 5087c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri + strlen("svc:/"), action); 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate uu_free(message); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * log_console - log a message to the consoles and to syslog 5177c478bd9Sstevel@tonic-gate * 5187c478bd9Sstevel@tonic-gate * This logs a message as-is to the console (and auxiliary consoles), 5197c478bd9Sstevel@tonic-gate * as well as to the master restarter log. 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 5227c478bd9Sstevel@tonic-gate void 5237c478bd9Sstevel@tonic-gate log_console(int severity, const char *format, ...) 5247c478bd9Sstevel@tonic-gate { 5257c478bd9Sstevel@tonic-gate va_list args; 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate va_start(args, format); 5287c478bd9Sstevel@tonic-gate vlog_prefix(severity, "", format, args); 5297c478bd9Sstevel@tonic-gate va_end(args); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate va_start(args, format); 5327c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, args); 5337c478bd9Sstevel@tonic-gate va_end(args); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * void log_init() 5387c478bd9Sstevel@tonic-gate * 5397c478bd9Sstevel@tonic-gate * Set up the log files, if necessary, for the current invocation. This 5407c478bd9Sstevel@tonic-gate * function should be called before any other functions in this file. Set the 5417c478bd9Sstevel@tonic-gate * syslog(3C) logging mask such that severities of the importance of 5427c478bd9Sstevel@tonic-gate * LOG_NOTICE and above are passed through, but lower severity messages are 5437c478bd9Sstevel@tonic-gate * masked out. 5447c478bd9Sstevel@tonic-gate * 5457c478bd9Sstevel@tonic-gate * It may be called multiple times to change the logging configuration due to 5467c478bd9Sstevel@tonic-gate * administrative request. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate void 5497c478bd9Sstevel@tonic-gate log_init() 5507c478bd9Sstevel@tonic-gate { 5517c478bd9Sstevel@tonic-gate int dirfd, logfd; 5527c478bd9Sstevel@tonic-gate char *dir; 5537c478bd9Sstevel@tonic-gate struct stat sb; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (st->st_start_time.tv_sec == 0) { 5567c478bd9Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 5577c478bd9Sstevel@tonic-gate st->st_start_time.tv_sec = time(NULL); 5587c478bd9Sstevel@tonic-gate } else { 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * We need to special-case the BOOT_TIME utmp entry, and 5617c478bd9Sstevel@tonic-gate * drag that value out of the kernel if it's there. 5627c478bd9Sstevel@tonic-gate */ 5637c478bd9Sstevel@tonic-gate kstat_ctl_t *kc; 5647c478bd9Sstevel@tonic-gate kstat_t *ks; 5657c478bd9Sstevel@tonic-gate kstat_named_t *boot; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (((kc = kstat_open()) != 0) && 5687c478bd9Sstevel@tonic-gate ((ks = kstat_lookup(kc, "unix", 0, "system_misc")) 5697c478bd9Sstevel@tonic-gate != NULL) && 5707c478bd9Sstevel@tonic-gate (kstat_read(kc, ks, NULL) != -1) && 5717c478bd9Sstevel@tonic-gate ((boot = kstat_data_lookup(ks, "boot_time")) != 5727c478bd9Sstevel@tonic-gate NULL)) { 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * If we're here, then we've successfully found 5757c478bd9Sstevel@tonic-gate * the boot_time kstat... use its value. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate st->st_start_time.tv_sec = boot->value.ul; 5787c478bd9Sstevel@tonic-gate } else { 5797c478bd9Sstevel@tonic-gate st->st_start_time.tv_sec = time(NULL); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (kc) 5837c478bd9Sstevel@tonic-gate (void) kstat_close(kc); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * Establish our timezone if the appropriate directory is available. 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate if (!st->st_log_timezone_known && stat(FS_TIMEZONE_DIR, &sb) == 0) { 5917c478bd9Sstevel@tonic-gate tzset(); 5927c478bd9Sstevel@tonic-gate st->st_log_timezone_known = 1; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate * Establish our locale if the appropriate directory is available. Set 5977c478bd9Sstevel@tonic-gate * the locale string from the environment so we can extract template 5987c478bd9Sstevel@tonic-gate * information correctly, if the locale directories aren't yet 5997c478bd9Sstevel@tonic-gate * available. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate if (st->st_locale != NULL) 6027c478bd9Sstevel@tonic-gate free(st->st_locale); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if ((st->st_locale = getenv("LC_ALL")) == NULL) 6057c478bd9Sstevel@tonic-gate if ((st->st_locale = getenv("LC_MESSAGES")) == NULL) 6067c478bd9Sstevel@tonic-gate st->st_locale = getenv("LANG"); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (!st->st_log_locale_known && stat(FS_LOCALE_DIR, &sb) == 0) { 6097c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 6107c478bd9Sstevel@tonic-gate st->st_locale = setlocale(LC_MESSAGES, ""); 6117c478bd9Sstevel@tonic-gate if (st->st_locale) 6127c478bd9Sstevel@tonic-gate st->st_log_locale_known = 1; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate if (st->st_locale) { 6187c478bd9Sstevel@tonic-gate st->st_locale = safe_strdup(st->st_locale); 6197c478bd9Sstevel@tonic-gate xstr_sanitize(st->st_locale); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (logfile) { 6237c478bd9Sstevel@tonic-gate (void) fclose(logfile); 6247c478bd9Sstevel@tonic-gate logfile = NULL; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * Set syslog(3C) behaviour in all cases. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate closelog(); 6317c478bd9Sstevel@tonic-gate openlog("svc.startd", LOG_PID | LOG_CONS, LOG_DAEMON); 6327c478bd9Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_NOTICE)); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if ((dirfd = log_dir_writeable(LOG_PREFIX_NORMAL)) == -1) { 6357c478bd9Sstevel@tonic-gate if ((dirfd = log_dir_writeable(LOG_PREFIX_EARLY)) == -1) 6367c478bd9Sstevel@tonic-gate return; 6377c478bd9Sstevel@tonic-gate else 6387c478bd9Sstevel@tonic-gate dir = LOG_PREFIX_EARLY; 6397c478bd9Sstevel@tonic-gate } else { 6407c478bd9Sstevel@tonic-gate dir = LOG_PREFIX_NORMAL; 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate st->st_log_prefix = dir; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate (void) umask(fmask); 6467c478bd9Sstevel@tonic-gate if ((logfd = openat(dirfd, STARTD_DEFAULT_LOG, O_CREAT | O_RDWR, 6477c478bd9Sstevel@tonic-gate 0644)) == -1) { 6487c478bd9Sstevel@tonic-gate (void) close(dirfd); 6497c478bd9Sstevel@tonic-gate (void) umask(dmask); 6507c478bd9Sstevel@tonic-gate return; 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate (void) close(dirfd); 6547c478bd9Sstevel@tonic-gate (void) umask(dmask); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if ((logfile = fdopen(logfd, "a")) == NULL) 6577c478bd9Sstevel@tonic-gate if (errno != EROFS) 6587c478bd9Sstevel@tonic-gate log_error(LOG_WARNING, "can't open logfile %s/%s", 6597c478bd9Sstevel@tonic-gate dir, STARTD_DEFAULT_LOG); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (logfile && 6627c478bd9Sstevel@tonic-gate fcntl(fileno(logfile), F_SETFD, FD_CLOEXEC) == -1) 6637c478bd9Sstevel@tonic-gate log_error(LOG_WARNING, 6647c478bd9Sstevel@tonic-gate "couldn't mark logfile close-on-exec: %s\n", 6657c478bd9Sstevel@tonic-gate strerror(errno)); 6667c478bd9Sstevel@tonic-gate } 667