1/* $NetBSD: altqd.c,v 1.10 2011/08/16 12:39:29 christos Exp $ */ 2/* $KAME: altqd.c,v 1.10 2002/02/20 10:42:26 kjc Exp $ */ 3/* 4 * Copyright (c) 2001 Theo de Raadt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Copyright (C) 1997-2002 28 * Sony Computer Science Laboratories, Inc. All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 39 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49 * SUCH DAMAGE. 50 */ 51 52#include <sys/param.h> 53#include <sys/socket.h> 54#include <sys/un.h> 55#include <sys/stat.h> 56#include <net/if.h> 57 58#include <stdio.h> 59#include <stdlib.h> 60#include <unistd.h> 61#include <string.h> 62#include <errno.h> 63#include <signal.h> 64#include <fcntl.h> 65#include <syslog.h> 66#include <err.h> 67#ifndef __FreeBSD__ 68#include <util.h> 69#endif 70 71#include <altq/altq.h> 72#include "altq_qop.h" 73#include "quip_server.h" 74 75#ifdef __FreeBSD__ 76#define ALTQD_PID_FILE "/var/run/altqd.pid" 77#endif 78#define MAX_CLIENT 10 79 80static volatile sig_atomic_t gotsig_hup, gotsig_int, gotsig_term; 81 82__dead static void usage(void); 83static void sig_handler(int); 84 85static void 86usage(void) 87{ 88 fprintf(stderr, "usage: %s [-dv] [-f config]\n", getprogname()); 89 exit(1); 90} 91 92static void 93sig_handler(int sig) 94{ 95 switch (sig) { 96 case SIGHUP: 97 gotsig_hup = 1; 98 break; 99 case SIGINT: 100 gotsig_int = 1; 101 break; 102 case SIGTERM: 103 gotsig_term = 1; 104 break; 105 case SIGPIPE: 106 /* 107 * we have lost an API connection. 108 * a subsequent output operation will catch EPIPE. 109 */ 110 break; 111 } 112} 113 114int 115main(int argc, char **argv) 116{ 117 int i, c, maxfd, rval, qpsock, fd; 118 fd_set fds, rfds; 119 FILE *fp, *client[MAX_CLIENT]; 120 121 m_debug = 0; 122 l_debug = LOG_INFO; 123 fp = NULL; 124 for (i = 0; i < MAX_CLIENT; i++) 125 client[i] = NULL; 126 127 while ((c = getopt(argc, argv, "f:vdl:")) != -1) { 128 switch (c) { 129 case 'f': 130 altqconfigfile = optarg; 131 break; 132 case 'v': 133 l_debug = LOG_DEBUG; 134 m_debug |= DEBUG_ALTQ; 135 daemonize = 0; 136 break; 137 case 'd': 138 daemonize = 0; 139 break; 140 case 'l': 141 l_debug = atoi(optarg); 142 break; 143 default: 144 usage(); 145 } 146 } 147 148 signal(SIGINT, sig_handler); 149 signal(SIGTERM, sig_handler); 150 signal(SIGHUP, sig_handler); 151 signal(SIGPIPE, sig_handler); 152 153 if (daemonize) 154 openlog("altqd", LOG_PID, LOG_DAEMON); 155 156 if (qcmd_init() != 0) { 157 if (daemonize) 158 closelog(); 159 exit(1); 160 } 161 162 /* 163 * open a unix domain socket for altqd clients 164 */ 165 if ((qpsock = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 166 LOG(LOG_ERR, errno, "can't open unix domain socket"); 167 else { 168 struct sockaddr_un addr; 169 170 bzero(&addr, sizeof(addr)); 171 addr.sun_family = AF_LOCAL; 172 strlcpy(addr.sun_path, QUIP_PATH, sizeof(addr.sun_path)); 173 unlink(QUIP_PATH); 174 if (bind(qpsock, (struct sockaddr *)&addr, 175 sizeof(addr)) < 0) { 176 LOG(LOG_ERR, errno, "can't bind to %s", QUIP_PATH); 177 close(qpsock); 178 qpsock = -1; 179 } 180 chmod(QUIP_PATH, 0666); 181 if (listen(qpsock, SOMAXCONN) < 0) { 182 LOG(LOG_ERR, errno, "can't listen to %s", QUIP_PATH); 183 close(qpsock); 184 qpsock = -1; 185 } 186 } 187 188 if (daemonize) { 189 daemon(0, 0); 190 191 /* save pid to the pid file (/var/tmp/altqd.pid) */ 192#ifdef __FreeBSD__ 193 { 194 FILE *fp; 195 196 if ((fp = fopen(ALTQD_PID_FILE, "w")) != NULL) { 197 fprintf(fp, "%d\n", getpid()); 198 fclose(fp); 199 } else 200 LOG(LOG_WARNING, errno, "can't open pid file"); 201 } 202#else 203 pidfile(NULL); 204#endif 205 } else { 206 /* interactive mode */ 207 fp = stdin; 208 printf("\nEnter ? or command:\n"); 209 printf("altqd %s> ", cur_ifname()); 210 fflush(stdout); 211 } 212 213 /* 214 * go into the command mode. 215 */ 216 FD_ZERO(&fds); 217 maxfd = 0; 218 if (fp != NULL) { 219 fd = fileno(fp); 220 if (fd == -1) 221 LOG(LOG_ERR, 0, "bad file descriptor", QUIP_PATH); 222 } else 223 fd = -1; 224 225 if (fd != -1) { 226 FD_SET(fd, &fds); 227 maxfd = MAX(maxfd, fd + 1); 228 } 229 if (qpsock >= 0) { 230 FD_SET(qpsock, &fds); 231 maxfd = MAX(maxfd, qpsock + 1); 232 } 233 234 rval = 1; 235 while (rval) { 236 if (gotsig_hup) { 237 qcmd_destroyall(); 238 gotsig_hup = 0; 239 LOG(LOG_INFO, 0, "reinitializing altqd..."); 240 if (qcmd_init() != 0) { 241 LOG(LOG_INFO, 0, "reinitialization failed"); 242 break; 243 } 244 } 245 if (gotsig_term || gotsig_int) { 246 LOG(LOG_INFO, 0, "Exiting on signal %d", 247 gotsig_term ? SIGTERM : SIGINT); 248 break; 249 } 250 251 FD_COPY(&fds, &rfds); 252 if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) { 253 if (errno != EINTR) 254 err(1, "select"); 255 continue; 256 } 257 258 /* 259 * if there is command input, read the input line, 260 * parse it, and execute. 261 */ 262 if (fp && FD_ISSET(fd, &rfds)) { 263 rval = do_command(fp); 264 if (rval == 0) { 265 /* quit command or eof on input */ 266 LOG(LOG_INFO, 0, "Exiting."); 267 } else if (fp == stdin) 268 printf("altqd %s> ", cur_ifname()); 269 fflush(stdout); 270 } else if (qpsock >= 0 && FD_ISSET(qpsock, &rfds)) { 271 /* 272 * quip connection request from client via unix 273 * domain socket; get a new socket for this 274 * connection and add it to the select list. 275 */ 276 int newsock = accept(qpsock, NULL, NULL); 277 278 if (newsock == -1) { 279 LOG(LOG_ERR, errno, "accept"); 280 continue; 281 } 282 FD_SET(newsock, &fds); 283 for (i = 0; i < MAX_CLIENT; i++) 284 if (client[i] == NULL) { 285 client[i] = fdopen(newsock, "r+"); 286 break; 287 } 288 maxfd = MAX(maxfd, newsock + 1); 289 } else { 290 /* 291 * check input from a client via unix domain socket 292 */ 293 for (i = 0; i < MAX_CLIENT; i++) { 294 int fd1; 295 296 if (client[i] == NULL) 297 continue; 298 fd1 = fileno(client[i]); 299 if (FD_ISSET(fd1, &rfds)) { 300 if (quip_input(client[i]) != 0 || 301 fflush(client[i]) != 0) { 302 /* connection closed */ 303 fclose(client[i]); 304 client[i] = NULL; 305 FD_CLR(fd1, &fds); 306 } 307 } 308 } 309 } 310 } 311 312 /* cleanup and exit */ 313 qcmd_destroyall(); 314 if (qpsock >= 0) 315 (void)close(qpsock); 316 unlink(QUIP_PATH); 317 318 for (i = 0; i < MAX_CLIENT; i++) 319 if (client[i] != NULL) 320 (void)fclose(client[i]); 321 if (daemonize) { 322#ifdef __FreeBSD__ 323 /* if we have a pid file, remove it */ 324 unlink(ALTQD_PID_FILE); 325#endif 326 closelog(); 327 } 328 exit(0); 329} 330