1 /* $NetBSD: altqd.c,v 1.7 2002/03/05 04:11:51 itojun 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: altqd [-vd] [-f config]\n"); 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:vDdl:")) != -1) { 128 switch (c) { 129 case 'f': 130 altqconfigfile = optarg; 131 break; 132 case 'D': /* -D => dummy mode */ 133 Debug_mode = 1; 134 printf("Debug mode set.\n"); 135 break; 136 case 'v': 137 l_debug = LOG_DEBUG; 138 m_debug |= DEBUG_ALTQ; 139 daemonize = 0; 140 break; 141 case 'd': 142 daemonize = 0; 143 break; 144 case 'l': 145 l_debug = atoi(optarg); 146 break; 147 default: 148 usage(); 149 } 150 } 151 152 signal(SIGINT, sig_handler); 153 signal(SIGTERM, sig_handler); 154 signal(SIGHUP, sig_handler); 155 signal(SIGPIPE, sig_handler); 156 157 if (daemonize) 158 openlog("altqd", LOG_PID, LOG_DAEMON); 159 160 if (qcmd_init() != 0) { 161 if (daemonize) 162 closelog(); 163 exit(1); 164 } 165 166 /* 167 * open a unix domain socket for altqd clients 168 */ 169 if ((qpsock = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) 170 LOG(LOG_ERR, errno, "can't open unix domain socket"); 171 else { 172 struct sockaddr_un addr; 173 174 bzero(&addr, sizeof(addr)); 175 addr.sun_family = AF_LOCAL; 176 strlcpy(addr.sun_path, QUIP_PATH, sizeof(addr.sun_path)); 177 unlink(QUIP_PATH); 178 if (bind(qpsock, (struct sockaddr *)&addr, 179 sizeof(addr)) < 0) { 180 LOG(LOG_ERR, errno, "can't bind to %s", QUIP_PATH); 181 close(qpsock); 182 qpsock = -1; 183 } 184 chmod(QUIP_PATH, 0666); 185 if (listen(qpsock, SOMAXCONN) < 0) { 186 LOG(LOG_ERR, errno, "can't listen to %s", QUIP_PATH); 187 close(qpsock); 188 qpsock = -1; 189 } 190 } 191 192 if (daemonize) { 193 daemon(0, 0); 194 195 /* save pid to the pid file (/var/tmp/altqd.pid) */ 196 #ifdef __FreeBSD__ 197 { 198 FILE *fp; 199 200 if ((fp = fopen(ALTQD_PID_FILE, "w")) != NULL) { 201 fprintf(fp, "%d\n", getpid()); 202 fclose(fp); 203 } else 204 LOG(LOG_WARNING, errno, "can't open pid file"); 205 } 206 #else 207 pidfile(NULL); 208 #endif 209 } else { 210 /* interactive mode */ 211 fp = stdin; 212 printf("\nEnter ? or command:\n"); 213 printf("altqd %s> ", cur_ifname()); 214 fflush(stdout); 215 } 216 217 /* 218 * go into the command mode. 219 */ 220 FD_ZERO(&fds); 221 maxfd = 0; 222 if (fp != NULL) { 223 FD_SET(fileno(fp), &fds); 224 maxfd = MAX(maxfd, fileno(fp) + 1); 225 } 226 if (qpsock >= 0) { 227 FD_SET(qpsock, &fds); 228 maxfd = MAX(maxfd, qpsock + 1); 229 } 230 231 rval = 1; 232 while (rval) { 233 if (gotsig_hup) { 234 qcmd_destroyall(); 235 gotsig_hup = 0; 236 LOG(LOG_INFO, 0, "reinitializing altqd..."); 237 if (qcmd_init() != 0) { 238 LOG(LOG_INFO, 0, "reinitialization failed"); 239 break; 240 } 241 } 242 if (gotsig_term || gotsig_int) { 243 LOG(LOG_INFO, 0, "Exiting on signal %d", 244 gotsig_term ? SIGTERM : SIGINT); 245 break; 246 } 247 248 FD_COPY(&fds, &rfds); 249 if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) { 250 if (errno != EINTR) 251 err(1, "select"); 252 continue; 253 } 254 255 /* 256 * if there is command input, read the input line, 257 * parse it, and execute. 258 */ 259 if (fp && FD_ISSET(fileno(fp), &rfds)) { 260 rval = do_command(fp); 261 if (rval == 0) { 262 /* quit command or eof on input */ 263 LOG(LOG_INFO, 0, "Exiting."); 264 } else if (fp == stdin) 265 printf("altqd %s> ", cur_ifname()); 266 fflush(stdout); 267 } else if (qpsock >= 0 && FD_ISSET(qpsock, &rfds)) { 268 /* 269 * quip connection request from client via unix 270 * domain socket; get a new socket for this 271 * connection and add it to the select list. 272 */ 273 int newsock = accept(qpsock, NULL, NULL); 274 275 if (newsock == -1) { 276 LOG(LOG_ERR, errno, "accept"); 277 continue; 278 } 279 FD_SET(newsock, &fds); 280 for (i = 0; i < MAX_CLIENT; i++) 281 if (client[i] == NULL) { 282 client[i] = fdopen(newsock, "r+"); 283 break; 284 } 285 maxfd = MAX(maxfd, newsock + 1); 286 } else { 287 /* 288 * check input from a client via unix domain socket 289 */ 290 for (i = 0; i < MAX_CLIENT; i++) { 291 int fd; 292 293 if (client[i] == NULL) 294 continue; 295 fd = fileno(client[i]); 296 if (FD_ISSET(fd, &rfds)) { 297 if (quip_input(client[i]) != 0 || 298 fflush(client[i]) != 0) { 299 /* connection closed */ 300 fclose(client[i]); 301 client[i] = NULL; 302 FD_CLR(fd, &fds); 303 } 304 } 305 } 306 } 307 } 308 309 /* cleanup and exit */ 310 qcmd_destroyall(); 311 if (qpsock >= 0) 312 (void)close(qpsock); 313 unlink(QUIP_PATH); 314 315 for (i = 0; i < MAX_CLIENT; i++) 316 if (client[i] != NULL) 317 (void)fclose(client[i]); 318 if (daemonize) { 319 #ifdef __FreeBSD__ 320 /* if we have a pid file, remove it */ 321 unlink(ALTQD_PID_FILE); 322 #endif 323 closelog(); 324 } 325 exit(0); 326 } 327