1 /* $NetBSD: altqd.c,v 1.9 2006/11/26 11:38:07 peter 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 80 static volatile sig_atomic_t gotsig_hup, gotsig_int, gotsig_term; 81 82 static void usage(void); 83 static void sig_handler(int); 84 85 static void 86 usage(void) 87 { 88 fprintf(stderr, "usage: %s [-dv] [-f config]\n", getprogname()); 89 exit(1); 90 } 91 92 static void 93 sig_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 114 int 115 main(int argc, char **argv) 116 { 117 int i, c, maxfd, rval, qpsock; 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_SET(fileno(fp), &fds); 220 maxfd = MAX(maxfd, fileno(fp) + 1); 221 } 222 if (qpsock >= 0) { 223 FD_SET(qpsock, &fds); 224 maxfd = MAX(maxfd, qpsock + 1); 225 } 226 227 rval = 1; 228 while (rval) { 229 if (gotsig_hup) { 230 qcmd_destroyall(); 231 gotsig_hup = 0; 232 LOG(LOG_INFO, 0, "reinitializing altqd..."); 233 if (qcmd_init() != 0) { 234 LOG(LOG_INFO, 0, "reinitialization failed"); 235 break; 236 } 237 } 238 if (gotsig_term || gotsig_int) { 239 LOG(LOG_INFO, 0, "Exiting on signal %d", 240 gotsig_term ? SIGTERM : SIGINT); 241 break; 242 } 243 244 FD_COPY(&fds, &rfds); 245 if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) { 246 if (errno != EINTR) 247 err(1, "select"); 248 continue; 249 } 250 251 /* 252 * if there is command input, read the input line, 253 * parse it, and execute. 254 */ 255 if (fp && FD_ISSET(fileno(fp), &rfds)) { 256 rval = do_command(fp); 257 if (rval == 0) { 258 /* quit command or eof on input */ 259 LOG(LOG_INFO, 0, "Exiting."); 260 } else if (fp == stdin) 261 printf("altqd %s> ", cur_ifname()); 262 fflush(stdout); 263 } else if (qpsock >= 0 && FD_ISSET(qpsock, &rfds)) { 264 /* 265 * quip connection request from client via unix 266 * domain socket; get a new socket for this 267 * connection and add it to the select list. 268 */ 269 int newsock = accept(qpsock, NULL, NULL); 270 271 if (newsock == -1) { 272 LOG(LOG_ERR, errno, "accept"); 273 continue; 274 } 275 FD_SET(newsock, &fds); 276 for (i = 0; i < MAX_CLIENT; i++) 277 if (client[i] == NULL) { 278 client[i] = fdopen(newsock, "r+"); 279 break; 280 } 281 maxfd = MAX(maxfd, newsock + 1); 282 } else { 283 /* 284 * check input from a client via unix domain socket 285 */ 286 for (i = 0; i < MAX_CLIENT; i++) { 287 int fd; 288 289 if (client[i] == NULL) 290 continue; 291 fd = fileno(client[i]); 292 if (FD_ISSET(fd, &rfds)) { 293 if (quip_input(client[i]) != 0 || 294 fflush(client[i]) != 0) { 295 /* connection closed */ 296 fclose(client[i]); 297 client[i] = NULL; 298 FD_CLR(fd, &fds); 299 } 300 } 301 } 302 } 303 } 304 305 /* cleanup and exit */ 306 qcmd_destroyall(); 307 if (qpsock >= 0) 308 (void)close(qpsock); 309 unlink(QUIP_PATH); 310 311 for (i = 0; i < MAX_CLIENT; i++) 312 if (client[i] != NULL) 313 (void)fclose(client[i]); 314 if (daemonize) { 315 #ifdef __FreeBSD__ 316 /* if we have a pid file, remove it */ 317 unlink(ALTQD_PID_FILE); 318 #endif 319 closelog(); 320 } 321 exit(0); 322 } 323