178977Sroam/* $NetBSD: altqd.c,v 1.10 2011/08/16 12:39:29 christos Exp $ */ 278977Sroam/* $KAME: altqd.c,v 1.10 2002/02/20 10:42:26 kjc Exp $ */ 378977Sroam/* 478977Sroam * Copyright (c) 2001 Theo de Raadt 578977Sroam * All rights reserved. 678977Sroam * 778977Sroam * Redistribution and use in source and binary forms, with or without 878977Sroam * modification, are permitted provided that the following conditions 978977Sroam * are met: 1078977Sroam * 1. Redistributions of source code must retain the above copyright 1178977Sroam * notice, this list of conditions and the following disclaimer. 1278977Sroam * 2. Redistributions in binary form must reproduce the above copyright 1378977Sroam * notice, this list of conditions and the following disclaimer in the 1478977Sroam * documentation and/or other materials provided with the distribution. 1578977Sroam * 1678977Sroam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1778977Sroam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1878977Sroam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1978977Sroam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2078977Sroam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2178977Sroam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2278977Sroam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2378977Sroam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2478977Sroam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2578977Sroam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2678977Sroam * 27114589Sobrien * Copyright (C) 1997-2002 28114589Sobrien * Sony Computer Science Laboratories, Inc. All rights reserved. 2978977Sroam * 3078977Sroam * Redistribution and use in source and binary forms, with or without 3178977Sroam * modification, are permitted provided that the following conditions 3278977Sroam * are met: 3378977Sroam * 1. Redistributions of source code must retain the above copyright 3478977Sroam * notice, this list of conditions and the following disclaimer. 3578977Sroam * 2. Redistributions in binary form must reproduce the above copyright 3678977Sroam * notice, this list of conditions and the following disclaimer in the 3778977Sroam * documentation and/or other materials provided with the distribution. 3878977Sroam * 3978977Sroam * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 4078977Sroam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4178977Sroam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4278977Sroam * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 4378977Sroam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4478977Sroam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4578977Sroam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4678977Sroam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4778977Sroam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4878977Sroam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4978977Sroam * SUCH DAMAGE. 5078977Sroam */ 5178977Sroam 5278977Sroam#include <sys/param.h> 5378977Sroam#include <sys/socket.h> 5478977Sroam#include <sys/un.h> 5578977Sroam#include <sys/stat.h> 5678977Sroam#include <net/if.h> 5778977Sroam 5878977Sroam#include <stdio.h> 5978977Sroam#include <stdlib.h> 6078977Sroam#include <unistd.h> 6178977Sroam#include <string.h> 6278977Sroam#include <errno.h> 6378977Sroam#include <signal.h> 6478977Sroam#include <fcntl.h> 6578977Sroam#include <syslog.h> 6678977Sroam#include <err.h> 6778977Sroam#ifndef __FreeBSD__ 6878977Sroam#include <util.h> 6978977Sroam#endif 7078977Sroam 7178977Sroam#include <altq/altq.h> 7278977Sroam#include "altq_qop.h" 7378977Sroam#include "quip_server.h" 7478977Sroam 7578977Sroam#ifdef __FreeBSD__ 7678977Sroam#define ALTQD_PID_FILE "/var/run/altqd.pid" 7778977Sroam#endif 7878977Sroam#define MAX_CLIENT 10 7978977Sroam 8078977Sroamstatic volatile sig_atomic_t gotsig_hup, gotsig_int, gotsig_term; 8178977Sroam 8278977Sroam__dead static void usage(void); 8378977Sroamstatic void sig_handler(int); 8478977Sroam 8578977Sroamstatic void 8678977Sroamusage(void) 8778977Sroam{ 8878977Sroam fprintf(stderr, "usage: %s [-dv] [-f config]\n", getprogname()); 8978977Sroam exit(1); 9078977Sroam} 9178977Sroam 9278977Sroamstatic void 9378977Sroamsig_handler(int sig) 9478977Sroam{ 9578977Sroam switch (sig) { 9678977Sroam case SIGHUP: 9778977Sroam gotsig_hup = 1; 9878977Sroam break; 9978977Sroam case SIGINT: 10078977Sroam gotsig_int = 1; 10178977Sroam break; 10278977Sroam case SIGTERM: 10378977Sroam gotsig_term = 1; 10478977Sroam break; 10578977Sroam case SIGPIPE: 10678977Sroam /* 10778977Sroam * we have lost an API connection. 10878977Sroam * a subsequent output operation will catch EPIPE. 10978977Sroam */ 11078977Sroam break; 11178977Sroam } 11278977Sroam} 11378977Sroam 11478977Sroamint 11578977Sroammain(int argc, char **argv) 116126643Smarkm{ 11778977Sroam int i, c, maxfd, rval, qpsock, fd; 11878977Sroam fd_set fds, rfds; 11978977Sroam FILE *fp, *client[MAX_CLIENT]; 12079002Sroam 12179002Sroam m_debug = 0; 12278977Sroam l_debug = LOG_INFO; 123126643Smarkm fp = NULL; 12478977Sroam for (i = 0; i < MAX_CLIENT; i++) 12578977Sroam client[i] = NULL; 12678977Sroam 12778977Sroam while ((c = getopt(argc, argv, "f:vdl:")) != -1) { 12878977Sroam switch (c) { 12978977Sroam case 'f': 13078977Sroam altqconfigfile = optarg; 13178977Sroam break; 13278977Sroam case 'v': 13378977Sroam l_debug = LOG_DEBUG; 13478977Sroam m_debug |= DEBUG_ALTQ; 13578977Sroam daemonize = 0; 13678977Sroam break; 13778977Sroam case 'd': 13878977Sroam daemonize = 0; 13978977Sroam break; 14078977Sroam case 'l': 14178977Sroam l_debug = atoi(optarg); 14278977Sroam break; 143113936Sjohan default: 14478977Sroam usage(); 14578977Sroam } 14678977Sroam } 14778977Sroam 14878977Sroam signal(SIGINT, sig_handler); 14978977Sroam signal(SIGTERM, sig_handler); 15078977Sroam signal(SIGHUP, sig_handler); 15178977Sroam signal(SIGPIPE, sig_handler); 15278977Sroam 15378977Sroam if (daemonize) 15478977Sroam openlog("altqd", LOG_PID, LOG_DAEMON); 15578977Sroam 15678977Sroam if (qcmd_init() != 0) { 15778977Sroam if (daemonize) 15878977Sroam closelog(); 15978977Sroam exit(1); 16078977Sroam } 16178977Sroam 16278977Sroam /* 16378977Sroam * open a unix domain socket for altqd clients 16478977Sroam */ 16578977Sroam if ((qpsock = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 16678977Sroam LOG(LOG_ERR, errno, "can't open unix domain socket"); 16778977Sroam else { 16878977Sroam struct sockaddr_un addr; 16978977Sroam 17078977Sroam bzero(&addr, sizeof(addr)); 17178977Sroam addr.sun_family = AF_LOCAL; 17278977Sroam strlcpy(addr.sun_path, QUIP_PATH, sizeof(addr.sun_path)); 17378977Sroam unlink(QUIP_PATH); 17478977Sroam if (bind(qpsock, (struct sockaddr *)&addr, 17578977Sroam sizeof(addr)) < 0) { 17678977Sroam LOG(LOG_ERR, errno, "can't bind to %s", QUIP_PATH); 17778977Sroam close(qpsock); 17878977Sroam qpsock = -1; 17978977Sroam } 18078977Sroam chmod(QUIP_PATH, 0666); 18178977Sroam if (listen(qpsock, SOMAXCONN) < 0) { 18278977Sroam LOG(LOG_ERR, errno, "can't listen to %s", QUIP_PATH); 18378977Sroam close(qpsock); 18478977Sroam qpsock = -1; 18578977Sroam } 18678977Sroam } 18778977Sroam 18878977Sroam if (daemonize) { 18978977Sroam daemon(0, 0); 19078977Sroam 19178977Sroam /* save pid to the pid file (/var/tmp/altqd.pid) */ 19278977Sroam#ifdef __FreeBSD__ 19378977Sroam { 19478977Sroam FILE *fp; 19578977Sroam 19678977Sroam if ((fp = fopen(ALTQD_PID_FILE, "w")) != NULL) { 19778977Sroam fprintf(fp, "%d\n", getpid()); 19878977Sroam fclose(fp); 19978977Sroam } else 20078977Sroam LOG(LOG_WARNING, errno, "can't open pid file"); 20178977Sroam } 20278977Sroam#else 20378977Sroam pidfile(NULL); 20478977Sroam#endif 20578977Sroam } else { 20678977Sroam /* interactive mode */ 20778977Sroam fp = stdin; 20878977Sroam printf("\nEnter ? or command:\n"); 20978977Sroam printf("altqd %s> ", cur_ifname()); 21078977Sroam fflush(stdout); 21178977Sroam } 21278977Sroam 21378977Sroam /* 21478977Sroam * go into the command mode. 21578977Sroam */ 21678977Sroam FD_ZERO(&fds); 21778977Sroam maxfd = 0; 21878977Sroam if (fp != NULL) { 21978977Sroam fd = fileno(fp); 22078977Sroam if (fd == -1) 22178977Sroam LOG(LOG_ERR, 0, "bad file descriptor", QUIP_PATH); 22278977Sroam } else 22378977Sroam fd = -1; 22478977Sroam 22578977Sroam if (fd != -1) { 22678977Sroam FD_SET(fd, &fds); 22778977Sroam maxfd = MAX(maxfd, fd + 1); 22878977Sroam } 22978977Sroam if (qpsock >= 0) { 23078977Sroam FD_SET(qpsock, &fds); 23178977Sroam maxfd = MAX(maxfd, qpsock + 1); 23278977Sroam } 23378977Sroam 23478977Sroam rval = 1; 23578977Sroam while (rval) { 23678977Sroam if (gotsig_hup) { 23778977Sroam qcmd_destroyall(); 23878977Sroam gotsig_hup = 0; 23978977Sroam LOG(LOG_INFO, 0, "reinitializing altqd..."); 24078977Sroam if (qcmd_init() != 0) { 24178977Sroam LOG(LOG_INFO, 0, "reinitialization failed"); 24278977Sroam break; 24378977Sroam } 24478977Sroam } 24578977Sroam if (gotsig_term || gotsig_int) { 24678977Sroam LOG(LOG_INFO, 0, "Exiting on signal %d", 24778977Sroam gotsig_term ? SIGTERM : SIGINT); 24878977Sroam break; 24978977Sroam } 25078977Sroam 25178977Sroam FD_COPY(&fds, &rfds); 25278977Sroam if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) { 25378977Sroam if (errno != EINTR) 25478977Sroam err(1, "select"); 25578977Sroam continue; 25678977Sroam } 25778977Sroam 25878977Sroam /* 25978977Sroam * if there is command input, read the input line, 26078977Sroam * parse it, and execute. 26178977Sroam */ 26278977Sroam if (fp && FD_ISSET(fd, &rfds)) { 26378977Sroam rval = do_command(fp); 26478977Sroam if (rval == 0) { 26578977Sroam /* quit command or eof on input */ 26678977Sroam LOG(LOG_INFO, 0, "Exiting."); 26778977Sroam } else if (fp == stdin) 26878977Sroam printf("altqd %s> ", cur_ifname()); 26978977Sroam fflush(stdout); 27078977Sroam } else if (qpsock >= 0 && FD_ISSET(qpsock, &rfds)) { 27178977Sroam /* 27278977Sroam * quip connection request from client via unix 273152169Sru * domain socket; get a new socket for this 27478977Sroam * connection and add it to the select list. 27578977Sroam */ 27678977Sroam int newsock = accept(qpsock, NULL, NULL); 27778977Sroam 27878977Sroam if (newsock == -1) { 27978977Sroam LOG(LOG_ERR, errno, "accept"); 28078977Sroam continue; 28178977Sroam } 28278977Sroam FD_SET(newsock, &fds); 28378977Sroam for (i = 0; i < MAX_CLIENT; i++) 28478977Sroam if (client[i] == NULL) { 28578977Sroam client[i] = fdopen(newsock, "r+"); 28678977Sroam break; 28778977Sroam } 28878977Sroam maxfd = MAX(maxfd, newsock + 1); 28978977Sroam } else { 29078977Sroam /* 29178977Sroam * check input from a client via unix domain socket 29278977Sroam */ 29378977Sroam for (i = 0; i < MAX_CLIENT; i++) { 29478977Sroam int fd1; 29578977Sroam 29678977Sroam if (client[i] == NULL) 29778977Sroam continue; 29878977Sroam fd1 = fileno(client[i]); 29978977Sroam if (FD_ISSET(fd1, &rfds)) { 30078977Sroam if (quip_input(client[i]) != 0 || 30178977Sroam fflush(client[i]) != 0) { 30278977Sroam /* connection closed */ 30378977Sroam fclose(client[i]); 30478977Sroam client[i] = NULL; 30578977Sroam FD_CLR(fd1, &fds); 30678977Sroam } 30778977Sroam } 30878977Sroam } 30978977Sroam } 310141611Sru } 31178977Sroam 31278977Sroam /* cleanup and exit */ 31378977Sroam qcmd_destroyall(); 31478977Sroam if (qpsock >= 0) 31578977Sroam (void)close(qpsock); 31678977Sroam unlink(QUIP_PATH); 31778977Sroam 31878977Sroam for (i = 0; i < MAX_CLIENT; i++) 31978977Sroam if (client[i] != NULL) 32078977Sroam (void)fclose(client[i]); 32178977Sroam if (daemonize) { 32278977Sroam#ifdef __FreeBSD__ 32378977Sroam /* if we have a pid file, remove it */ 32478977Sroam unlink(ALTQD_PID_FILE); 32578977Sroam#endif 32678977Sroam closelog(); 32778977Sroam } 32878977Sroam exit(0); 32978977Sroam} 33078977Sroam