178977Sroam/*	$NetBSD: altqd.c,v 1.10 2011/08/16 12:39:29 christos Exp $	*/
278977Sroam/*	$KAME: altqd.c,v 1.10 2002/02/20 10:42:26 kjc Exp $	*/
378977Sroam/*
478977Sroam * Copyright (c) 2001 Theo de Raadt
578977Sroam * All rights reserved.
678977Sroam *
778977Sroam * Redistribution and use in source and binary forms, with or without
878977Sroam * modification, are permitted provided that the following conditions
978977Sroam * are met:
1078977Sroam * 1. Redistributions of source code must retain the above copyright
1178977Sroam *    notice, this list of conditions and the following disclaimer.
1278977Sroam * 2. Redistributions in binary form must reproduce the above copyright
1378977Sroam *    notice, this list of conditions and the following disclaimer in the
1478977Sroam *    documentation and/or other materials provided with the distribution.
1578977Sroam *
1678977Sroam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1778977Sroam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1878977Sroam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1978977Sroam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2078977Sroam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2178977Sroam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2278977Sroam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2378977Sroam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2478977Sroam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2578977Sroam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2678977Sroam *
27114589Sobrien * Copyright (C) 1997-2002
28114589Sobrien *	Sony Computer Science Laboratories, Inc.  All rights reserved.
2978977Sroam *
3078977Sroam * Redistribution and use in source and binary forms, with or without
3178977Sroam * modification, are permitted provided that the following conditions
3278977Sroam * are met:
3378977Sroam * 1. Redistributions of source code must retain the above copyright
3478977Sroam *    notice, this list of conditions and the following disclaimer.
3578977Sroam * 2. Redistributions in binary form must reproduce the above copyright
3678977Sroam *    notice, this list of conditions and the following disclaimer in the
3778977Sroam *    documentation and/or other materials provided with the distribution.
3878977Sroam *
3978977Sroam * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
4078977Sroam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4178977Sroam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4278977Sroam * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
4378977Sroam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4478977Sroam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4578977Sroam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4678977Sroam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4778977Sroam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4878977Sroam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4978977Sroam * SUCH DAMAGE.
5078977Sroam */
5178977Sroam
5278977Sroam#include <sys/param.h>
5378977Sroam#include <sys/socket.h>
5478977Sroam#include <sys/un.h>
5578977Sroam#include <sys/stat.h>
5678977Sroam#include <net/if.h>
5778977Sroam
5878977Sroam#include <stdio.h>
5978977Sroam#include <stdlib.h>
6078977Sroam#include <unistd.h>
6178977Sroam#include <string.h>
6278977Sroam#include <errno.h>
6378977Sroam#include <signal.h>
6478977Sroam#include <fcntl.h>
6578977Sroam#include <syslog.h>
6678977Sroam#include <err.h>
6778977Sroam#ifndef __FreeBSD__
6878977Sroam#include <util.h>
6978977Sroam#endif
7078977Sroam
7178977Sroam#include <altq/altq.h>
7278977Sroam#include "altq_qop.h"
7378977Sroam#include "quip_server.h"
7478977Sroam
7578977Sroam#ifdef __FreeBSD__
7678977Sroam#define  ALTQD_PID_FILE		"/var/run/altqd.pid"
7778977Sroam#endif
7878977Sroam#define MAX_CLIENT		10
7978977Sroam
8078977Sroamstatic volatile sig_atomic_t gotsig_hup, gotsig_int, gotsig_term;
8178977Sroam
8278977Sroam__dead static void usage(void);
8378977Sroamstatic void sig_handler(int);
8478977Sroam
8578977Sroamstatic void
8678977Sroamusage(void)
8778977Sroam{
8878977Sroam	fprintf(stderr, "usage: %s [-dv] [-f config]\n", getprogname());
8978977Sroam	exit(1);
9078977Sroam}
9178977Sroam
9278977Sroamstatic void
9378977Sroamsig_handler(int sig)
9478977Sroam{
9578977Sroam	switch (sig) {
9678977Sroam	case SIGHUP:
9778977Sroam		gotsig_hup = 1;
9878977Sroam		break;
9978977Sroam	case SIGINT:
10078977Sroam		gotsig_int = 1;
10178977Sroam		break;
10278977Sroam	case SIGTERM:
10378977Sroam		gotsig_term = 1;
10478977Sroam		break;
10578977Sroam	case SIGPIPE:
10678977Sroam		/*
10778977Sroam		 * we have lost an API connection.
10878977Sroam		 * a subsequent output operation will catch EPIPE.
10978977Sroam		 */
11078977Sroam		break;
11178977Sroam	}
11278977Sroam}
11378977Sroam
11478977Sroamint
11578977Sroammain(int argc, char **argv)
116126643Smarkm{
11778977Sroam	int	i, c, maxfd, rval, qpsock, fd;
11878977Sroam	fd_set	fds, rfds;
11978977Sroam	FILE	*fp, *client[MAX_CLIENT];
12079002Sroam
12179002Sroam	m_debug = 0;
12278977Sroam	l_debug = LOG_INFO;
123126643Smarkm	fp = NULL;
12478977Sroam	for (i = 0; i < MAX_CLIENT; i++)
12578977Sroam		client[i] = NULL;
12678977Sroam
12778977Sroam	while ((c = getopt(argc, argv, "f:vdl:")) != -1) {
12878977Sroam		switch (c) {
12978977Sroam		case 'f':
13078977Sroam			altqconfigfile = optarg;
13178977Sroam			break;
13278977Sroam		case 'v':
13378977Sroam			l_debug = LOG_DEBUG;
13478977Sroam			m_debug |= DEBUG_ALTQ;
13578977Sroam			daemonize = 0;
13678977Sroam			break;
13778977Sroam		case 'd':
13878977Sroam			daemonize = 0;
13978977Sroam			break;
14078977Sroam		case 'l':
14178977Sroam			l_debug = atoi(optarg);
14278977Sroam			break;
143113936Sjohan		default:
14478977Sroam			usage();
14578977Sroam		}
14678977Sroam	}
14778977Sroam
14878977Sroam	signal(SIGINT, sig_handler);
14978977Sroam	signal(SIGTERM, sig_handler);
15078977Sroam	signal(SIGHUP, sig_handler);
15178977Sroam	signal(SIGPIPE, sig_handler);
15278977Sroam
15378977Sroam	if (daemonize)
15478977Sroam		openlog("altqd", LOG_PID, LOG_DAEMON);
15578977Sroam
15678977Sroam	if (qcmd_init() != 0) {
15778977Sroam		if (daemonize)
15878977Sroam			closelog();
15978977Sroam		exit(1);
16078977Sroam	}
16178977Sroam
16278977Sroam	/*
16378977Sroam	 * open a unix domain socket for altqd clients
16478977Sroam	 */
16578977Sroam	if ((qpsock = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
16678977Sroam		LOG(LOG_ERR, errno, "can't open unix domain socket");
16778977Sroam	else {
16878977Sroam		struct sockaddr_un addr;
16978977Sroam
17078977Sroam		bzero(&addr, sizeof(addr));
17178977Sroam		addr.sun_family = AF_LOCAL;
17278977Sroam		strlcpy(addr.sun_path, QUIP_PATH, sizeof(addr.sun_path));
17378977Sroam		unlink(QUIP_PATH);
17478977Sroam		if (bind(qpsock, (struct sockaddr *)&addr,
17578977Sroam		    sizeof(addr)) < 0) {
17678977Sroam			LOG(LOG_ERR, errno, "can't bind to %s", QUIP_PATH);
17778977Sroam			close(qpsock);
17878977Sroam			qpsock = -1;
17978977Sroam		}
18078977Sroam		chmod(QUIP_PATH, 0666);
18178977Sroam		if (listen(qpsock, SOMAXCONN) < 0) {
18278977Sroam			LOG(LOG_ERR, errno, "can't listen to %s", QUIP_PATH);
18378977Sroam			close(qpsock);
18478977Sroam			qpsock = -1;
18578977Sroam		}
18678977Sroam	}
18778977Sroam
18878977Sroam	if (daemonize) {
18978977Sroam		daemon(0, 0);
19078977Sroam
19178977Sroam		/* save pid to the pid file (/var/tmp/altqd.pid) */
19278977Sroam#ifdef __FreeBSD__
19378977Sroam		{
19478977Sroam			FILE *fp;
19578977Sroam
19678977Sroam			if ((fp = fopen(ALTQD_PID_FILE, "w")) != NULL) {
19778977Sroam				fprintf(fp, "%d\n", getpid());
19878977Sroam				fclose(fp);
19978977Sroam			} else
20078977Sroam				LOG(LOG_WARNING, errno, "can't open pid file");
20178977Sroam		}
20278977Sroam#else
20378977Sroam		pidfile(NULL);
20478977Sroam#endif
20578977Sroam	} else {
20678977Sroam		/* interactive mode */
20778977Sroam		fp = stdin;
20878977Sroam		printf("\nEnter ? or command:\n");
20978977Sroam		printf("altqd %s> ", cur_ifname());
21078977Sroam		fflush(stdout);
21178977Sroam	}
21278977Sroam
21378977Sroam	/*
21478977Sroam	 * go into the command mode.
21578977Sroam	 */
21678977Sroam	FD_ZERO(&fds);
21778977Sroam	maxfd = 0;
21878977Sroam	if (fp != NULL) {
21978977Sroam	    fd = fileno(fp);
22078977Sroam	    if (fd == -1)
22178977Sroam		    LOG(LOG_ERR, 0, "bad file descriptor", QUIP_PATH);
22278977Sroam	} else
22378977Sroam		fd = -1;
22478977Sroam
22578977Sroam	if (fd != -1) {
22678977Sroam		FD_SET(fd, &fds);
22778977Sroam		maxfd = MAX(maxfd, fd + 1);
22878977Sroam	}
22978977Sroam	if (qpsock >= 0) {
23078977Sroam		FD_SET(qpsock, &fds);
23178977Sroam		maxfd = MAX(maxfd, qpsock + 1);
23278977Sroam	}
23378977Sroam
23478977Sroam	rval = 1;
23578977Sroam	while (rval) {
23678977Sroam		if (gotsig_hup) {
23778977Sroam			qcmd_destroyall();
23878977Sroam			gotsig_hup = 0;
23978977Sroam			LOG(LOG_INFO, 0, "reinitializing altqd...");
24078977Sroam			if (qcmd_init() != 0) {
24178977Sroam				LOG(LOG_INFO, 0, "reinitialization failed");
24278977Sroam				break;
24378977Sroam			}
24478977Sroam		}
24578977Sroam		if (gotsig_term || gotsig_int) {
24678977Sroam			LOG(LOG_INFO, 0, "Exiting on signal %d",
24778977Sroam			    gotsig_term ? SIGTERM : SIGINT);
24878977Sroam			break;
24978977Sroam		}
25078977Sroam
25178977Sroam		FD_COPY(&fds, &rfds);
25278977Sroam		if (select(maxfd, &rfds, NULL, NULL, NULL) < 0) {
25378977Sroam			if (errno != EINTR)
25478977Sroam				err(1, "select");
25578977Sroam			continue;
25678977Sroam		}
25778977Sroam
25878977Sroam		/*
25978977Sroam		 * if there is command input, read the input line,
26078977Sroam		 * parse it, and execute.
26178977Sroam		 */
26278977Sroam		if (fp && FD_ISSET(fd, &rfds)) {
26378977Sroam			rval = do_command(fp);
26478977Sroam			if (rval == 0) {
26578977Sroam				/* quit command or eof on input */
26678977Sroam				LOG(LOG_INFO, 0, "Exiting.");
26778977Sroam			} else if (fp == stdin)
26878977Sroam				printf("altqd %s> ", cur_ifname());
26978977Sroam			fflush(stdout);
27078977Sroam		} else if (qpsock >= 0 && FD_ISSET(qpsock, &rfds)) {
27178977Sroam			/*
27278977Sroam			 * quip connection request from client via unix
273152169Sru			 * domain socket; get a new socket for this
27478977Sroam			 * connection and add it to the select list.
27578977Sroam			 */
27678977Sroam			int newsock = accept(qpsock, NULL, NULL);
27778977Sroam
27878977Sroam			if (newsock == -1) {
27978977Sroam				LOG(LOG_ERR, errno, "accept");
28078977Sroam				continue;
28178977Sroam			}
28278977Sroam			FD_SET(newsock, &fds);
28378977Sroam			for (i = 0; i < MAX_CLIENT; i++)
28478977Sroam				if (client[i] == NULL) {
28578977Sroam					client[i] = fdopen(newsock, "r+");
28678977Sroam					break;
28778977Sroam				}
28878977Sroam			maxfd = MAX(maxfd, newsock + 1);
28978977Sroam		} else {
29078977Sroam			/*
29178977Sroam			 * check input from a client via unix domain socket
29278977Sroam			 */
29378977Sroam			for (i = 0; i < MAX_CLIENT; i++) {
29478977Sroam				int fd1;
29578977Sroam
29678977Sroam				if (client[i] == NULL)
29778977Sroam					continue;
29878977Sroam				fd1 = fileno(client[i]);
29978977Sroam				if (FD_ISSET(fd1, &rfds)) {
30078977Sroam					if (quip_input(client[i]) != 0 ||
30178977Sroam					    fflush(client[i]) != 0) {
30278977Sroam						/* connection closed */
30378977Sroam						fclose(client[i]);
30478977Sroam						client[i] = NULL;
30578977Sroam						FD_CLR(fd1, &fds);
30678977Sroam					}
30778977Sroam				}
30878977Sroam			}
30978977Sroam		}
310141611Sru	}
31178977Sroam
31278977Sroam	/* cleanup and exit */
31378977Sroam	qcmd_destroyall();
31478977Sroam	if (qpsock >= 0)
31578977Sroam		(void)close(qpsock);
31678977Sroam	unlink(QUIP_PATH);
31778977Sroam
31878977Sroam	for (i = 0; i < MAX_CLIENT; i++)
31978977Sroam		if (client[i] != NULL)
32078977Sroam			(void)fclose(client[i]);
32178977Sroam	if (daemonize) {
32278977Sroam#ifdef __FreeBSD__
32378977Sroam		/* if we have a pid file, remove it */
32478977Sroam		unlink(ALTQD_PID_FILE);
32578977Sroam#endif
32678977Sroam		closelog();
32778977Sroam	}
32878977Sroam	exit(0);
32978977Sroam}
33078977Sroam