Home | History | Annotate | Line # | Download | only in altqd
      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