#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/corectl.h>
#include <sys/resource.h>
#include <priv_utils.h>
#include <signal.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <zone.h>
#include <fmd_error.h>
#include <fmd_string.h>
#include <fmd_conf.h>
#include <fmd_dispq.h>
#include <fmd_subr.h>
#include <fmd.h>
fmd_t fmd;
mutex_t _svcstate_lock = ERRORCHECKMUTEX;
#ifdef DEBUG
const char *
_umem_debug_init()
{
return ("default,verbose");
}
const char *
_umem_logging_init(void)
{
return ("fail,contents");
}
#endif
static int
daemonize_init(void)
{
const char *gzp1, *gzp2, *gzp3, *gzp4, *gzp5;
int status, pfds[2];
sigset_t set, oset;
struct rlimit rlim;
char path[PATH_MAX];
pid_t pid;
(void) snprintf(path, sizeof (path),
"%s/var/fm/fmd/core.%s.%%p", fmd.d_rootdir, fmd.d_pname);
(void) core_set_process_path(path, strlen(path) + 1, fmd.d_pid);
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
(void) setrlimit(RLIMIT_CORE, &rlim);
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
rlim.rlim_cur = rlim.rlim_max;
(void) setrlimit(RLIMIT_NOFILE, &rlim);
}
if (getzoneid() == GLOBAL_ZONEID) {
gzp1 = PRIV_PROC_PRIOCNTL;
gzp2 = PRIV_SYS_CONFIG;
gzp3 = PRIV_SYS_DEVICES;
gzp4 = PRIV_SYS_RES_CONFIG;
gzp5 = PRIV_SYS_NET_CONFIG;
} else {
gzp1 = gzp2 = gzp3 = gzp4 = gzp5 = NULL;
}
if (__init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS,
0, 0,
PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH,
PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_PROC_OWNER,
PRIV_SYS_ADMIN, PRIV_NET_PRIVADDR,
gzp1, gzp2, gzp3, gzp4, gzp5, NULL) != 0)
fmd_error(EFMD_EXIT, "additional privileges required to run\n");
(void) sigfillset(&set);
(void) sigdelset(&set, SIGABRT);
(void) sigprocmask(SIG_BLOCK, &set, &oset);
if (pipe(pfds) == -1)
fmd_error(EFMD_EXIT, "failed to create pipe for daemonize");
if ((pid = fork()) == -1)
fmd_error(EFMD_EXIT, "failed to fork into background");
if (pid != 0) {
(void) close(pfds[1]);
if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
_exit(status);
if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
_exit(WEXITSTATUS(status));
_exit(FMD_EXIT_ERROR);
}
fmd.d_pid = getpid();
(void) setsid();
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
(void) chdir("/");
(void) umask(022);
(void) close(pfds[0]);
return (pfds[1]);
}
static void
daemonize_fini(int fd)
{
(void) close(fd);
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
(void) close(fd);
}
}
static void
handler(int sig)
{
if (fmd.d_signal == 0)
fmd.d_signal = sig;
}
static int
usage(const char *arg0, FILE *fp)
{
(void) fprintf(fp,
"Usage: %s [-V] [-f file] [-o opt=val] [-R dir]\n", arg0);
return (FMD_EXIT_USAGE);
}
int
main(int argc, char *argv[])
{
const char *opt_f = NULL, *opt_R = NULL;
const char optstr[] = "f:o:R:V";
int c, pfd = -1, opt_V = 0;
char *p;
struct sigaction act;
sigset_t set;
while ((c = getopt(argc, argv, optstr)) != EOF) {
switch (c) {
case 'f':
opt_f = optarg;
break;
case 'o':
break;
case 'R':
opt_R = optarg;
break;
case 'V':
opt_V++;
break;
default:
return (usage(argv[0], stderr));
}
}
if (optind < argc)
return (usage(argv[0], stderr));
if (opt_V) {
#ifdef DEBUG
const char *debug = " (DEBUG)";
#else
const char *debug = "";
#endif
(void) printf("%s: version %s%s\n",
argv[0], _fmd_version, debug);
return (FMD_EXIT_SUCCESS);
}
closefrom(STDERR_FILENO + 1);
fmd_create(&fmd, argv[0], opt_R, opt_f);
for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
if (c == 'o') {
if ((p = strchr(optarg, '=')) == NULL) {
(void) fprintf(stderr, "%s: failed to set "
"option -o %s: option requires value\n",
fmd.d_pname, optarg);
return (FMD_EXIT_USAGE);
}
*p++ = '\0';
if (p[0] == '"' && p[strlen(p) - 1] == '"') {
p[strlen(p) - 1] = '\0';
(void) fmd_stresc2chr(++p);
}
if (fmd_conf_setprop(fmd.d_conf, optarg, p) != 0) {
(void) fprintf(stderr,
"%s: failed to set option -o %s: %s\n",
fmd.d_pname, optarg, fmd_strerror(errno));
return (FMD_EXIT_USAGE);
}
}
}
if (fmd.d_fmd_debug & FMD_DBG_HELP) {
fmd_help(&fmd);
fmd_destroy(&fmd);
return (FMD_EXIT_SUCCESS);
}
(void) fmd_conf_getprop(fmd.d_conf, "fg", &fmd.d_fg);
(void) sigfillset(&set);
(void) sigdelset(&set, SIGABRT);
(void) sigfillset(&act.sa_mask);
act.sa_handler = handler;
act.sa_flags = 0;
(void) sigaction(SIGTERM, &act, NULL);
(void) sigdelset(&set, SIGTERM);
if (fmd.d_fg) {
(void) sigaction(SIGHUP, &act, NULL);
(void) sigdelset(&set, SIGHUP);
(void) sigaction(SIGINT, &act, NULL);
(void) sigdelset(&set, SIGINT);
(void) sigdelset(&set, SIGTSTP);
(void) sigdelset(&set, SIGTTIN);
(void) sigdelset(&set, SIGTTOU);
(void) printf("%s: [ loading modules ... ", fmd.d_pname);
(void) fflush(stdout);
} else
pfd = daemonize_init();
fmd_run(&fmd, pfd);
if (fmd.d_fg) {
(void) printf("done ]\n");
(void) printf("%s: [ awaiting events ]\n", fmd.d_pname);
} else
daemonize_fini(pfd);
while (!fmd.d_signal)
(void) sigsuspend(&set);
fmd_destroy(&fmd);
return (FMD_EXIT_SUCCESS);
}