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