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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*0d421f66SBryan Cantrill /* 28*0d421f66SBryan Cantrill * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29*0d421f66SBryan Cantrill */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * utmpx.c - utmpx utility routines 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * Since svc.startd(1M) places utmpx records for its launched instances, it must 357c478bd9Sstevel@tonic-gate * also mark them as dead once completed. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/wait.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <errno.h> 437c478bd9Sstevel@tonic-gate #include <pthread.h> 447c478bd9Sstevel@tonic-gate #include <sac.h> 457c478bd9Sstevel@tonic-gate #include <string.h> 467c478bd9Sstevel@tonic-gate #include <strings.h> 477c478bd9Sstevel@tonic-gate #include <time.h> 487c478bd9Sstevel@tonic-gate #include <unistd.h> 497c478bd9Sstevel@tonic-gate #include <utmpx.h> 507c478bd9Sstevel@tonic-gate #include <fcntl.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include "startd.h" 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate static const char rlevels[] = { 'S', '0', '1', '2', '3', '4', '5', '6', 0 }; 557c478bd9Sstevel@tonic-gate static int n_prev[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static pthread_mutex_t utmpx_lock; 587c478bd9Sstevel@tonic-gate static int utmpx_truncated = 0; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #define USEC_PER_MSEC 1000 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate int 637c478bd9Sstevel@tonic-gate utmpx_mark_init(pid_t pid, char *prefix) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate struct utmpx ut, *oldu; 667c478bd9Sstevel@tonic-gate int tmplen; 677c478bd9Sstevel@tonic-gate int ret; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate while (st->st_initial && !utmpx_truncated) 707c478bd9Sstevel@tonic-gate (void) usleep(200 * USEC_PER_MSEC); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Clean out any preexisting records for this PID, as they must be 747c478bd9Sstevel@tonic-gate * inaccurate. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate utmpx_mark_dead(pid, 0, B_TRUE); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Construct a new record with the appropriate prefix. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate (void) memset(&ut, 0, sizeof (ut)); 827c478bd9Sstevel@tonic-gate (void) strncpy(ut.ut_user, ".startd", sizeof (ut.ut_user)); 837c478bd9Sstevel@tonic-gate ut.ut_pid = pid; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate ut.ut_id[0] = ut.ut_id[1] = ut.ut_id[2] = ut.ut_id[3] = (char)SC_WILDC; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate for (ret = 0; ret < strlen(prefix); ret++) 887c478bd9Sstevel@tonic-gate ut.ut_id[ret] = prefix[ret]; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate ut.ut_type = INIT_PROCESS; 917c478bd9Sstevel@tonic-gate (void) time(&ut.ut_tv.tv_sec); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate for (;;) { 947c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 957c478bd9Sstevel@tonic-gate setutxent(); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate if ((oldu = getutxid(&ut)) != NULL) { 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Copy in the old "line" and "host" fields. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate bcopy(oldu->ut_line, ut.ut_line, sizeof (ut.ut_line)); 1027c478bd9Sstevel@tonic-gate bcopy(oldu->ut_host, ut.ut_host, sizeof (ut.ut_host)); 1037c478bd9Sstevel@tonic-gate ut.ut_syslen = (tmplen = strlen(ut.ut_host)) ? 1047c478bd9Sstevel@tonic-gate min(tmplen + 1, sizeof (ut.ut_host)) : 0; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (makeutx(&ut) != NULL) 1087c478bd9Sstevel@tonic-gate break; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate if (errno != EROFS) 1117c478bd9Sstevel@tonic-gate log_framework(LOG_WARNING, 1127c478bd9Sstevel@tonic-gate "makeutx failed, retrying: %s\n", strerror(errno)); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate (void) sleep(1); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, &ut); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate endutxent(); 1227c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate return (ret); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate void 1287c478bd9Sstevel@tonic-gate utmpx_mark_dead(pid_t pid, int status, boolean_t blocking) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate struct utmpx *up; 1317c478bd9Sstevel@tonic-gate int logged = 0; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate for (;;) { 1347c478bd9Sstevel@tonic-gate int found = 0; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 1377c478bd9Sstevel@tonic-gate setutxent(); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate while (up = getutxent()) { 1407c478bd9Sstevel@tonic-gate if (up->ut_pid == pid) { 1417c478bd9Sstevel@tonic-gate found = 1; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate if (up->ut_type == DEAD_PROCESS) { 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * Cleaned up elsewhere. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate endutxent(); 1487c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 1497c478bd9Sstevel@tonic-gate return; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate up->ut_type = DEAD_PROCESS; 1537c478bd9Sstevel@tonic-gate up->ut_exit.e_termination = WTERMSIG(status); 1547c478bd9Sstevel@tonic-gate up->ut_exit.e_exit = WEXITSTATUS(status); 1557c478bd9Sstevel@tonic-gate (void) time(&up->ut_tv.tv_sec); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (pututxline(up) != NULL) { 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Now attempt to add to the end of the 1607c478bd9Sstevel@tonic-gate * wtmp and wtmpx files. Do not create 1617c478bd9Sstevel@tonic-gate * if they don't already exist. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, up); 1647c478bd9Sstevel@tonic-gate endutxent(); 1657c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate return; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate endutxent(); 1737c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (!found || !blocking) 1767c478bd9Sstevel@tonic-gate return; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (!logged) { 1797c478bd9Sstevel@tonic-gate log_framework(LOG_INFO, "retrying utmpx_dead on PID " 1807c478bd9Sstevel@tonic-gate "%ld\n", pid); 1817c478bd9Sstevel@tonic-gate logged++; 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate (void) sleep(1); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate static void 1897c478bd9Sstevel@tonic-gate utmpx_check() 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate struct stat sb; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (stat(_UTMPX_FILE, &sb) == 0 && 1947c478bd9Sstevel@tonic-gate sb.st_mode != (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) 1957c478bd9Sstevel@tonic-gate (void) chmod(_UTMPX_FILE, S_IRUSR | S_IWUSR | S_IRGRP | 1967c478bd9Sstevel@tonic-gate S_IROTH); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate if (stat(_WTMPX_FILE, &sb) == 0 && 1997c478bd9Sstevel@tonic-gate sb.st_mode != (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) 2007c478bd9Sstevel@tonic-gate (void) chmod(_WTMPX_FILE, S_IRUSR | S_IWUSR | S_IRGRP | 2017c478bd9Sstevel@tonic-gate S_IROTH); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * Retrieve the runlevel utmpx entry if there is one; used to recover 2067c478bd9Sstevel@tonic-gate * state when svc.startd is restarted. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate char 2097c478bd9Sstevel@tonic-gate utmpx_get_runlevel(void) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate struct utmpx *up; 2127c478bd9Sstevel@tonic-gate char rl = '\0'; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 2157c478bd9Sstevel@tonic-gate setutxent(); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate while (up = getutxent()) { 2187c478bd9Sstevel@tonic-gate if (up->ut_type == RUN_LVL && 2197c478bd9Sstevel@tonic-gate sscanf(up->ut_line, RUNLVL_MSG, &rl) == 1) 2207c478bd9Sstevel@tonic-gate break; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate endutxent(); 2237c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate return (rl); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate void 2297c478bd9Sstevel@tonic-gate utmpx_set_runlevel(char runlevel, char oldrl, boolean_t do_bump) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate struct utmpx u; 2327c478bd9Sstevel@tonic-gate struct utmpx *oup; 2337c478bd9Sstevel@tonic-gate size_t tmplen; 2347c478bd9Sstevel@tonic-gate int i; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (runlevel == 's') 2377c478bd9Sstevel@tonic-gate runlevel = 'S'; 2387c478bd9Sstevel@tonic-gate if (oldrl == 's') 2397c478bd9Sstevel@tonic-gate oldrl = 'S'; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate bzero(&u, sizeof (struct utmpx)); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate u.ut_id[0] = u.ut_id[1] = u.ut_id[2] = u.ut_id[3] = '\0'; 2447c478bd9Sstevel@tonic-gate u.ut_pid = 0; 2457c478bd9Sstevel@tonic-gate u.ut_type = RUN_LVL; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate (void) time(&u.ut_tv.tv_sec); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 2507c478bd9Sstevel@tonic-gate setutxent(); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if ((oup = getutxid(&u)) != NULL) { 2537c478bd9Sstevel@tonic-gate bcopy(oup->ut_host, u.ut_host, sizeof (u.ut_host)); 2547c478bd9Sstevel@tonic-gate bcopy(oup->ut_line, u.ut_line, sizeof (u.ut_line)); 2557c478bd9Sstevel@tonic-gate bcopy(oup->ut_user, u.ut_user, sizeof (u.ut_user)); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate tmplen = strlen(u.ut_host); 2587c478bd9Sstevel@tonic-gate if (tmplen) 2597c478bd9Sstevel@tonic-gate u.ut_syslen = min(tmplen + 1, sizeof (u.ut_host)); 2607c478bd9Sstevel@tonic-gate else 2617c478bd9Sstevel@tonic-gate u.ut_syslen = 0; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate if (oldrl != '\0') 2657c478bd9Sstevel@tonic-gate u.ut_exit.e_exit = oldrl; 2667c478bd9Sstevel@tonic-gate else if (oup != NULL) 2677c478bd9Sstevel@tonic-gate u.ut_exit.e_exit = oup->ut_exit.e_termination; 2687c478bd9Sstevel@tonic-gate else 2697c478bd9Sstevel@tonic-gate u.ut_exit.e_exit = '0'; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate u.ut_exit.e_termination = runlevel; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate for (i = 0; rlevels[i] != '\0'; ++i) { 2747c478bd9Sstevel@tonic-gate if (rlevels[i] == runlevel) 2757c478bd9Sstevel@tonic-gate break; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate u.ut_pid = n_prev[i]; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (do_bump) { 2817c478bd9Sstevel@tonic-gate for (i = 0; rlevels[i] != '\0'; ++i) { 2827c478bd9Sstevel@tonic-gate if (rlevels[i] == u.ut_exit.e_exit) 2837c478bd9Sstevel@tonic-gate break; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate ++n_prev[i]; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate (void) sprintf(u.ut_line, RUNLVL_MSG, runlevel); 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate if (pututxline(&u) == NULL) { 2927c478bd9Sstevel@tonic-gate endutxent(); 2937c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate return; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, &u); 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate endutxent(); 3017c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate utmpx_check(); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate static void 3077c478bd9Sstevel@tonic-gate utmpx_write_entry(short type, const char *msg, time_t tstamp) 3087c478bd9Sstevel@tonic-gate { 3097c478bd9Sstevel@tonic-gate struct utmpx u; 3107c478bd9Sstevel@tonic-gate struct utmpx *oup; 3117c478bd9Sstevel@tonic-gate size_t tmplen; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate bzero(&u, sizeof (struct utmpx)); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate u.ut_id[0] = u.ut_id[1] = u.ut_id[2] = u.ut_id[3] = '\0'; 3167c478bd9Sstevel@tonic-gate u.ut_pid = 0; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate u.ut_exit.e_termination = WTERMSIG(0); 3197c478bd9Sstevel@tonic-gate u.ut_exit.e_exit = WEXITSTATUS(0); 3207c478bd9Sstevel@tonic-gate u.ut_type = type; 3217c478bd9Sstevel@tonic-gate u.ut_tv.tv_sec = tstamp; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 3247c478bd9Sstevel@tonic-gate setutxent(); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if ((oup = getutxid(&u)) != NULL) { 3277c478bd9Sstevel@tonic-gate bcopy(oup->ut_user, u.ut_user, sizeof (u.ut_user)); 3287c478bd9Sstevel@tonic-gate bcopy(oup->ut_line, u.ut_line, sizeof (u.ut_line)); 3297c478bd9Sstevel@tonic-gate bcopy(oup->ut_host, u.ut_host, sizeof (u.ut_host)); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate tmplen = strlen(u.ut_host); 3327c478bd9Sstevel@tonic-gate if (tmplen) 3337c478bd9Sstevel@tonic-gate u.ut_syslen = min(tmplen + 1, sizeof (u.ut_host)); 3347c478bd9Sstevel@tonic-gate else 3357c478bd9Sstevel@tonic-gate u.ut_syslen = 0; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate (void) sprintf(u.ut_line, "%.12s", msg); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if (pututxline(&u) == NULL) { 3417c478bd9Sstevel@tonic-gate endutxent(); 3427c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate return; 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate updwtmpx(WTMPX_FILE, &u); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate endutxent(); 3507c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate utmpx_check(); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate void 3567c478bd9Sstevel@tonic-gate utmpx_write_boottime(void) 3577c478bd9Sstevel@tonic-gate { 3587c478bd9Sstevel@tonic-gate time_t tstamp; 3597c478bd9Sstevel@tonic-gate struct stat stbuf; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * The DOWN_TIME record tracks when the OS became unavailable 3637c478bd9Sstevel@tonic-gate * during the previous boot. We stat(2) WTMPX and check its 3647c478bd9Sstevel@tonic-gate * attributes to determine when (and how) the OS became 3657c478bd9Sstevel@tonic-gate * unavailable. If the file is empty, skip writing a DOWN_TIME 3667c478bd9Sstevel@tonic-gate * record. Otherwise, check the access and modify times and 3677c478bd9Sstevel@tonic-gate * use whichever is latest as the time that the OS became 3687c478bd9Sstevel@tonic-gate * unavailable. If st_atime is latest, the instance crashed or 3697c478bd9Sstevel@tonic-gate * the machine lost power. If st_mtime is latest, the shutdown 3707c478bd9Sstevel@tonic-gate * was controlled. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate if (stat(WTMPX_FILE, &stbuf) == 0 && stbuf.st_size != 0) { 3737c478bd9Sstevel@tonic-gate tstamp = (stbuf.st_atime >= stbuf.st_mtime) ? 3747c478bd9Sstevel@tonic-gate stbuf.st_atime : stbuf.st_mtime; 3757c478bd9Sstevel@tonic-gate utmpx_write_entry(DOWN_TIME, DOWN_MSG, tstamp); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * The boot time (or start time, for a non-global zone) is retrieved in 3807c478bd9Sstevel@tonic-gate * log_init(). 3817c478bd9Sstevel@tonic-gate */ 3827c478bd9Sstevel@tonic-gate tstamp = st->st_start_time.tv_sec; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate utmpx_write_entry(BOOT_TIME, BOOT_MSG, tstamp); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * void utmpx_clear_old(void) 3897c478bd9Sstevel@tonic-gate * At boot and only at boot, truncate the utmpx file. 3907c478bd9Sstevel@tonic-gate * 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate void 3937c478bd9Sstevel@tonic-gate utmpx_clear_old(void) 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate int fd; 3967c478bd9Sstevel@tonic-gate mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate if (!st->st_initial || utmpx_truncated) 3997c478bd9Sstevel@tonic-gate return; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate MUTEX_LOCK(&utmpx_lock); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if ((fd = open(_UTMPX_FILE, 4047c478bd9Sstevel@tonic-gate O_WRONLY | O_CREAT | O_TRUNC, mode)) != -1) { 4057c478bd9Sstevel@tonic-gate (void) fchmod(fd, mode); /* force mode regardless of umask() */ 4067c478bd9Sstevel@tonic-gate (void) fchown(fd, 0, 2); /* force owner to root/bin */ 4077c478bd9Sstevel@tonic-gate (void) close(fd); 4087c478bd9Sstevel@tonic-gate } else { 4097c478bd9Sstevel@tonic-gate log_framework(LOG_NOTICE, "Unable to create %s: %s\n", 4107c478bd9Sstevel@tonic-gate _UTMPX_FILE, strerror(errno)); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate utmpx_truncated = 1; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&utmpx_lock); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate void 4197c478bd9Sstevel@tonic-gate utmpx_init() 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&utmpx_lock, &mutex_attrs); 4227c478bd9Sstevel@tonic-gate } 423*0d421f66SBryan Cantrill 424*0d421f66SBryan Cantrill void 425*0d421f66SBryan Cantrill utmpx_prefork() 426*0d421f66SBryan Cantrill { 427*0d421f66SBryan Cantrill /* 428*0d421f66SBryan Cantrill * The libc utmpx routines are entirely MT-unsafe; we must assure 429*0d421f66SBryan Cantrill * that no other thread is in these routines when we fork lest we 430*0d421f66SBryan Cantrill * leave the child with inconsistent library state. 431*0d421f66SBryan Cantrill */ 432*0d421f66SBryan Cantrill MUTEX_LOCK(&utmpx_lock); 433*0d421f66SBryan Cantrill } 434*0d421f66SBryan Cantrill 435*0d421f66SBryan Cantrill void 436*0d421f66SBryan Cantrill utmpx_postfork() 437*0d421f66SBryan Cantrill { 438*0d421f66SBryan Cantrill MUTEX_UNLOCK(&utmpx_lock); 439*0d421f66SBryan Cantrill } 440