136589d6bSRobert Mustacchi /*
236589d6bSRobert Mustacchi * This file and its contents are supplied under the terms of the
336589d6bSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
436589d6bSRobert Mustacchi * You may only use this file in accordance with the terms of version
536589d6bSRobert Mustacchi * 1.0 of the CDDL.
636589d6bSRobert Mustacchi *
736589d6bSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
836589d6bSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
936589d6bSRobert Mustacchi * http://www.illumos.org/license/CDDL.
1036589d6bSRobert Mustacchi */
1136589d6bSRobert Mustacchi
1236589d6bSRobert Mustacchi /*
1336589d6bSRobert Mustacchi * Copyright (c) 2021 Joyent, Inc.
1436589d6bSRobert Mustacchi */
1536589d6bSRobert Mustacchi
1636589d6bSRobert Mustacchi /*
1736589d6bSRobert Mustacchi * virtual arp daemon -- varpd
1836589d6bSRobert Mustacchi *
1936589d6bSRobert Mustacchi * The virtual arp daemon is the user land counterpart to the overlay driver. To
2036589d6bSRobert Mustacchi * truly understand its purpose and how it fits into things, you should read the
2136589d6bSRobert Mustacchi * overlay big theory statement in uts/common/io/overlay/overlay.c.
2236589d6bSRobert Mustacchi *
2336589d6bSRobert Mustacchi * varpd's purpose it to provide a means for looking up the destination on the
2436589d6bSRobert Mustacchi * underlay network for a host on an overlay network and to also be a door
25bbf21555SRichard Lowe * server such that dladm(8) via libdladm can configure and get useful status
2636589d6bSRobert Mustacchi * information. The heavy lifting is all done by libvarpd and the various lookup
2736589d6bSRobert Mustacchi * plugins.
2836589d6bSRobert Mustacchi *
2936589d6bSRobert Mustacchi * When varpd first starts up, we take care of chdiring into /var/run/varpd,
3036589d6bSRobert Mustacchi * which is also where we create /var/run/varpd/varpd.door, our door server.
3136589d6bSRobert Mustacchi * After that we daemonize and only after we daemonize do we go ahead and load
3236589d6bSRobert Mustacchi * plugins. The reason that we don't load plugins before daemonizing is that
3336589d6bSRobert Mustacchi * they could very well be creating threads and thus lose them all. In general,
3436589d6bSRobert Mustacchi * we want to make things easier on our children and not require them to be
3536589d6bSRobert Mustacchi * fork safe.
3636589d6bSRobert Mustacchi *
3736589d6bSRobert Mustacchi * Once it's spun up, the main varpd thread sits in sigsuspend and really just
3836589d6bSRobert Mustacchi * hangs out waiting for something, libvarpd handles everything else.
3936589d6bSRobert Mustacchi */
4036589d6bSRobert Mustacchi
4136589d6bSRobert Mustacchi #include <libvarpd.h>
4236589d6bSRobert Mustacchi #include <stdio.h>
4336589d6bSRobert Mustacchi #include <unistd.h>
4436589d6bSRobert Mustacchi #include <string.h>
4536589d6bSRobert Mustacchi #include <signal.h>
4636589d6bSRobert Mustacchi #include <sys/types.h>
4736589d6bSRobert Mustacchi #include <sys/stat.h>
4836589d6bSRobert Mustacchi #include <fcntl.h>
4936589d6bSRobert Mustacchi #include <errno.h>
5036589d6bSRobert Mustacchi #include <libgen.h>
5136589d6bSRobert Mustacchi #include <stdarg.h>
5236589d6bSRobert Mustacchi #include <stdlib.h>
5336589d6bSRobert Mustacchi #include <paths.h>
5436589d6bSRobert Mustacchi #include <limits.h>
5536589d6bSRobert Mustacchi #include <sys/corectl.h>
5636589d6bSRobert Mustacchi #include <signal.h>
5736589d6bSRobert Mustacchi #include <strings.h>
5836589d6bSRobert Mustacchi #include <sys/wait.h>
5936589d6bSRobert Mustacchi #include <unistd.h>
6036589d6bSRobert Mustacchi #include <thread.h>
6136589d6bSRobert Mustacchi #include <priv.h>
6236589d6bSRobert Mustacchi #include <libscf.h>
6336589d6bSRobert Mustacchi
6436589d6bSRobert Mustacchi #define VARPD_EXIT_REQUESTED SMF_EXIT_OK
6536589d6bSRobert Mustacchi #define VARPD_EXIT_FATAL SMF_EXIT_ERR_FATAL
6636589d6bSRobert Mustacchi #define VARPD_EXIT_USAGE SMF_EXIT_ERR_CONFIG
6736589d6bSRobert Mustacchi
6836589d6bSRobert Mustacchi #define VARPD_RUNDIR "/var/run/varpd"
6936589d6bSRobert Mustacchi #define VARPD_DEFAULT_DOOR "/var/run/varpd/varpd.door"
7036589d6bSRobert Mustacchi
7136589d6bSRobert Mustacchi #define VARPD_PG "varpd"
7236589d6bSRobert Mustacchi #define VARPD_PROP_INC "include_path"
7336589d6bSRobert Mustacchi
7436589d6bSRobert Mustacchi static varpd_handle_t *varpd_handle;
7536589d6bSRobert Mustacchi static const char *varpd_pname;
7636589d6bSRobert Mustacchi static volatile boolean_t varpd_exit = B_FALSE;
7736589d6bSRobert Mustacchi
7836589d6bSRobert Mustacchi /*
7936589d6bSRobert Mustacchi * Debug builds are automatically wired up for umem debugging.
8036589d6bSRobert Mustacchi */
8136589d6bSRobert Mustacchi #ifdef DEBUG
8236589d6bSRobert Mustacchi const char *
_umem_debug_init()8336589d6bSRobert Mustacchi _umem_debug_init()
8436589d6bSRobert Mustacchi {
8536589d6bSRobert Mustacchi return ("default,verbose");
8636589d6bSRobert Mustacchi }
8736589d6bSRobert Mustacchi
8836589d6bSRobert Mustacchi const char *
_umem_logging_init(void)8936589d6bSRobert Mustacchi _umem_logging_init(void)
9036589d6bSRobert Mustacchi {
9136589d6bSRobert Mustacchi return ("fail,contents");
9236589d6bSRobert Mustacchi }
9336589d6bSRobert Mustacchi #endif /* DEBUG */
9436589d6bSRobert Mustacchi
9536589d6bSRobert Mustacchi static void
varpd_vwarn(FILE * out,const char * fmt,va_list ap)9636589d6bSRobert Mustacchi varpd_vwarn(FILE *out, const char *fmt, va_list ap)
9736589d6bSRobert Mustacchi {
9836589d6bSRobert Mustacchi int error = errno;
9936589d6bSRobert Mustacchi
10036589d6bSRobert Mustacchi (void) fprintf(out, "%s: ", varpd_pname);
10136589d6bSRobert Mustacchi (void) vfprintf(out, fmt, ap);
10236589d6bSRobert Mustacchi
10336589d6bSRobert Mustacchi if (fmt[strlen(fmt) - 1] != '\n')
10436589d6bSRobert Mustacchi (void) fprintf(out, ": %s\n", strerror(error));
10536589d6bSRobert Mustacchi }
10636589d6bSRobert Mustacchi
10736589d6bSRobert Mustacchi static void
varpd_fatal(const char * fmt,...)10836589d6bSRobert Mustacchi varpd_fatal(const char *fmt, ...)
10936589d6bSRobert Mustacchi {
11036589d6bSRobert Mustacchi va_list ap;
11136589d6bSRobert Mustacchi
11236589d6bSRobert Mustacchi va_start(ap, fmt);
11336589d6bSRobert Mustacchi varpd_vwarn(stderr, fmt, ap);
11436589d6bSRobert Mustacchi va_end(ap);
11536589d6bSRobert Mustacchi
11636589d6bSRobert Mustacchi exit(VARPD_EXIT_FATAL);
11736589d6bSRobert Mustacchi }
11836589d6bSRobert Mustacchi
11936589d6bSRobert Mustacchi static void
varpd_dfatal(int dfd,const char * fmt,...)12036589d6bSRobert Mustacchi varpd_dfatal(int dfd, const char *fmt, ...)
12136589d6bSRobert Mustacchi {
12236589d6bSRobert Mustacchi int status = VARPD_EXIT_FATAL;
12336589d6bSRobert Mustacchi va_list ap;
12436589d6bSRobert Mustacchi
12536589d6bSRobert Mustacchi va_start(ap, fmt);
12636589d6bSRobert Mustacchi varpd_vwarn(stdout, fmt, ap);
12736589d6bSRobert Mustacchi va_end(ap);
12836589d6bSRobert Mustacchi
12936589d6bSRobert Mustacchi /* Take a single shot at this */
13036589d6bSRobert Mustacchi (void) write(dfd, &status, sizeof (status));
13136589d6bSRobert Mustacchi exit(status);
13236589d6bSRobert Mustacchi }
13336589d6bSRobert Mustacchi
13436589d6bSRobert Mustacchi /* ARGSUSED */
13536589d6bSRobert Mustacchi static int
varpd_plugin_walk_cb(varpd_handle_t * vph,const char * name,void * unused)13636589d6bSRobert Mustacchi varpd_plugin_walk_cb(varpd_handle_t *vph, const char *name, void *unused)
13736589d6bSRobert Mustacchi {
13836589d6bSRobert Mustacchi (void) printf("loaded %s!\n", name);
13936589d6bSRobert Mustacchi return (0);
14036589d6bSRobert Mustacchi }
14136589d6bSRobert Mustacchi
14236589d6bSRobert Mustacchi static int
varpd_dir_setup(void)14336589d6bSRobert Mustacchi varpd_dir_setup(void)
14436589d6bSRobert Mustacchi {
14536589d6bSRobert Mustacchi int fd;
14636589d6bSRobert Mustacchi
14736589d6bSRobert Mustacchi if (mkdir(VARPD_RUNDIR, 0700) != 0) {
14836589d6bSRobert Mustacchi if (errno != EEXIST)
14936589d6bSRobert Mustacchi varpd_fatal("failed to create %s: %s", VARPD_RUNDIR,
15036589d6bSRobert Mustacchi strerror(errno));
15136589d6bSRobert Mustacchi }
15236589d6bSRobert Mustacchi
15336589d6bSRobert Mustacchi fd = open(VARPD_RUNDIR, O_RDONLY);
15436589d6bSRobert Mustacchi if (fd < 0)
15536589d6bSRobert Mustacchi varpd_fatal("failed to open %s: %s", VARPD_RUNDIR,
15636589d6bSRobert Mustacchi strerror(errno));
15736589d6bSRobert Mustacchi
15836589d6bSRobert Mustacchi if (fchown(fd, UID_NETADM, GID_NETADM) != 0)
15936589d6bSRobert Mustacchi varpd_fatal("failed to chown %s: %s\n", VARPD_RUNDIR,
16036589d6bSRobert Mustacchi strerror(errno));
16136589d6bSRobert Mustacchi
16236589d6bSRobert Mustacchi return (fd);
16336589d6bSRobert Mustacchi }
16436589d6bSRobert Mustacchi
16536589d6bSRobert Mustacchi /*
16636589d6bSRobert Mustacchi * Because varpd is generally run under SMF, we opt to keep its stdout and
16736589d6bSRobert Mustacchi * stderr to be whatever our parent set them up to be.
16836589d6bSRobert Mustacchi */
16936589d6bSRobert Mustacchi static void
varpd_fd_setup(void)17036589d6bSRobert Mustacchi varpd_fd_setup(void)
17136589d6bSRobert Mustacchi {
17236589d6bSRobert Mustacchi int dupfd;
17336589d6bSRobert Mustacchi
17436589d6bSRobert Mustacchi closefrom(STDERR_FILENO + 1);
17536589d6bSRobert Mustacchi dupfd = open(_PATH_DEVNULL, O_RDONLY);
17636589d6bSRobert Mustacchi if (dupfd < 0)
17736589d6bSRobert Mustacchi varpd_fatal("failed to open %s: %s", _PATH_DEVNULL,
17836589d6bSRobert Mustacchi strerror(errno));
17936589d6bSRobert Mustacchi if (dup2(dupfd, STDIN_FILENO) == -1)
18036589d6bSRobert Mustacchi varpd_fatal("failed to dup out stdin: %s", strerror(errno));
18136589d6bSRobert Mustacchi }
18236589d6bSRobert Mustacchi
18336589d6bSRobert Mustacchi /*
18436589d6bSRobert Mustacchi * We borrow fmd's daemonization style. Basically, the parent waits for the
18536589d6bSRobert Mustacchi * child to successfully set up a door and recover all of the old configurations
18636589d6bSRobert Mustacchi * before we say that we're good to go.
18736589d6bSRobert Mustacchi */
18836589d6bSRobert Mustacchi static int
varpd_daemonize(int dirfd)18936589d6bSRobert Mustacchi varpd_daemonize(int dirfd)
19036589d6bSRobert Mustacchi {
19136589d6bSRobert Mustacchi char path[PATH_MAX];
19236589d6bSRobert Mustacchi struct rlimit rlim;
19336589d6bSRobert Mustacchi sigset_t set, oset;
19436589d6bSRobert Mustacchi int estatus, pfds[2];
19536589d6bSRobert Mustacchi pid_t child;
19636589d6bSRobert Mustacchi priv_set_t *pset;
19736589d6bSRobert Mustacchi
19836589d6bSRobert Mustacchi /*
19936589d6bSRobert Mustacchi * Set a per-process core path to be inside of /var/run/varpd. Make sure
20036589d6bSRobert Mustacchi * that we aren't limited in our dump size.
20136589d6bSRobert Mustacchi */
20236589d6bSRobert Mustacchi (void) snprintf(path, sizeof (path),
20336589d6bSRobert Mustacchi "/var/run/varpd/core.%s.%%p", varpd_pname);
20436589d6bSRobert Mustacchi (void) core_set_process_path(path, strlen(path) + 1, getpid());
20536589d6bSRobert Mustacchi
20636589d6bSRobert Mustacchi rlim.rlim_cur = RLIM_INFINITY;
20736589d6bSRobert Mustacchi rlim.rlim_max = RLIM_INFINITY;
20836589d6bSRobert Mustacchi (void) setrlimit(RLIMIT_CORE, &rlim);
20936589d6bSRobert Mustacchi
21036589d6bSRobert Mustacchi /*
21136589d6bSRobert Mustacchi * Claim as many file descriptors as the system will let us.
21236589d6bSRobert Mustacchi */
21336589d6bSRobert Mustacchi if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
21436589d6bSRobert Mustacchi rlim.rlim_cur = rlim.rlim_max;
21536589d6bSRobert Mustacchi (void) setrlimit(RLIMIT_NOFILE, &rlim);
21636589d6bSRobert Mustacchi }
21736589d6bSRobert Mustacchi
21836589d6bSRobert Mustacchi /*
21936589d6bSRobert Mustacchi * chdir /var/run/varpd
22036589d6bSRobert Mustacchi */
22136589d6bSRobert Mustacchi if (fchdir(dirfd) != 0)
22236589d6bSRobert Mustacchi varpd_fatal("failed to chdir to %s", VARPD_RUNDIR);
22336589d6bSRobert Mustacchi
22436589d6bSRobert Mustacchi
22536589d6bSRobert Mustacchi /*
22636589d6bSRobert Mustacchi * At this point block all signals going in so we don't have the parent
22736589d6bSRobert Mustacchi * mistakingly exit when the child is running, but never block SIGABRT.
22836589d6bSRobert Mustacchi */
22936589d6bSRobert Mustacchi if (sigfillset(&set) != 0)
23036589d6bSRobert Mustacchi abort();
23136589d6bSRobert Mustacchi if (sigdelset(&set, SIGABRT) != 0)
23236589d6bSRobert Mustacchi abort();
23336589d6bSRobert Mustacchi if (sigprocmask(SIG_BLOCK, &set, &oset) != 0)
23436589d6bSRobert Mustacchi abort();
23536589d6bSRobert Mustacchi
23636589d6bSRobert Mustacchi /*
23736589d6bSRobert Mustacchi * Do the fork+setsid dance.
23836589d6bSRobert Mustacchi */
23936589d6bSRobert Mustacchi if (pipe(pfds) != 0)
24036589d6bSRobert Mustacchi varpd_fatal("failed to create pipe for daemonizing");
24136589d6bSRobert Mustacchi
24236589d6bSRobert Mustacchi if ((child = fork()) == -1)
24336589d6bSRobert Mustacchi varpd_fatal("failed to fork for daemonizing");
24436589d6bSRobert Mustacchi
24536589d6bSRobert Mustacchi if (child != 0) {
24636589d6bSRobert Mustacchi /* We'll be exiting shortly, so allow for silent failure */
24736589d6bSRobert Mustacchi (void) close(pfds[1]);
24836589d6bSRobert Mustacchi if (read(pfds[0], &estatus, sizeof (estatus)) ==
24936589d6bSRobert Mustacchi sizeof (estatus))
25036589d6bSRobert Mustacchi _exit(estatus);
25136589d6bSRobert Mustacchi
25236589d6bSRobert Mustacchi if (waitpid(child, &estatus, 0) == child && WIFEXITED(estatus))
25336589d6bSRobert Mustacchi _exit(WEXITSTATUS(estatus));
25436589d6bSRobert Mustacchi
25536589d6bSRobert Mustacchi _exit(VARPD_EXIT_FATAL);
25636589d6bSRobert Mustacchi }
25736589d6bSRobert Mustacchi
25836589d6bSRobert Mustacchi /*
25936589d6bSRobert Mustacchi * Drop privileges here.
26036589d6bSRobert Mustacchi *
26136589d6bSRobert Mustacchi * We should make sure we keep around PRIV_NET_PRIVADDR and
26236589d6bSRobert Mustacchi * PRIV_SYS_DLCONFIG, but drop everything else; however, keep basic
26336589d6bSRobert Mustacchi * privs and have our child drop them.
26436589d6bSRobert Mustacchi *
26536589d6bSRobert Mustacchi * We should also run as netadm:netadm and drop all of our groups.
26636589d6bSRobert Mustacchi */
26736589d6bSRobert Mustacchi if (setgroups(0, NULL) != 0)
26836589d6bSRobert Mustacchi abort();
26936589d6bSRobert Mustacchi if (setgid(GID_NETADM) == -1 || seteuid(UID_NETADM) == -1)
27036589d6bSRobert Mustacchi abort();
27136589d6bSRobert Mustacchi if ((pset = priv_allocset()) == NULL)
27236589d6bSRobert Mustacchi abort();
27336589d6bSRobert Mustacchi priv_basicset(pset);
27436589d6bSRobert Mustacchi if (priv_delset(pset, PRIV_PROC_EXEC) == -1 ||
27536589d6bSRobert Mustacchi priv_delset(pset, PRIV_PROC_INFO) == -1 ||
27636589d6bSRobert Mustacchi priv_delset(pset, PRIV_PROC_FORK) == -1 ||
27736589d6bSRobert Mustacchi priv_delset(pset, PRIV_PROC_SESSION) == -1 ||
27836589d6bSRobert Mustacchi priv_delset(pset, PRIV_FILE_LINK_ANY) == -1 ||
27936589d6bSRobert Mustacchi priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1 ||
28036589d6bSRobert Mustacchi priv_addset(pset, PRIV_NET_PRIVADDR) == -1) {
28136589d6bSRobert Mustacchi abort();
28236589d6bSRobert Mustacchi }
28336589d6bSRobert Mustacchi /*
28436589d6bSRobert Mustacchi * Remove privs from the permitted set. That will cause them to be
28536589d6bSRobert Mustacchi * removed from the effective set. We want to make sure that in the case
28636589d6bSRobert Mustacchi * of a vulnerability, something can't get back in here and wreak more
28736589d6bSRobert Mustacchi * havoc. But if we want non-basic privs in the effective set, we have
28836589d6bSRobert Mustacchi * to request them explicitly.
28936589d6bSRobert Mustacchi */
29036589d6bSRobert Mustacchi if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1)
29136589d6bSRobert Mustacchi abort();
29236589d6bSRobert Mustacchi if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) == -1)
29336589d6bSRobert Mustacchi abort();
29436589d6bSRobert Mustacchi
29536589d6bSRobert Mustacchi priv_freeset(pset);
29636589d6bSRobert Mustacchi
29736589d6bSRobert Mustacchi if (close(pfds[0]) != 0)
29836589d6bSRobert Mustacchi abort();
29936589d6bSRobert Mustacchi if (setsid() == -1)
30036589d6bSRobert Mustacchi abort();
30136589d6bSRobert Mustacchi if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0)
30236589d6bSRobert Mustacchi abort();
30336589d6bSRobert Mustacchi (void) umask(0022);
30436589d6bSRobert Mustacchi
30536589d6bSRobert Mustacchi return (pfds[1]);
30636589d6bSRobert Mustacchi }
30736589d6bSRobert Mustacchi
30836589d6bSRobert Mustacchi static int
varpd_setup_lookup_threads(void)30936589d6bSRobert Mustacchi varpd_setup_lookup_threads(void)
31036589d6bSRobert Mustacchi {
31136589d6bSRobert Mustacchi int ret;
31236589d6bSRobert Mustacchi long i, ncpus = sysconf(_SC_NPROCESSORS_ONLN) * 2 + 1;
31336589d6bSRobert Mustacchi
31436589d6bSRobert Mustacchi if (ncpus <= 0)
31536589d6bSRobert Mustacchi abort();
31636589d6bSRobert Mustacchi for (i = 0; i < ncpus; i++) {
31736589d6bSRobert Mustacchi thread_t thr;
31836589d6bSRobert Mustacchi
31936589d6bSRobert Mustacchi ret = thr_create(NULL, 0, libvarpd_overlay_lookup_run,
32036589d6bSRobert Mustacchi varpd_handle, THR_DETACHED | THR_DAEMON, &thr);
32136589d6bSRobert Mustacchi if (ret != 0)
32236589d6bSRobert Mustacchi return (ret);
32336589d6bSRobert Mustacchi }
32436589d6bSRobert Mustacchi
32536589d6bSRobert Mustacchi return (0);
32636589d6bSRobert Mustacchi }
32736589d6bSRobert Mustacchi
32836589d6bSRobert Mustacchi static void
varpd_cleanup(int signal __unused)329*30699046SRichard Lowe varpd_cleanup(int signal __unused)
33036589d6bSRobert Mustacchi {
33136589d6bSRobert Mustacchi varpd_exit = B_TRUE;
33236589d6bSRobert Mustacchi }
33336589d6bSRobert Mustacchi
33436589d6bSRobert Mustacchi /*
33536589d6bSRobert Mustacchi * Load default information from SMF and apply any of if necessary. We recognize
33636589d6bSRobert Mustacchi * the following properties:
33736589d6bSRobert Mustacchi *
33836589d6bSRobert Mustacchi * varpd/include_path Treat these as a series of -i options.
33936589d6bSRobert Mustacchi *
34036589d6bSRobert Mustacchi * If we're not under SMF, just move on.
34136589d6bSRobert Mustacchi */
34236589d6bSRobert Mustacchi static void
varpd_load_smf(int dfd)34336589d6bSRobert Mustacchi varpd_load_smf(int dfd)
34436589d6bSRobert Mustacchi {
34536589d6bSRobert Mustacchi char *fmri, *inc;
34636589d6bSRobert Mustacchi scf_simple_prop_t *prop;
34736589d6bSRobert Mustacchi
34836589d6bSRobert Mustacchi if ((fmri = getenv("SMF_FMRI")) == NULL)
34936589d6bSRobert Mustacchi return;
35036589d6bSRobert Mustacchi
35136589d6bSRobert Mustacchi if ((prop = scf_simple_prop_get(NULL, fmri, VARPD_PG,
35236589d6bSRobert Mustacchi VARPD_PROP_INC)) == NULL)
35336589d6bSRobert Mustacchi return;
35436589d6bSRobert Mustacchi
35536589d6bSRobert Mustacchi while ((inc = scf_simple_prop_next_astring(prop)) != NULL) {
35636589d6bSRobert Mustacchi int err = libvarpd_plugin_load(varpd_handle, inc);
35736589d6bSRobert Mustacchi if (err != 0) {
35836589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to load from %s: %s\n",
35936589d6bSRobert Mustacchi inc, strerror(err));
36036589d6bSRobert Mustacchi }
36136589d6bSRobert Mustacchi }
36236589d6bSRobert Mustacchi
36336589d6bSRobert Mustacchi scf_simple_prop_free(prop);
36436589d6bSRobert Mustacchi }
36536589d6bSRobert Mustacchi
36636589d6bSRobert Mustacchi /*
36736589d6bSRobert Mustacchi * There are a bunch of things we need to do to be a proper daemon here.
36836589d6bSRobert Mustacchi *
36936589d6bSRobert Mustacchi * o Ensure that /var/run/varpd exists or create it
37036589d6bSRobert Mustacchi * o make stdin /dev/null (stdout?)
37136589d6bSRobert Mustacchi * o Ensure any other fds that we somehow inherited are closed, eg.
37236589d6bSRobert Mustacchi * closefrom()
37336589d6bSRobert Mustacchi * o Properly daemonize
37436589d6bSRobert Mustacchi * o Mask all signals except sigabrt before creating our first door -- all
37536589d6bSRobert Mustacchi * other doors will inherit from that.
37636589d6bSRobert Mustacchi * o Have the main thread sigsuspend looking for most things that are
37736589d6bSRobert Mustacchi * actionable...
37836589d6bSRobert Mustacchi */
37936589d6bSRobert Mustacchi int
main(int argc,char * argv[])38036589d6bSRobert Mustacchi main(int argc, char *argv[])
38136589d6bSRobert Mustacchi {
38236589d6bSRobert Mustacchi int err, c, dirfd, dfd, i;
38336589d6bSRobert Mustacchi const char *doorpath = VARPD_DEFAULT_DOOR;
38436589d6bSRobert Mustacchi sigset_t set;
38536589d6bSRobert Mustacchi struct sigaction act;
38636589d6bSRobert Mustacchi int nincpath = 0, nextincpath = 0;
38736589d6bSRobert Mustacchi char **incpath = NULL;
38836589d6bSRobert Mustacchi
38936589d6bSRobert Mustacchi varpd_pname = basename(argv[0]);
39036589d6bSRobert Mustacchi
39136589d6bSRobert Mustacchi /*
39236589d6bSRobert Mustacchi * We want to clean up our file descriptors before we do anything else
39336589d6bSRobert Mustacchi * as we can't assume that libvarpd won't open file descriptors, etc.
39436589d6bSRobert Mustacchi */
39536589d6bSRobert Mustacchi varpd_fd_setup();
39636589d6bSRobert Mustacchi
39736589d6bSRobert Mustacchi if ((err = libvarpd_create(&varpd_handle)) != 0) {
39836589d6bSRobert Mustacchi varpd_fatal("failed to open a libvarpd handle");
39936589d6bSRobert Mustacchi return (1);
40036589d6bSRobert Mustacchi }
40136589d6bSRobert Mustacchi
40236589d6bSRobert Mustacchi while ((c = getopt(argc, argv, ":i:d:")) != -1) {
40336589d6bSRobert Mustacchi switch (c) {
40436589d6bSRobert Mustacchi case 'i':
40536589d6bSRobert Mustacchi if (nextincpath == nincpath) {
40636589d6bSRobert Mustacchi if (nincpath == 0)
40736589d6bSRobert Mustacchi nincpath = 16;
40836589d6bSRobert Mustacchi else
40936589d6bSRobert Mustacchi nincpath *= 2;
41036589d6bSRobert Mustacchi incpath = realloc(incpath, sizeof (char *) *
41136589d6bSRobert Mustacchi nincpath);
41236589d6bSRobert Mustacchi if (incpath == NULL) {
41336589d6bSRobert Mustacchi (void) fprintf(stderr, "failed to "
41436589d6bSRobert Mustacchi "allocate memory for the %dth "
41536589d6bSRobert Mustacchi "-I option: %s\n", nextincpath + 1,
41636589d6bSRobert Mustacchi strerror(errno));
41736589d6bSRobert Mustacchi }
41836589d6bSRobert Mustacchi
41936589d6bSRobert Mustacchi }
42036589d6bSRobert Mustacchi incpath[nextincpath] = optarg;
42136589d6bSRobert Mustacchi nextincpath++;
42236589d6bSRobert Mustacchi break;
42336589d6bSRobert Mustacchi case 'd':
42436589d6bSRobert Mustacchi doorpath = optarg;
42536589d6bSRobert Mustacchi break;
42636589d6bSRobert Mustacchi default:
42736589d6bSRobert Mustacchi (void) fprintf(stderr, "unknown option: %c\n", c);
42836589d6bSRobert Mustacchi return (1);
42936589d6bSRobert Mustacchi }
43036589d6bSRobert Mustacchi }
43136589d6bSRobert Mustacchi
43236589d6bSRobert Mustacchi dirfd = varpd_dir_setup();
43336589d6bSRobert Mustacchi
43436589d6bSRobert Mustacchi (void) libvarpd_plugin_walk(varpd_handle, varpd_plugin_walk_cb, NULL);
43536589d6bSRobert Mustacchi
43636589d6bSRobert Mustacchi dfd = varpd_daemonize(dirfd);
43736589d6bSRobert Mustacchi
43836589d6bSRobert Mustacchi /*
43936589d6bSRobert Mustacchi * Now that we're in the child, go ahead and load all of our plug-ins.
44036589d6bSRobert Mustacchi * We do this, in part, because these plug-ins may need threads of their
44136589d6bSRobert Mustacchi * own and fork won't preserve those and we'd rather the plug-ins don't
44236589d6bSRobert Mustacchi * have to learn about fork-handlers.
44336589d6bSRobert Mustacchi */
44436589d6bSRobert Mustacchi for (i = 0; i < nextincpath; i++) {
44536589d6bSRobert Mustacchi err = libvarpd_plugin_load(varpd_handle, incpath[i]);
44636589d6bSRobert Mustacchi if (err != 0) {
44736589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to load from %s: %s\n",
44836589d6bSRobert Mustacchi incpath[i], strerror(err));
44936589d6bSRobert Mustacchi }
45036589d6bSRobert Mustacchi }
45136589d6bSRobert Mustacchi
45236589d6bSRobert Mustacchi varpd_load_smf(dfd);
45336589d6bSRobert Mustacchi
45436589d6bSRobert Mustacchi if ((err = libvarpd_persist_enable(varpd_handle, VARPD_RUNDIR)) != 0)
45536589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
45636589d6bSRobert Mustacchi strerror(err));
45736589d6bSRobert Mustacchi
45836589d6bSRobert Mustacchi if ((err = libvarpd_persist_restore(varpd_handle)) != 0)
45936589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
46036589d6bSRobert Mustacchi strerror(err));
46136589d6bSRobert Mustacchi
46236589d6bSRobert Mustacchi /*
46336589d6bSRobert Mustacchi * The ur-door thread will inherit from this signal mask. So set it to
46436589d6bSRobert Mustacchi * what we want before doing anything else. In addition, so will our
46536589d6bSRobert Mustacchi * threads that handle varpd lookups.
46636589d6bSRobert Mustacchi */
46736589d6bSRobert Mustacchi if (sigfillset(&set) != 0)
46836589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to fill a signal set...");
46936589d6bSRobert Mustacchi
47036589d6bSRobert Mustacchi if (sigdelset(&set, SIGABRT) != 0)
47136589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to unmask SIGABRT");
47236589d6bSRobert Mustacchi
47336589d6bSRobert Mustacchi if (sigprocmask(SIG_BLOCK, &set, NULL) != 0)
47436589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to set our door signal mask");
47536589d6bSRobert Mustacchi
47636589d6bSRobert Mustacchi if ((err = varpd_setup_lookup_threads()) != 0)
47736589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to create lookup threads: %s\n",
47836589d6bSRobert Mustacchi strerror(err));
47936589d6bSRobert Mustacchi
48036589d6bSRobert Mustacchi if ((err = libvarpd_door_server_create(varpd_handle, doorpath)) != 0)
48136589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to create door server at %s: %s\n",
48236589d6bSRobert Mustacchi doorpath, strerror(err));
48336589d6bSRobert Mustacchi
48436589d6bSRobert Mustacchi /*
48536589d6bSRobert Mustacchi * At this point, finish up signal initialization and finally go ahead,
48636589d6bSRobert Mustacchi * notify the parent that we're okay, and enter the sigsuspend loop.
48736589d6bSRobert Mustacchi */
48836589d6bSRobert Mustacchi bzero(&act, sizeof (struct sigaction));
48936589d6bSRobert Mustacchi act.sa_handler = varpd_cleanup;
49036589d6bSRobert Mustacchi if (sigfillset(&act.sa_mask) != 0)
49136589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to fill sigaction mask");
49236589d6bSRobert Mustacchi act.sa_flags = 0;
49336589d6bSRobert Mustacchi if (sigaction(SIGHUP, &act, NULL) != 0)
49436589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to register HUP handler");
49536589d6bSRobert Mustacchi if (sigdelset(&set, SIGHUP) != 0)
49636589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to remove HUP from mask");
49736589d6bSRobert Mustacchi if (sigaction(SIGQUIT, &act, NULL) != 0)
49836589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to register QUIT handler");
49936589d6bSRobert Mustacchi if (sigdelset(&set, SIGQUIT) != 0)
50036589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to remove QUIT from mask");
50136589d6bSRobert Mustacchi if (sigaction(SIGINT, &act, NULL) != 0)
50236589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to register INT handler");
50336589d6bSRobert Mustacchi if (sigdelset(&set, SIGINT) != 0)
50436589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to remove INT from mask");
50536589d6bSRobert Mustacchi if (sigaction(SIGTERM, &act, NULL) != 0)
50636589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to register TERM handler");
50736589d6bSRobert Mustacchi if (sigdelset(&set, SIGTERM) != 0)
50836589d6bSRobert Mustacchi varpd_dfatal(dfd, "failed to remove TERM from mask");
50936589d6bSRobert Mustacchi
51036589d6bSRobert Mustacchi err = 0;
51136589d6bSRobert Mustacchi (void) write(dfd, &err, sizeof (err));
51236589d6bSRobert Mustacchi (void) close(dfd);
51336589d6bSRobert Mustacchi
51436589d6bSRobert Mustacchi for (;;) {
51536589d6bSRobert Mustacchi if (sigsuspend(&set) == -1)
51636589d6bSRobert Mustacchi if (errno == EFAULT)
51736589d6bSRobert Mustacchi abort();
51836589d6bSRobert Mustacchi if (varpd_exit == B_TRUE)
51936589d6bSRobert Mustacchi break;
52036589d6bSRobert Mustacchi }
52136589d6bSRobert Mustacchi
52236589d6bSRobert Mustacchi libvarpd_door_server_destroy(varpd_handle);
52336589d6bSRobert Mustacchi libvarpd_destroy(varpd_handle);
52436589d6bSRobert Mustacchi
52536589d6bSRobert Mustacchi return (VARPD_EXIT_REQUESTED);
52636589d6bSRobert Mustacchi }
527