xref: /onnv-gate/usr/src/cmd/fps/fpsd/fpsd_main.c (revision 7186:e728311aafb0)
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