/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * bridged - bridging control daemon. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" boolean_t debugging; uint32_t tablemax; const char *instance_name = "default"; struct pollfd *fdarray; dladm_handle_t dlhandle; boolean_t shutting_down; static pthread_t sighand; /* * engine_lock is held while the main loop is busy calling librstp functions. * Door threads take the lock to protect the library from reentrancy. */ static pthread_mutex_t engine_lock = PTHREAD_MUTEX_INITIALIZER; /* * These wrapper functions allow the other components in the daemon to remain * ignorant of pthreads details. */ int lock_engine(void) { return (pthread_mutex_lock(&engine_lock)); } void unlock_engine(void) { (void) pthread_mutex_unlock(&engine_lock); } /* * Utility function for STREAMS ioctls. */ ssize_t strioctl(int fd, int cmd, void *buf, size_t buflen) { int retv; struct strioctl ic; ic.ic_cmd = cmd; ic.ic_timout = 0; ic.ic_dp = buf; ic.ic_len = buflen; if ((retv = ioctl(fd, I_STR, &ic)) != 0) return (retv); else return (ic.ic_len); } static void daemonize(void) { pid_t pid; /* * A little bit of magic here. By the first fork+setsid, we * disconnect from our current controlling terminal and become * a session group leader. By forking again without calling * setsid again, we make certain that we are not the session * group leader and can never reacquire a controlling terminal. */ if ((pid = fork()) == (pid_t)-1) { syslog(LOG_ERR, "fork 1 failed"); exit(EXIT_FAILURE); } if (pid != 0) { (void) wait(NULL); _exit(EXIT_SUCCESS); } if (setsid() == (pid_t)-1) { syslog(LOG_ERR, "setsid"); exit(EXIT_FAILURE); } if ((pid = fork()) == (pid_t)-1) { syslog(LOG_ERR, "fork 2 failed"); exit(EXIT_FAILURE); } if (pid != 0) _exit(EXIT_SUCCESS); (void) chdir("/"); (void) umask(022); } static void * sighandler(void *arg) { sigset_t sigset; int sig; int sigfd = (int)(uintptr_t)arg; (void) sigfillset(&sigset); for (;;) { sig = sigwait(&sigset); switch (sig) { case SIGHUP: (void) write(sigfd, "", 1); break; default: if (debugging) syslog(LOG_NOTICE, "%s signal, shutting down", strsignal(sig)); shutting_down = B_TRUE; break; } /* if we're shutting down, exit this thread */ if (shutting_down) return (NULL); } } static void init_signalhandling(void) { pthread_attr_t attr; int err; sigset_t new; int fildes[2]; if ((fdarray = malloc(FDOFFSET * sizeof (struct pollfd))) == NULL) { syslog(LOG_ERR, "unable to allocate fdarray: %m"); exit(EXIT_FAILURE); } if (pipe(fildes) != 0) { syslog(LOG_ERR, "unable to create signal pipe: %m"); exit(EXIT_FAILURE); } fdarray[0].fd = fildes[0]; fdarray[0].events = POLLIN; assert(control_fd != -1); fdarray[1].fd = control_fd; fdarray[1].events = POLLIN; (void) sigfillset(&new); (void) pthread_sigmask(SIG_BLOCK, &new, NULL); (void) pthread_attr_init(&attr); (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); err = pthread_create(&sighand, &attr, sighandler, (void *)(uintptr_t)fildes[1]); if (err != 0) { syslog(LOG_ERR, "cannot create signal handling thread: %s", strerror(err)); exit(EXIT_FAILURE); } (void) pthread_attr_destroy(&attr); } int main(int argc, char **argv) { dladm_status_t status; char buf[DLADM_STRSIZE]; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); shutting_down = B_FALSE; openlog("bridged", LOG_PID | LOG_NDELAY, LOG_DAEMON); if (argc != 2) { syslog(LOG_ERR, "instance name is required"); exit(EXIT_FAILURE); } instance_name = argv[1]; if ((status = dladm_open(&dlhandle)) != DLADM_STATUS_OK) { syslog(LOG_ERR, "%s: unable to open datalink control: %s", instance_name, dladm_status2str(status, buf)); exit(EXIT_FAILURE); } status = dladm_bridge_get_privprop(instance_name, &debugging, &tablemax); if (status != DLADM_STATUS_OK) { syslog(LOG_ERR, "%s: unable to read properties: %s", instance_name, dladm_status2str(status, buf)); exit(EXIT_FAILURE); } /* Get the properties once so that we have the right initial values */ rstp_init(); open_bridge_control(); daemonize(); init_signalhandling(); init_door(); if (debugging) syslog(LOG_INFO, "bridged started: instance %s", instance_name); event_loop(); (void) pthread_cancel(sighand); (void) pthread_join(sighand, NULL); return (0); }