16429Svs195195 /* 26429Svs195195 * CDDL HEADER START 36429Svs195195 * 46429Svs195195 * The contents of this file are subject to the terms of the 56429Svs195195 * Common Development and Distribution License (the "License"). 66429Svs195195 * You may not use this file except in compliance with the License. 76429Svs195195 * 86429Svs195195 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96429Svs195195 * or http://www.opensolaris.org/os/licensing. 106429Svs195195 * See the License for the specific language governing permissions 116429Svs195195 * and limitations under the License. 126429Svs195195 * 136429Svs195195 * When distributing Covered Code, include this CDDL HEADER in each 146429Svs195195 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156429Svs195195 * If applicable, add the following below this CDDL HEADER, with the 166429Svs195195 * fields enclosed by brackets "[]" replaced with your own identifying 176429Svs195195 * information: Portions Copyright [yyyy] [name of copyright owner] 186429Svs195195 * 196429Svs195195 * CDDL HEADER END 206429Svs195195 */ 216429Svs195195 226429Svs195195 /* 236429Svs195195 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 246429Svs195195 * Use is subject to license terms. 256429Svs195195 */ 266429Svs195195 276429Svs195195 #pragma ident "%Z%%M% %I% %E% SMI" 286429Svs195195 296429Svs195195 #include <stdio.h> 306429Svs195195 #include <string.h> 316429Svs195195 #include <sys/types.h> 326429Svs195195 #include <dirent.h> 336429Svs195195 #include <stdarg.h> 346429Svs195195 #include <stddef.h> 356429Svs195195 #include <stdlib.h> 366429Svs195195 #include <dlfcn.h> 376429Svs195195 #include <door.h> 386429Svs195195 #include <errno.h> 396429Svs195195 #include <fcntl.h> 406429Svs195195 #include <strings.h> 416429Svs195195 #include <unistd.h> 426429Svs195195 #include <synch.h> 436429Svs195195 #include <syslog.h> 446429Svs195195 #include <pthread.h> 456429Svs195195 #include <thread.h> 466429Svs195195 #include <signal.h> 476429Svs195195 #include <limits.h> 486429Svs195195 #include <locale.h> 496429Svs195195 #include <sys/stat.h> 506429Svs195195 #include <sys/systeminfo.h> 516429Svs195195 #include <sys/wait.h> 526429Svs195195 #include <sys/processor.h> 536429Svs195195 #include <ctype.h> 546429Svs195195 #include <poll.h> 556429Svs195195 #include <sys/wait.h> 566429Svs195195 #include <dirent.h> 576429Svs195195 #include <kstat.h> 586429Svs195195 #include <libscf.h> 596429Svs195195 #include <sys/pset.h> 606429Svs195195 #include <sys/param.h> 616429Svs195195 #include <sys/corectl.h> 626429Svs195195 #include <libgen.h> 636429Svs195195 #include <priv_utils.h> 646429Svs195195 #include <fpsapi.h> 656429Svs195195 666429Svs195195 #include "fpsd.h" 676429Svs195195 #include "messages.h" 686429Svs195195 696429Svs195195 /* Only messages of priority 'debug_level' and lower will be logged */ 706429Svs195195 int debug_level = DFLT_DBG_LVL; 716429Svs195195 726429Svs195195 fpsd_t fpsd; 736429Svs195195 mach_conf_t fpsd_conf; 746429Svs195195 char fps_tst_path[MAXPATHLEN + MAXNAMELEN]; 756429Svs195195 766429Svs195195 void terminate_process(); 776429Svs195195 786429Svs195195 /* Local Static Variables */ 796429Svs195195 806429Svs195195 static int door_id = -1; 816429Svs195195 static char *str_fps_fmri = NULL; 826429Svs195195 836429Svs195195 /* Local static functions */ 846429Svs195195 856429Svs195195 static int check_if_supported_CPU(char *cpu_brand, char *arch); 866429Svs195195 static int read_conf_props(); 876429Svs195195 static void fpsd_fini(); 886429Svs195195 static int reprobe_and_reread_config(); 896429Svs195195 static int fpsd_probe_config(); 906429Svs195195 static int fpsd_probe(mach_conf_t *m_stat); 916429Svs195195 926429Svs195195 936429Svs195195 /* ARGSUSED */ 946429Svs195195 void 956429Svs195195 sig_hup_handler(int sig, siginfo_t *siginfo, void *sigctx) 966429Svs195195 { 976429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 986429Svs195195 SIGNAL_INFO, "HUP", SIGHUP); 996429Svs195195 fpsd_read_config(); 1006429Svs195195 } 1016429Svs195195 1026429Svs195195 void 1036429Svs195195 fpsd_read_config() 1046429Svs195195 { 1056429Svs195195 int ret; 1066429Svs195195 1076429Svs195195 ret = reprobe_and_reread_config(); 1086429Svs195195 if (NO_CPUS_2_TEST == ret) { 1096429Svs195195 while (NO_CPUS_2_TEST == ret) { 110*7186Skk158166 (void) sleep(600); 1116429Svs195195 ret = reprobe_and_reread_config(); 1126429Svs195195 } 1136429Svs195195 } 1146429Svs195195 } 1156429Svs195195 1166429Svs195195 static int 1176429Svs195195 reprobe_and_reread_config() 1186429Svs195195 { 1196429Svs195195 int ret; 1206429Svs195195 1216429Svs195195 fpsd.d_conf->m_reprobe = 1; 1226429Svs195195 if (fpsd_probe(fpsd.d_conf) != 0) { 1236429Svs195195 (void) fpsd_message(FPSD_EXIT_ERROR, 1246429Svs195195 FPS_ERROR, UNSUPPORTED_SYSTEM); 1256429Svs195195 } 1266429Svs195195 ret = fpsd_probe_config(); 1276429Svs195195 if (ZERO_INTERVAL == ret) { 1286429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, 1296429Svs195195 FPSD_ZERO_INTVL, fpsd.d_interval); 1306429Svs195195 } 1316429Svs195195 return (ret); 1326429Svs195195 1336429Svs195195 } 1346429Svs195195 1356429Svs195195 static int 1366429Svs195195 daemon_exists() 1376429Svs195195 { 1386429Svs195195 int door_fd; 1396429Svs195195 struct door_info dinfo; 1406429Svs195195 1416429Svs195195 door_fd = open(FPS_DOOR_FILE, O_RDONLY); 1426429Svs195195 if (door_fd < 0) 1436429Svs195195 return (NO_DAEMON); 1446429Svs195195 if (door_info(door_fd, &dinfo) < 0) { 1456429Svs195195 (void) close(door_fd); 1466429Svs195195 return (NO_DAEMON); 1476429Svs195195 } 1486429Svs195195 if ((dinfo.di_attributes & DOOR_REVOKED) || 1496429Svs195195 (dinfo.di_data != (uintptr_t)FPS_DOOR_COOKIE)) { 1506429Svs195195 (void) close(door_fd); 1516429Svs195195 return (NO_DAEMON); 1526429Svs195195 } 1536429Svs195195 if (dinfo.di_target != getpid()) { 1546429Svs195195 /* Daemon exists; different process */ 1556429Svs195195 (void) close(door_fd); 1566429Svs195195 return (DAEMON_EXISTS); 1576429Svs195195 } else { 1586429Svs195195 (void) close(door_fd); 1596429Svs195195 return (DAEMON_EXISTS_AND_SAME_PROC); /* Same process */ 1606429Svs195195 } 1616429Svs195195 1626429Svs195195 } 1636429Svs195195 1646429Svs195195 static int 1656429Svs195195 fps_setup_door(void) 1666429Svs195195 { 1676429Svs195195 1686429Svs195195 struct stat stbuf; 1696429Svs195195 int newfd; 1706429Svs195195 1716429Svs195195 /* Create the door */ 1726429Svs195195 door_id = door_create(fps_door_handler, FPS_DOOR_COOKIE, 0); 1736429Svs195195 1746429Svs195195 if (door_id < 0) { 1756429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, DAEMON_DOOR_FAIL, 1766429Svs195195 strerror(errno)); 1776429Svs195195 return (-1); 1786429Svs195195 } 1796429Svs195195 1806429Svs195195 if (stat(FPS_DOOR_FILE, &stbuf) < 0) { 1816429Svs195195 if ((newfd = creat(FPS_DOOR_FILE, 0600)) < 0) { 1826429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 1836429Svs195195 DAEMON_DOOR_FILE_FAIL, strerror(errno)); 1846429Svs195195 return (-1); 1856429Svs195195 } 1866429Svs195195 (void) close(newfd); 1876429Svs195195 } 1886429Svs195195 1896429Svs195195 if (fattach(door_id, FPS_DOOR_FILE) < 0) { 1906429Svs195195 if ((errno != EBUSY) || (fdetach(FPS_DOOR_FILE) < 0) || 1916429Svs195195 (fattach(door_id, FPS_DOOR_FILE) < 0)) { 1926429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 1936429Svs195195 DAEMON_DOOR_FATTACH_FAIL, 1946429Svs195195 strerror(errno)); 1956429Svs195195 return (-1); 1966429Svs195195 } 1976429Svs195195 } 1986429Svs195195 1996429Svs195195 return (0); 2006429Svs195195 } 2016429Svs195195 2026429Svs195195 void 2036429Svs195195 terminate_process() 2046429Svs195195 { 2056429Svs195195 fpsd_fini(); 2066429Svs195195 if (door_id >= 0) { 2076429Svs195195 (void) door_revoke(door_id); 2086429Svs195195 (void) unlink(FPS_DOOR_FILE); 2096429Svs195195 } 2106429Svs195195 } 2116429Svs195195 2126429Svs195195 static int 2136429Svs195195 become_daemon_init() 2146429Svs195195 { 2156429Svs195195 int pfds[2]; 2166429Svs195195 pid_t pid; 2176429Svs195195 int status; 2186429Svs195195 sigset_t set, oset; 2196429Svs195195 2206429Svs195195 /* 2216429Svs195195 * Block all signals prior to the fork and leave them blocked in 2226429Svs195195 * the parent so we don't get in a situation where the parent gets 2236429Svs195195 * SIGINT and returns non-zero exit status and the child is 2246429Svs195195 * actually running. In the child, restore the signal mask once 2256429Svs195195 * we've done our setsid(). 2266429Svs195195 */ 2276429Svs195195 (void) sigfillset(&set); 2286429Svs195195 (void) sigdelset(&set, SIGABRT); 2296429Svs195195 (void) sigdelset(&set, SIGHUP); 2306429Svs195195 (void) sigprocmask(SIG_BLOCK, &set, &oset); 2316429Svs195195 2326429Svs195195 2336429Svs195195 if (pipe(pfds) == -1) 2346429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_PIPE_FAIL, 2356429Svs195195 strerror(errno)); 2366429Svs195195 2376429Svs195195 if ((pid = fork()) == -1) 2386429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_FORK_FAIL, 2396429Svs195195 strerror(errno)); 2406429Svs195195 2416429Svs195195 /* 2426429Svs195195 * If we're the parent process, wait for either the child to send 2436429Svs195195 * us the appropriate exit status over the pipe or for the read to 2446429Svs195195 * fail (presumably with 0 for EOF if our child terminated 2456429Svs195195 * abnormally). If the read fails, exit with either the child's 2466429Svs195195 * exit status if it exited or with FPSD_EXIT_ERROR if it died 2476429Svs195195 * from a fatal signal. 2486429Svs195195 */ 2496429Svs195195 if (pid != 0) { /* Parent */ 2506429Svs195195 (void) close(pfds[1]); 2516429Svs195195 2526429Svs195195 if (read(pfds[0], &status, sizeof (status)) == sizeof (status)) 2536429Svs195195 _exit(status); 2546429Svs195195 2556429Svs195195 if (waitpid(pid, &status, 0) == pid && WIFEXITED(status)) 2566429Svs195195 _exit(WEXITSTATUS(status)); 2576429Svs195195 2586429Svs195195 _exit(FPSD_EXIT_ERROR); 2596429Svs195195 } 2606429Svs195195 2616429Svs195195 fpsd.d_pid = getpid(); 2626429Svs195195 (void) sigprocmask(SIG_SETMASK, &oset, NULL); /* Restore signal mask */ 2636429Svs195195 (void) setsid(); 2646429Svs195195 (void) chdir("/"); 2656429Svs195195 (void) umask(022); 2666429Svs195195 (void) close(pfds[0]); 2676429Svs195195 return (pfds[1]); 2686429Svs195195 } 2696429Svs195195 2706429Svs195195 2716429Svs195195 static void 2726429Svs195195 become_daemon_fini(int fd) 2736429Svs195195 { 2746429Svs195195 (void) close(fd); 2756429Svs195195 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 2766429Svs195195 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 2776429Svs195195 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 2786429Svs195195 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 2796429Svs195195 (void) close(fd); 2806429Svs195195 } 2816429Svs195195 2826429Svs195195 } 2836429Svs195195 2846429Svs195195 /* 2856429Svs195195 * Calculates the number of iterations needed for each testable cpu 2866429Svs195195 * based on the frequency and using the following table. This table 2876429Svs195195 * tells how much time it takes for the matrix sizes on a processor 2886429Svs195195 * with frequencies upto 1000MHz/1500 MHz/ 2000 MHz. This data is 2896429Svs195195 * based on profiling done earlier. 2906429Svs195195 * 2916429Svs195195 * f\p\t| 100 200 300 400 500 600 700 800 900 ms 2926429Svs195195 * ====================================================================== 2936429Svs195195 * 1000 1-28 29-50 51-62 63-72 73-81 82-90 91-98 99-105 106-112 2946429Svs195195 * 1500 1-36 37-64 65-80 81-93 94-106 107-115 116-126 127-134 135-144 2956429Svs195195 * 2000 1-39 40-70 71-87 88-102 103-113 114-126 127-137 138-148 149-157 2966429Svs195195 * 2976429Svs195195 * If asc is 0, these iterations will be executed in the descending of 2986429Svs195195 * of matrix size; else the iterations will be executed in the increasing 2996429Svs195195 * order of matrix sizes. This is done to average out the execution time 3006429Svs195195 * as large matrices mean more time to complete the test. 3016429Svs195195 */ 3026429Svs195195 3036429Svs195195 static void 3046429Svs195195 calculateTotalIterations(mach_conf_t *m_stat) 3056429Svs195195 { 3066429Svs195195 const int num_iterations_1K = 112; 3076429Svs195195 const int num_iterations_1500 = 144; 3086429Svs195195 const int num_iterations_2K = 157; 3096429Svs195195 3106429Svs195195 int total_iterations = 0; 3116429Svs195195 int asc = 1; 3126429Svs195195 int i; 3136429Svs195195 int freq; 3146429Svs195195 3156429Svs195195 if (m_stat->m_cpuids_size <= 0) { 3166429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, 3176429Svs195195 FPSD_NO_CPUS_TO_TEST); 3186429Svs195195 } 3196429Svs195195 m_stat->m_num_cpus_to_test = 0; 3206429Svs195195 for (i = 0; i < m_stat->m_cpuids_size; i++) { 3216429Svs195195 if (m_stat->m_cpus[i].disable_test) 3226429Svs195195 continue; 3236429Svs195195 freq = m_stat->m_cpus[i].frequency; 3246429Svs195195 m_stat->m_cpus[i].asc = asc; 3256429Svs195195 if (freq < 1500) { 3266429Svs195195 total_iterations += num_iterations_1K; 3276429Svs195195 m_stat->m_cpus[i].total_iterations = num_iterations_1K; 3286429Svs195195 } else if (freq < 2000) { 3296429Svs195195 total_iterations += num_iterations_1500; 3306429Svs195195 m_stat->m_cpus[i].total_iterations = 3316429Svs195195 num_iterations_1500; 3326429Svs195195 } else { 3336429Svs195195 total_iterations += num_iterations_2K; 3346429Svs195195 m_stat->m_cpus[i].total_iterations = num_iterations_2K; 3356429Svs195195 } 3366429Svs195195 if (asc) { 3376429Svs195195 m_stat->m_cpus[i].previous_iteration = 0; 3386429Svs195195 asc = 0; 3396429Svs195195 } else { 3406429Svs195195 m_stat->m_cpus[i].previous_iteration = 3416429Svs195195 m_stat->m_cpus[i].total_iterations + 1; 3426429Svs195195 asc = 1; 3436429Svs195195 } 3446429Svs195195 m_stat->m_num_cpus_to_test++; 3456429Svs195195 } 3466429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, TOT_ITERS, 3476429Svs195195 total_iterations, m_stat->m_num_cpus_to_test); 3486429Svs195195 fpsd.d_conf->total_iter = total_iterations; 3496429Svs195195 } 3506429Svs195195 3516429Svs195195 /* 3526429Svs195195 * Calculates the time interval between the tests invocation in seconds. 3536429Svs195195 * The goal is to complete once all iterations for all cpus in a 24hr 3546429Svs195195 * period. 3556429Svs195195 */ 3566429Svs195195 3576429Svs195195 static int 3586429Svs195195 calculateTimeInterval() 3596429Svs195195 { 3606429Svs195195 int total_iterations = fpsd.d_conf->total_iter; 3616429Svs195195 int intvl; 3626429Svs195195 3636429Svs195195 if (total_iterations <= 0) { 3646429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, FPSD_MIS_CALCULATIONS, 3656429Svs195195 total_iterations); 3666429Svs195195 } 3676429Svs195195 intvl = (24*60*60) / (total_iterations); 3686429Svs195195 fpsd.d_interval = intvl; 3696429Svs195195 return (1); 3706429Svs195195 } 3716429Svs195195 3726429Svs195195 /* 3736429Svs195195 * Checks if a platform is supported by looking for the corresponding 3746429Svs195195 * binary under /usr/lib/fps/ARCH/CPU_BRAND/fptest; (e.g) ARCH = sun4u, 3756429Svs195195 * CPU_BRAND = UltraSPARC-III; 3766429Svs195195 */ 3776429Svs195195 3786429Svs195195 static int 3796429Svs195195 check_if_supported_CPU(char *cpu_brand, char *arch) 3806429Svs195195 { 3816429Svs195195 (void) snprintf(fps_tst_path, sizeof (fps_tst_path), "%s/%s/%s/%s", 3826429Svs195195 FPS_DIR, arch, cpu_brand, FPS_FPUTST_NAME); 3836429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, FPTST_BIN_PTH, fps_tst_path); 3846429Svs195195 if (access(fps_tst_path, X_OK) == 0) 3856429Svs195195 return (1); 3866429Svs195195 else 3876429Svs195195 return (0); 3886429Svs195195 } 3896429Svs195195 3906429Svs195195 /* 3916429Svs195195 * fpsd_probe(): probes system configuration and 3926429Svs195195 * sets up the fpsd_t structure. 3936429Svs195195 * Returns 0 on success, non-zero on failure. 3946429Svs195195 * 3956429Svs195195 */ 3966429Svs195195 static int 3976429Svs195195 fpsd_probe(mach_conf_t *m_stat) 3986429Svs195195 { 3996429Svs195195 kstat_ctl_t *kstat_ctl; 4006429Svs195195 kstat_t *fps_kstat; 4016429Svs195195 kstat_named_t *kstat_cpu_name; 4026429Svs195195 kstat_named_t *kstat_cpu_freq; 4036429Svs195195 char *cpu_brand = NULL; 4046429Svs195195 int cpu_freq; 4056429Svs195195 int supported; 4066429Svs195195 int i; 4076429Svs195195 int cpuid_index; 4086429Svs195195 4096429Svs195195 processorid_t *cpuid_list; 4106429Svs195195 kid_t ret; 4117101Svs195195 int total_onln = sysconf(_SC_NPROCESSORS_ONLN); 4126429Svs195195 4136429Svs195195 /* probe the system and fill in mach_conf_t elements */ 4146429Svs195195 4156429Svs195195 (void) sysinfo(SI_MACHINE, m_stat->m_machine, 4166429Svs195195 sizeof (m_stat->m_machine) - 1); 4176429Svs195195 4186429Svs195195 if (1 == m_stat->m_reprobe) { 4196429Svs195195 /* Reprobe request */ 4206429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, REPRBE_REQ); 4216429Svs195195 fpsd.d_iteration = 0; 4226429Svs195195 fpsd.d_interval = 0; 4236429Svs195195 fpsd.d_fpuid_index = 0; 4246429Svs195195 m_stat->m_num_on_fpuids = 0; 4256429Svs195195 m_stat->m_cpuids_size = 0; 4266429Svs195195 m_stat->total_iter = 0; 4276429Svs195195 m_stat->m_reprobe = 0; 4286429Svs195195 m_stat->m_num_cpus_to_test = 0; 4296429Svs195195 4306429Svs195195 if (NULL != fpsd.d_ignore_cpuid) { 4316429Svs195195 free(fpsd.d_ignore_cpuid); 4326429Svs195195 } 4336429Svs195195 } 4346429Svs195195 4356429Svs195195 /* 4366429Svs195195 * Find number of online FPUs, and initialize 4376429Svs195195 * m_stat->m_num_on_fpuids. Then collect kstat 4386429Svs195195 * cpu_info for each. 4396429Svs195195 */ 4406429Svs195195 4417101Svs195195 cpuid_list = (processorid_t *)malloc(m_stat->m_num_fpus * 4426429Svs195195 sizeof (processorid_t)); 4436429Svs195195 if (NULL == cpuid_list) { 4446429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, LIBRARY_CALL_FAIL, 4456429Svs195195 "malloc", strerror(errno)); 4466429Svs195195 return (-1); 4476429Svs195195 } 4486429Svs195195 4496429Svs195195 cpuid_index = 0; 4507101Svs195195 for (i = 0; i < m_stat->m_max_cpuid; i++) { 4516429Svs195195 if (p_online(i, P_STATUS) == P_ONLINE) { 4526429Svs195195 cpuid_list[cpuid_index++] = i; 4536429Svs195195 } 4547101Svs195195 if (cpuid_index == total_onln) { 4556429Svs195195 /* Break after all onln cpuids found */ 4566429Svs195195 break; 4576429Svs195195 } 4586429Svs195195 } 4597101Svs195195 m_stat->m_num_on_fpuids = (uint_t)cpuid_index; 4607101Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, NUM_ONLN_CPUS, 4617101Svs195195 m_stat->m_num_on_fpuids); 4626429Svs195195 4636429Svs195195 /* 4646429Svs195195 * Get cpu-brand info all valid cpuids using kstat. 4656429Svs195195 * This is needed to take care 4666429Svs195195 * of mixed cpu scenario 4676429Svs195195 */ 4686429Svs195195 4696429Svs195195 kstat_ctl = kstat_open(); 4706429Svs195195 if (NULL == kstat_ctl) { 4716429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, LIBRARY_CALL_FAIL, 4726429Svs195195 "kstat_open", strerror(errno)); 4736429Svs195195 free(cpuid_list); 4746429Svs195195 return (-1); 4756429Svs195195 } 4766429Svs195195 4776429Svs195195 4786429Svs195195 for (i = 0; i < m_stat->m_num_on_fpuids; i++) { 4796429Svs195195 4806429Svs195195 supported = 0; 4816429Svs195195 fps_kstat = NULL; 4826429Svs195195 4836429Svs195195 fps_kstat = kstat_lookup(kstat_ctl, "cpu_info", 4846429Svs195195 cpuid_list[i], NULL); 4856429Svs195195 if (NULL == fps_kstat) { 4866429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 4876429Svs195195 LIBRARY_CALL_FAIL, "kstat_lookup", 4886429Svs195195 strerror(errno)); 489*7186Skk158166 (void) kstat_close(kstat_ctl); 4906429Svs195195 free(cpuid_list); 4916429Svs195195 return (-1); 4926429Svs195195 } 4936429Svs195195 ret = kstat_read(kstat_ctl, fps_kstat, NULL); 4946429Svs195195 if (ret != -1) { 4956429Svs195195 kstat_cpu_name = kstat_data_lookup(fps_kstat, 4966429Svs195195 "brand"); 4976429Svs195195 if (NULL != kstat_cpu_name) { 4986429Svs195195 cpu_brand = KSTAT_NAMED_STR_PTR( 4996429Svs195195 kstat_cpu_name); 5006429Svs195195 5016429Svs195195 supported = check_if_supported_CPU( 5026429Svs195195 cpu_brand, m_stat->m_machine); 5036429Svs195195 } 5046429Svs195195 } else { 5056429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 5066429Svs195195 CPU_BRAND_PROBE_FAIL, cpuid_list[i]); 5076429Svs195195 (void) kstat_close(kstat_ctl); 5086429Svs195195 free(cpuid_list); 5096429Svs195195 return (-1); 5106429Svs195195 } 5116429Svs195195 if (!supported) { 5126429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 5136429Svs195195 CPU_NOT_SUPPORTED, cpu_brand, 5146429Svs195195 cpuid_list[i]); 5156429Svs195195 m_stat->m_cpus[i].disable_test = 1; 5166429Svs195195 (void) strcpy(m_stat->m_cpus[i].fptest_path, ""); 5176429Svs195195 } else { 5186429Svs195195 m_stat->m_cpus[i].disable_test = 0; 5196429Svs195195 m_stat->m_num_cpus_to_test++; 5206429Svs195195 (void) strlcpy(m_stat->m_cpus[i].fptest_path, 5216429Svs195195 fps_tst_path, 5226429Svs195195 sizeof (m_stat->m_cpus[i].fptest_path)); 5236429Svs195195 } 5246429Svs195195 5256429Svs195195 /* Get frequency */ 5266429Svs195195 5276429Svs195195 kstat_cpu_freq = kstat_data_lookup(fps_kstat, 5286429Svs195195 "clock_MHz"); 5296429Svs195195 if (NULL != kstat_cpu_freq) { 5306429Svs195195 cpu_freq = (int)kstat_cpu_freq->value.l; 5316429Svs195195 } else { 5326429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 5336429Svs195195 FREQ_PROBE_FAIL, cpuid_list[i]); 534*7186Skk158166 (void) kstat_close(kstat_ctl); 5356429Svs195195 free(cpuid_list); 5366429Svs195195 return (-1); 5376429Svs195195 } 5386429Svs195195 5396429Svs195195 m_stat->m_cpus[i].cpuid = cpuid_list[i]; 5406429Svs195195 m_stat->m_cpus[i].frequency = cpu_freq; 5416429Svs195195 (void) strncpy(m_stat->m_cpus[i].brand, cpu_brand, 5426429Svs195195 sizeof (m_stat->m_cpus[i].brand)); 5436429Svs195195 m_stat->m_cpus[i].num_failures = 0; 5446429Svs195195 5456429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, CPU_INFO, 5466429Svs195195 cpuid_list[i], m_stat->m_cpus[i].brand, 5476429Svs195195 cpu_freq); 5486429Svs195195 } 5496429Svs195195 m_stat->m_cpuids_size = (int)m_stat->m_num_on_fpuids; 5506429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 5516429Svs195195 NUM_CPUS_2_TST, m_stat->m_cpuids_size); 5526429Svs195195 free(cpuid_list); 553*7186Skk158166 (void) kstat_close(kstat_ctl); 5546429Svs195195 if (m_stat->m_num_cpus_to_test <= 0) { 5556429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 5566429Svs195195 FPSD_NO_CPUS_TO_TEST); 5576429Svs195195 return (-1); 5586429Svs195195 } 5596429Svs195195 return (0); 5606429Svs195195 } 5616429Svs195195 5626429Svs195195 /* 5636429Svs195195 * returns 1 if cpuid is found in the list of cpus to be 5646429Svs195195 * excluded from testing. 5656429Svs195195 */ 5666429Svs195195 static int 5676429Svs195195 ignore_cpu(int cpuid) 5686429Svs195195 { 5696429Svs195195 int found = 0; 5706429Svs195195 int i; 5716429Svs195195 processorid_t *ignore_cpus = fpsd.d_ignore_cpuid; 5726429Svs195195 for (i = 0; (i < fpsd.num_ignore_cpus) && (!found); i++) { 5736429Svs195195 if (ignore_cpus[i] == cpuid) { 5746429Svs195195 found = 1; 5756429Svs195195 } 5766429Svs195195 } 5776429Svs195195 return (found); 5786429Svs195195 } 5796429Svs195195 5806429Svs195195 /* 5816429Svs195195 * This function parses the string of cpu-ids separated by 5826429Svs195195 * "," , constructs the list and disables testing on those 5836429Svs195195 * cpus. This function assumes fpsd_probe has been called and all 5846429Svs195195 * the machine config info is available in structure fpsd. 5856429Svs195195 */ 5866429Svs195195 5876429Svs195195 static int 5886429Svs195195 parse_and_set_cpu_id_list(char *strCPUs) 5896429Svs195195 { 5906429Svs195195 char *last; 5916429Svs195195 int num_cpus = 0, invalid = 0; 5926429Svs195195 int *tmp_cpus; 5936429Svs195195 int num_cpus_to_test = 0; 5946429Svs195195 int i; 5956429Svs195195 int t_cpuid; 5966429Svs195195 char *cpu_id; 5976429Svs195195 static int first_time = 1; 5986429Svs195195 5996429Svs195195 tmp_cpus = (int *)malloc((int)fpsd.d_conf->m_num_fpus * sizeof (int)); 6006429Svs195195 if (NULL == tmp_cpus) 6016429Svs195195 return (-1); 6026429Svs195195 cpu_id = strtok_r(strCPUs, ",", &last); 6036429Svs195195 6046429Svs195195 while ((NULL != cpu_id) && (!invalid)) { 6056429Svs195195 (void) strtol(cpu_id, (char **)NULL, 10); 6066429Svs195195 if (errno != EINVAL) { 6076429Svs195195 tmp_cpus[num_cpus++] = 6086429Svs195195 (int)strtol(cpu_id, (char **)NULL, 10); 6096429Svs195195 cpu_id = strtok_r(NULL, ",", &last); 6106429Svs195195 } else { 6116429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 6126429Svs195195 INVAL_PROP_VALUE, strCPUs); 6136429Svs195195 invalid = 1; 6146429Svs195195 } 6156429Svs195195 if (num_cpus == fpsd.d_conf->m_num_fpus) { 6167101Svs195195 /* More than max supported cpus */ 6176429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 6186429Svs195195 INVAL_PROP_VALUE, strCPUs); 6196429Svs195195 invalid = 1; 6206429Svs195195 } 6216429Svs195195 } 6226429Svs195195 if (num_cpus) { 6236429Svs195195 fpsd.d_ignore_cpuid = (processorid_t *)malloc( 6246429Svs195195 sizeof (processorid_t) * (int) num_cpus); 6256429Svs195195 if (NULL != fpsd.d_ignore_cpuid) { 6266429Svs195195 for (i = 0; i < num_cpus; i++) { 6276429Svs195195 fpsd.d_ignore_cpuid[i] = tmp_cpus[i]; 6286429Svs195195 } 6296429Svs195195 fpsd.num_ignore_cpus = num_cpus; 6306429Svs195195 } else { 6316429Svs195195 fpsd.num_ignore_cpus = 0; 6326429Svs195195 } 6336429Svs195195 } else if ((num_cpus == 0) || (invalid)) { 6346429Svs195195 fpsd.d_ignore_cpuid = NULL; 6356429Svs195195 fpsd.num_ignore_cpus = 0; 6366429Svs195195 } 6376429Svs195195 free(tmp_cpus); 6386429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, NUM_IGN_CPUS, 6396429Svs195195 fpsd.num_ignore_cpus); 6406429Svs195195 if ((fpsd.num_ignore_cpus > 0) && (fpsd.d_conf->m_cpuids_size > 0)) { 6416429Svs195195 for (i = 0; i < fpsd.d_conf->m_cpuids_size; i++) { 6426429Svs195195 t_cpuid = fpsd.d_conf->m_cpus[i].cpuid; 6436429Svs195195 if (ignore_cpu(t_cpuid)) { 6446429Svs195195 fpsd.d_conf->m_cpus[i].disable_test = 1; 6456429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 6466429Svs195195 IGN_CPUS, t_cpuid); 6476429Svs195195 } else { 6486429Svs195195 num_cpus_to_test++; 6496429Svs195195 } 6506429Svs195195 } 6516429Svs195195 fpsd.d_conf->m_num_cpus_to_test = num_cpus_to_test; 6526429Svs195195 if (num_cpus_to_test <= 0) { 6536429Svs195195 if (1 == first_time) { 6546429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 6556429Svs195195 ALL_CPUS_EXCLDED); 6566429Svs195195 first_time = 0; 6576429Svs195195 } else { 6586429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 6596429Svs195195 ALL_CPUS_EXCLDED); 6606429Svs195195 } 6616429Svs195195 return (NO_CPUS_2_TEST); 6626429Svs195195 } 6636429Svs195195 } 6646429Svs195195 first_time = 1; 6656429Svs195195 return (0); 6666429Svs195195 } 6676429Svs195195 6686429Svs195195 #define CLEAN_UP_SCF_STUFF { \ 6696429Svs195195 if (scf_handle_p) { \ 670*7186Skk158166 (void) scf_handle_unbind(scf_handle_p); \ 6716429Svs195195 scf_handle_destroy(scf_handle_p); \ 6726429Svs195195 } \ 6736429Svs195195 if (inst) \ 6746429Svs195195 scf_instance_destroy(inst); \ 6756429Svs195195 if (pg) \ 6766429Svs195195 scf_pg_destroy(pg); \ 6776429Svs195195 if (scf_prop_p) \ 6786429Svs195195 scf_property_destroy(scf_prop_p); \ 6796429Svs195195 if (value) \ 6806429Svs195195 scf_value_destroy(value); \ 6816429Svs195195 } 6826429Svs195195 6836429Svs195195 /* Read properties from SMF configuration repository using libscf APIs */ 6846429Svs195195 6856429Svs195195 static int 6866429Svs195195 read_conf_props() 6876429Svs195195 { 6886429Svs195195 scf_handle_t *scf_handle_p; 6896429Svs195195 scf_property_t *scf_prop_p = NULL; 6906429Svs195195 scf_instance_t *inst = NULL; 6916429Svs195195 scf_propertygroup_t *pg = NULL; 6926429Svs195195 scf_value_t *value = NULL; 6936429Svs195195 int ret_val = -1; 6946429Svs195195 int val; 6956429Svs195195 int64_t intvl; 6966429Svs195195 int name_len; 6976429Svs195195 char *strCPUs; 6986429Svs195195 6996429Svs195195 scf_handle_p = scf_handle_create(SCF_VERSION); 7006429Svs195195 if ((NULL != scf_handle_p) && (NULL != str_fps_fmri)) { 7016429Svs195195 if (scf_handle_bind(scf_handle_p) != -1) { 7026429Svs195195 inst = scf_instance_create(scf_handle_p); 7036429Svs195195 pg = scf_pg_create(scf_handle_p); 7046429Svs195195 scf_prop_p = scf_property_create(scf_handle_p); 7056429Svs195195 if ((NULL == inst) || (NULL == pg) || 7066429Svs195195 (NULL == scf_prop_p)) { 7076429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7086429Svs195195 CREATE_FAIL, 7096429Svs195195 scf_strerror(scf_error())); 7106429Svs195195 CLEAN_UP_SCF_STUFF 7116429Svs195195 return (-1); 7126429Svs195195 } 7136429Svs195195 val = scf_handle_decode_fmri(scf_handle_p, 7146429Svs195195 str_fps_fmri, 7156429Svs195195 NULL, NULL, inst, pg, scf_prop_p, 0); 7166429Svs195195 if (val != 0) { 7176429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7186429Svs195195 HANDLE_DECODE_FAIL, 7196429Svs195195 scf_strerror(scf_error())); 7206429Svs195195 CLEAN_UP_SCF_STUFF 7216429Svs195195 return (-1); 7226429Svs195195 } 7236429Svs195195 val = scf_instance_get_pg_composed(inst, NULL, 7246429Svs195195 SMF_FPS_PROP_GRP_NAME, pg); 7256429Svs195195 if (val != 0) { 7266429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7276429Svs195195 INSTANCE_PG_GET_FAIL, 7286429Svs195195 scf_strerror(scf_error())); 7296429Svs195195 CLEAN_UP_SCF_STUFF 7306429Svs195195 return (-1); 7316429Svs195195 } 7326429Svs195195 val = scf_pg_get_property(pg, SMF_PROP_INTVL, 7336429Svs195195 scf_prop_p); 7346429Svs195195 /* Read interval property if defined */ 7356429Svs195195 if (val == 0) { 7366429Svs195195 value = scf_value_create(scf_handle_p); 7376429Svs195195 val = scf_property_get_value(scf_prop_p, value); 7386429Svs195195 val = scf_value_get_integer(value, &intvl); 7396429Svs195195 if (intvl != 0) { 7406429Svs195195 fpsd.d_interval = (int)intvl; 7416429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7426429Svs195195 INTVL_VAL, intvl); 7436429Svs195195 ret_val = 0; 7446429Svs195195 } 7456429Svs195195 } else { 7466429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 7476429Svs195195 PROP_UNDEFINED, SMF_PROP_INTVL, 7486429Svs195195 scf_strerror(scf_error())); 7496429Svs195195 } 7506429Svs195195 /* 7516429Svs195195 * Read property "exclude_cpus" if defined - this is 7526429Svs195195 * the array of cpu-ids to be excluded from testing. 7536429Svs195195 */ 7546429Svs195195 val = scf_pg_get_property(pg, SMF_PROP_EXCLD_CPUS, 7556429Svs195195 scf_prop_p); 7566429Svs195195 if (val == 0) { 7576429Svs195195 val = scf_property_get_value(scf_prop_p, value); 7586429Svs195195 name_len = 7596429Svs195195 scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 7606429Svs195195 strCPUs = malloc(name_len +1); 7616429Svs195195 if (NULL == strCPUs) { 7626429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7636429Svs195195 LIBRARY_CALL_FAIL, "malloc"); 7646429Svs195195 CLEAN_UP_SCF_STUFF 7656429Svs195195 return (-1); 7666429Svs195195 } 7676429Svs195195 val = scf_value_get_astring(value, 7686429Svs195195 strCPUs, name_len); 7696429Svs195195 if (strlen(strCPUs) > 0) { 7706429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7716429Svs195195 EXCL_CPUS, strCPUs); 7726429Svs195195 ret_val = 7736429Svs195195 parse_and_set_cpu_id_list( 7746429Svs195195 strCPUs); 7756429Svs195195 } 7766429Svs195195 } else { 7776429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 7786429Svs195195 PROP_UNDEFINED, 7796429Svs195195 SMF_PROP_EXCLD_CPUS, 7806429Svs195195 scf_strerror(scf_error())); 7816429Svs195195 } 7826429Svs195195 } 7836429Svs195195 } 7846429Svs195195 7856429Svs195195 /* Clean up */ 7866429Svs195195 7876429Svs195195 CLEAN_UP_SCF_STUFF 7886429Svs195195 return (ret_val); 7896429Svs195195 } 7906429Svs195195 7916429Svs195195 static int fpsd_init() { 7926429Svs195195 mach_conf_t *m_conf_p; 7936429Svs195195 7946429Svs195195 debug_level = DFLT_DBG_LVL; 7956429Svs195195 fpsd.d_fg = 0; 7966429Svs195195 fpsd.d_daemon = 0; 7976429Svs195195 fpsd.d_ignore_cpuid = NULL; 7986429Svs195195 fpsd.d_iteration = 0; 7996429Svs195195 fpsd.d_interval = 0; 8006429Svs195195 fpsd.d_fpuid_index = 0; 8016429Svs195195 fpsd.d_rootdir = "/"; 8026429Svs195195 fpsd.d_pid = getpid(); 8036429Svs195195 fpsd.d_conf = &fpsd_conf; 8046429Svs195195 fpsd.d_ts_hup = 0; 8056429Svs195195 8066429Svs195195 m_conf_p = fpsd.d_conf; 8076429Svs195195 m_conf_p->m_machine[0] = '\0'; 8086429Svs195195 m_conf_p->m_num_on_fpuids = 0; 8096429Svs195195 m_conf_p->m_cpuids_size = 0; 8106429Svs195195 m_conf_p->total_iter = 0; 8116429Svs195195 m_conf_p->m_reprobe = 0; 8126429Svs195195 m_conf_p->m_num_cpus_to_test = 0; 8137101Svs195195 m_conf_p->m_num_fpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX); 8146429Svs195195 8156429Svs195195 (void) mutex_init(&log_mutex, USYNC_THREAD, NULL); 8166429Svs195195 8177101Svs195195 m_conf_p->m_max_cpuid = (int)sysconf(_SC_CPUID_MAX) + 1; 8186429Svs195195 8196429Svs195195 /* 8206429Svs195195 * Allocate enough memory to accomodate maximum number of CPUs 8216429Svs195195 * supported by this platform. 8226429Svs195195 */ 8236429Svs195195 m_conf_p->m_cpus = malloc(sizeof (fps_cpu_t) * 8247101Svs195195 m_conf_p->m_num_fpus); 8256429Svs195195 if (NULL == m_conf_p->m_cpus) 8266429Svs195195 return (1); 8276429Svs195195 else 8286429Svs195195 return (0); 8296429Svs195195 8306429Svs195195 } 8316429Svs195195 8326429Svs195195 static void 8336429Svs195195 fpsd_fini() { 8346429Svs195195 if (fpsd.d_ignore_cpuid) 8356429Svs195195 free(fpsd.d_ignore_cpuid); 8366429Svs195195 if (fpsd.d_conf->m_cpus) 8376429Svs195195 free(fpsd.d_conf->m_cpus); 8386429Svs195195 } 8396429Svs195195 8406429Svs195195 static int 8416429Svs195195 fpsd_probe_config() 8426429Svs195195 { 8436429Svs195195 int smf_invoked = 0; 8446429Svs195195 int ret = 0; 8456429Svs195195 8466429Svs195195 /* 8476429Svs195195 * Use smf_get_state to get the status of the service to see 8486429Svs195195 * if the status is "online" by now. If so, read the proper- 8496429Svs195195 * ties defined using SCF. 8506429Svs195195 */ 8516429Svs195195 8526429Svs195195 if (NULL != str_fps_fmri) { 8536429Svs195195 const char *smf_state = smf_get_state(str_fps_fmri); 8546429Svs195195 if ((smf_state) && (strncmp(smf_state, 8556429Svs195195 SCF_STATE_STRING_ONLINE, 8566429Svs195195 strlen(SCF_STATE_STRING_ONLINE)) == 0)) { 8576429Svs195195 smf_invoked = 1; 8586429Svs195195 (void) fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 8596429Svs195195 SMF_INVOKED, smf_state); 8606429Svs195195 8616429Svs195195 /* Read SMF properties if invoked thro' SMF */ 8626429Svs195195 ret = read_conf_props(); 8636429Svs195195 if (ret == NO_CPUS_2_TEST) { 8646429Svs195195 return (ret); 8656429Svs195195 } 8666429Svs195195 } else { 8676429Svs195195 (void) fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 8686429Svs195195 CL_INVOKED, (smf_state) ? 8696429Svs195195 smf_state : "No SMF service named fpsd"); 8706429Svs195195 } 8716429Svs195195 } 8726429Svs195195 calculateTotalIterations(fpsd.d_conf); 8736429Svs195195 if ((ret == -1) || (!smf_invoked) || (fpsd.d_interval <= 0)) { 8746429Svs195195 ret = calculateTimeInterval(); 8756429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 8766429Svs195195 PRINT_INTVL, fpsd.d_interval); 8776429Svs195195 if ((ret != 1) || (fpsd.d_interval <= 0)) { 8786429Svs195195 return (ZERO_INTERVAL); 8796429Svs195195 } 8806429Svs195195 } 8816429Svs195195 return (0); 8826429Svs195195 } 8836429Svs195195 8846429Svs195195 int 8856429Svs195195 main(int argc, char **argv) 8866429Svs195195 { 8876429Svs195195 8886429Svs195195 int sig; 8896429Svs195195 sigset_t sigs; 8906429Svs195195 /* Pipe fd to write the status back to parent after becoming daemon */ 8916429Svs195195 int pfd = -1; 8926429Svs195195 int status = FPSD_INIT_SUCCESS; 8936429Svs195195 char rcvsigstr[32]; 8946429Svs195195 int c; 8956429Svs195195 int ret; 8966429Svs195195 struct rlimit rlim; 8976429Svs195195 char path[MAXPATHLEN]; 8986429Svs195195 int probe_status = -1; 8996429Svs195195 const char *progname; 9006429Svs195195 struct sigaction act; 9016429Svs195195 9026429Svs195195 progname = strrchr(argv[0], '/'); 9036429Svs195195 if (NULL != progname) 9046429Svs195195 progname++; 9056429Svs195195 else 9066429Svs195195 progname = argv[0]; 9076429Svs195195 9086429Svs195195 #ifndef TEXT_DOMAIN /* Should be defined via Makefile */ 9096429Svs195195 #define TEXT_DOMAIN "SUNW_FPS" 9106429Svs195195 #endif 9116429Svs195195 9126429Svs195195 (void) setlocale(LC_ALL, ""); 9136429Svs195195 (void) textdomain(TEXT_DOMAIN); 9146429Svs195195 9156429Svs195195 openlog(FPS_DAEMON_NAME, LOG_PID, LOG_DAEMON); 9166429Svs195195 9176429Svs195195 if (fpsd_init()) { 9186429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DAEMON_INIT_FAIL); 9196429Svs195195 } 9206429Svs195195 9216429Svs195195 /* 9226429Svs195195 * Set our per-process core file path to leave core files in 9236429Svs195195 * var/fps/core directory, named after the PID to aid in 9246429Svs195195 * debugging, and make sure that there is no restriction on core 9256429Svs195195 * file size. 9266429Svs195195 */ 9276429Svs195195 9286429Svs195195 if ((ret = access(FPS_CORE_DIR, W_OK)) != 0) { 9296429Svs195195 if ((ret = mkdirp(FPS_CORE_DIR, 0755)) != 0) { 9306429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 9316429Svs195195 CORE_DIR_CREATION_FAILED, 9326429Svs195195 FPS_CORE_DIR, strerror(errno)); 9336429Svs195195 } 9346429Svs195195 } 9356429Svs195195 9366429Svs195195 if (ret == 0) { 9376429Svs195195 (void) snprintf(path, sizeof (path), "%s/core.%s.%%p", 9386429Svs195195 FPS_CORE_DIR, progname); 9396429Svs195195 (void) core_set_process_path(path, strlen(path) + 1, 9406429Svs195195 fpsd.d_pid); 9416429Svs195195 rlim.rlim_cur = RLIM_INFINITY; 9426429Svs195195 rlim.rlim_max = RLIM_INFINITY; 9436429Svs195195 9446429Svs195195 (void) setrlimit(RLIMIT_CORE, &rlim); 9456429Svs195195 } 9466429Svs195195 9476429Svs195195 9486429Svs195195 /* parse arguments */ 9496429Svs195195 while ((c = getopt(argc, argv, "dl:")) != EOF) { 9506429Svs195195 switch (c) { 9516429Svs195195 case 'd': 9526429Svs195195 fpsd.d_fg = 1; 9536429Svs195195 break; 9546429Svs195195 9556429Svs195195 case 'l': 9566429Svs195195 debug_level = atoi(optarg); 9576429Svs195195 if (debug_level < 0) 9586429Svs195195 debug_level = DFLT_DBG_LVL; 9596429Svs195195 break; 9606429Svs195195 9616429Svs195195 default: 9626429Svs195195 fpsd_message(FPSD_EXIT_USAGE, FPS_ERROR, USAGE_MSG, 9636429Svs195195 progname); 9646429Svs195195 break; 9656429Svs195195 } 9666429Svs195195 } 9676429Svs195195 9686429Svs195195 9696429Svs195195 /* 9706429Svs195195 * Reset all of our privilege sets to the minimum set of required 9716429Svs195195 * privileges. We continue to run as root so that files we create 9726429Svs195195 * such as logs and checkpoints are secured in the /var 9736429Svs195195 * filesystem. 9746429Svs195195 */ 9756429Svs195195 if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS, 9766429Svs195195 0, 0, /* run as uid 0 and gid 0 */ 9776429Svs195195 PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, 9786429Svs195195 PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_PROC_OWNER, 9796429Svs195195 PRIV_PROC_PRIOCNTL, PRIV_SYS_ADMIN, PRIV_SYS_CONFIG, 9806429Svs195195 PRIV_SYS_DEVICES, PRIV_SYS_RES_CONFIG, 9816429Svs195195 PRIV_NET_PRIVADDR, NULL) != 0) { 9826429Svs195195 9836429Svs195195 (void) fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, 9846429Svs195195 INSUFFICIENT_PRIVS, progname); 9856429Svs195195 } 9866429Svs195195 9876429Svs195195 9886429Svs195195 if (!fpsd.d_fg) { /* Now become daemon */ 9896429Svs195195 pfd = become_daemon_init(); 9906429Svs195195 } else { 9916429Svs195195 (void) chdir(FPS_DIR); 9926429Svs195195 } 9936429Svs195195 9946429Svs195195 if (daemon_exists()) { 9956429Svs195195 /* 9966429Svs195195 * If another instance of fpsd daemon is already running; 9976429Svs195195 * exit. Should not clean up door file 9986429Svs195195 */ 9996429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, 10006429Svs195195 DAEMON_ALREADY_RUNNING); 10016429Svs195195 } 10026429Svs195195 10036429Svs195195 /* 10046429Svs195195 * Setup door prevents any more instances of fpsd from running. 10056429Svs195195 */ 10066429Svs195195 if (fps_setup_door() == -1) { 10076429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, DOOR_SETUP_FAIL); 10086429Svs195195 } 10096429Svs195195 10106429Svs195195 /* 10116429Svs195195 * Some desktop platforms satisfy E* guidelines. Here CPU power 10126429Svs195195 * management is enabled by default. The scheduling algorithms 10136429Svs195195 * change on these platforms to not to do testing on idle system 10146429Svs195195 * to save power. 10156429Svs195195 */ 10166429Svs195195 init_estar_db(); /* Initialize Estar config data base */ 10176429Svs195195 /* Print message on CPU E* enabled system */ 10186429Svs195195 if (is_estar_system) 10196429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, ESTAR_INFO); 10206429Svs195195 10216429Svs195195 if ((probe_status = fpsd_probe(fpsd.d_conf)) != 0) { 10226429Svs195195 (void) fpsd_message(FPSD_NO_EXIT, FPS_ERROR, 10236429Svs195195 UNSUPPORTED_SYSTEM); 10246429Svs195195 } 10256429Svs195195 10266429Svs195195 if (!fpsd.d_fg) { /* Complete daemonize proces */ 10276429Svs195195 10286429Svs195195 fpsd.d_daemon = 1; 10296429Svs195195 /* 10306429Svs195195 * Now that we're running, if a pipe fd was specified, write an 10316429Svs195195 * exit status to it to indicate that our parent process can 10326429Svs195195 * safely detach. 10336429Svs195195 */ 10346429Svs195195 if (pfd >= 0) { 10356429Svs195195 (void) write(pfd, &status, sizeof (status)); 10366429Svs195195 } 10376429Svs195195 become_daemon_fini(pfd); 10386429Svs195195 10396429Svs195195 } else { 10406429Svs195195 /* 10416429Svs195195 * Mask all signals before creating sched thread. We will 10426429Svs195195 * unmask selective siganls from main thread. This ensures 10436429Svs195195 * that only main thread handles signals. This is done in 10446429Svs195195 * become_daemon() if we had to daemonize. 10456429Svs195195 */ 10466429Svs195195 10476429Svs195195 (void) sigfillset(&sigs); 10486429Svs195195 (void) sigprocmask(SIG_BLOCK, &sigs, NULL); 10496429Svs195195 } 10506429Svs195195 10516429Svs195195 /* 10526429Svs195195 * Give some time for SMF to read the exit status 10536429Svs195195 * of parent and update fpsd fmri state 10546429Svs195195 */ 10556429Svs195195 (void) poll(NULL, 0, 3*1000); 10566429Svs195195 10576429Svs195195 str_fps_fmri = getenv("SMF_FMRI"); 10586429Svs195195 if (NULL != str_fps_fmri) { 10596429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, SMF_INVKD, str_fps_fmri); 10606429Svs195195 } else { 10616429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, CLI_INVKD); 10626429Svs195195 } 10636429Svs195195 10646429Svs195195 if (probe_status != 0) { 10656429Svs195195 /* Exit child proces too */ 10666429Svs195195 10676429Svs195195 if (NULL != str_fps_fmri) { 10686429Svs195195 const char *smf_state = smf_get_state(str_fps_fmri); 10696429Svs195195 if (NULL != smf_state) { 1070*7186Skk158166 (void) smf_disable_instance(str_fps_fmri, 10716429Svs195195 SMF_TEMPORARY); 10726429Svs195195 (void) fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, 10736429Svs195195 FPSD_STATE, smf_state); 10746429Svs195195 (void) poll(NULL, 0, 3*1000); 10756429Svs195195 } 10766429Svs195195 } 10776429Svs195195 terminate_process(); 10786429Svs195195 _exit(FPSD_EXIT_ERROR); 10796429Svs195195 } 10806429Svs195195 10816429Svs195195 act.sa_sigaction = sig_hup_handler; 10826429Svs195195 (void) sigemptyset(&act.sa_mask); 10836429Svs195195 act.sa_flags = SA_SIGINFO; 10846429Svs195195 (void) sigaction(SIGHUP, &act, NULL); 10856429Svs195195 fpsd_read_config(); 10866429Svs195195 10876429Svs195195 /* 10886429Svs195195 * On estar-systems, if interval < MIN_INTERVAL, scheduling tests will 10896429Svs195195 * reset the idle counter and prevent system from going to sleep. 10906429Svs195195 * To avoid this, setting interval to MIN_INTERVAL. 10916429Svs195195 */ 10926429Svs195195 10936429Svs195195 if ((is_estar_system) && (fpsd.d_interval < MIN_INTERVAL)) { 10946429Svs195195 fpsd.d_interval = MIN_INTERVAL; 10956429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_DEBUG, MIN_INTERVAL_MSG, 10966429Svs195195 fpsd.d_interval, MIN_INTERVAL); 10976429Svs195195 } 10986429Svs195195 10996429Svs195195 (void) sigfillset(&sigs); 11006429Svs195195 (void) sigprocmask(SIG_BLOCK, &sigs, NULL); 11016429Svs195195 11026429Svs195195 /* Run scheduling thread */ 11036429Svs195195 if ((ret == 0) && thr_create(NULL, 0, 11046429Svs195195 test_fpu_thr, (void *) NULL, THR_BOUND, NULL) != 0) { 11056429Svs195195 fpsd_message(FPSD_EXIT_ERROR, FPS_ERROR, THR_CREATION_FAIL); 11066429Svs195195 } 11076429Svs195195 11086429Svs195195 /* 11096429Svs195195 * We unmask selective signals here. Besides terminating on 11106429Svs195195 * SIGINT & SIGTERM, we handle SIGHUP that is used to cause 11116429Svs195195 * daemon to re-read the SMF properties. 11126429Svs195195 */ 11136429Svs195195 (void) sigemptyset(&sigs); 11146429Svs195195 (void) sigaddset(&sigs, SIGINT); 11156429Svs195195 (void) sigaddset(&sigs, SIGTERM); 11166429Svs195195 (void) sigaddset(&sigs, SIGHUP); 11176429Svs195195 (void) sigprocmask(SIG_UNBLOCK, &sigs, NULL); 11186429Svs195195 11196429Svs195195 for (;;) { 11206429Svs195195 (void) sigwait(&sigs, &sig); 11216429Svs195195 (void) sig2str(sig, rcvsigstr); 11226429Svs195195 11236429Svs195195 if (sig != -1) { 11246429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_INFO, 11256429Svs195195 SIGNAL_INFO, rcvsigstr, sig); 11266429Svs195195 switch (sig) { 11276429Svs195195 case SIGINT: 11286429Svs195195 case SIGTERM: 11296429Svs195195 terminate_process(); 11306429Svs195195 _exit(FPSD_EXIT_ERROR); 11316429Svs195195 break; 11326429Svs195195 case SIGHUP: 11336429Svs195195 fpsd.d_ts_hup = gethrtime(); 11346429Svs195195 break; 11356429Svs195195 default: break; 11366429Svs195195 } 11376429Svs195195 } 11386429Svs195195 } 11396429Svs195195 #pragma error_messages(off, E_STATEMENT_NOT_REACHED) 11406429Svs195195 /* NOTREACHED */ 11416429Svs195195 return (0); 11426429Svs195195 } 1143