OpenBSD-4.6/usr.bin/bgplg/bgplgsh.c

Compare this file to the similar file:
Show the results in this format:

/*	$OpenBSD: bgplgsh.c,v 1.2 2006/12/12 11:43:50 reyk Exp $	*/

/*
 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>

#include <readline/readline.h>
#include <readline/history.h>

#include "bgplg.h"

#define BGPDSOCK	"/var/www/logs/bgpd.rsock"
#define BGPCTL		"/usr/sbin/bgpctl", "-s", BGPDSOCK
#define PING		"/sbin/ping"
#define TRACEROUTE	"/usr/sbin/traceroute"

static volatile int quit;

static struct cmd cmds[] = CMDS;

char		**lg_arg2argv(char *, int *);
char		**lg_argextra(char **, int, int, struct cmd *);
int		  lg_checkarg(char *);
int		  lg_checkcmd(int, char **, int *, struct cmd *);
char		 *lg_completion(const char *, int);

int
lg_checkarg(char *arg)
{
	size_t len;
	u_int i;

	if (!(len = strlen(arg)))
		return (0);

#define allowed_in_string(_x)                                           \
	((isalnum(_x) || isprint(_x)) &&				\
	(_x != '%' && _x != '\\' && _x != ';' && _x != '&' && _x != '|'))

	for (i = 0; i < len; i++) {
		if (!allowed_in_string(arg[i])) {
			fprintf(stderr, "invalid character in input\n");
			return (EPERM);
		}
	}

	return (0);
}

char **
lg_arg2argv(char *arg, int *argc)
{
	char **argv, *ptr = arg;
	size_t len;
	u_int i, c = 1;

	if (lg_checkarg(arg) != 0)
		return (NULL);
	if (!(len = strlen(arg)))
		return (NULL);

	/* Count elements */
	for (i = 0; i < len; i++) {
		if (isspace(arg[i])) {
			/* filter out additional options */
			if (arg[i + 1] == '-') {
				printf("invalid input\n");
				return (NULL);
			}
			arg[i] = '\0';
			c++;
		}
	}
	if (arg[0] == '\0')
		return (NULL);

	/* Generate array */
	if ((argv = calloc(c + 1, sizeof(char *))) == NULL) {
		printf("fatal error: %s\n", strerror(errno));
		return (NULL);
	}

	argv[c] = NULL;
	*argc = c;

	/* Fill array */
	for (i = c = 0; i < len; i++) {
		if (arg[i] == '\0' || i == 0) {
			if (i != 0)
				ptr = &arg[i + 1];
			argv[c++] = ptr;
		}
	}

	return (argv);
}

char **
lg_argextra(char **argv, int argc, int off, struct cmd *cmdp)
{
	char **new_argv;
	int i, c = 0, n;

	if ((n = argc - off) < 0)
		return (NULL);

	/* Count elements */
	for (i = 0; cmdp->earg[i] != NULL; i++)
		c++;

	/* Generate array */
	if ((new_argv = calloc(c + n + 1, sizeof(char *))) == NULL) {
		printf("fatal error: %s\n", strerror(errno));
		return (NULL);
	}

	/* Fill array */
	for (i = c = 0; cmdp->earg[i] != NULL; i++)
		new_argv[c++] = cmdp->earg[i];

	/* Append old array */
	for (i = n; i < argc; i++)
		new_argv[c++] = argv[i];

	new_argv[c] = NULL;

	if (argv != NULL)
		free(argv);

	return (new_argv);
}

int
lg_checkcmd(int argc, char **argv, int *off, struct cmd *cmd)
{
	char **cmdp = NULL, *cmdstr = NULL;
	int i, ncmd, v, ret = -1;

	if ((cmdstr = strdup(cmd->name)) == NULL)
		goto done;
	if ((cmdp = lg_arg2argv(cmdstr, &ncmd)) == NULL)
		goto done;
	if (ncmd > argc || argc > (ncmd + cmd->maxargs))
		goto done;

	for (i = 0; i < ncmd; i++)
		if (strcmp(argv[i], cmdp[i]) != 0)
			goto done;

	if ((v = argc - ncmd) < 0 ||
	    (*off != -1 && *off < v))
		goto done;
	if (cmd->minargs && v < cmd->minargs) {
		ret = EINVAL;
		goto done;
	}
	*off = v;
	ret = 0;

 done:
	if (cmdp != NULL)
		free(cmdp);
	if (cmdstr != NULL)
		free(cmdstr);
	return (ret);
}

char *
lg_completion(const char *str, int state)
{
	static int lg_complidx, len;
	const char *name;

	if (state == 0) {
		len = strlen(str);
		lg_complidx = 0;
	}
	while ((name = cmds[lg_complidx].name) != NULL) {
		lg_complidx++;
		if (strncmp(name, str, len) == 0)
			return (strdup(name));
	}

	return (NULL);
}

int
main(void)
{
	struct cmd *cmd = NULL;
	char prompt[MAXHOSTNAMELEN], *line, **argp = NULL;
	int ncmd, ret, v = -1;
	u_int i;

	rl_readline_name = NAME;
	rl_completion_entry_function = lg_completion;

	/* Ignore the whitespace character */
	rl_basic_word_break_characters = "\t\n\"\\'`@$><=;|&{(";

	while (!quit) {
		v = -1;
		gethostname(prompt, sizeof(prompt) - 2);
		strlcat(prompt, "> ", sizeof(prompt));

		if ((line = readline(prompt)) == NULL) {
			printf("\n");
			lg_help(cmds, NULL);
			continue;
		}
		if (!lg_strip(line))
			goto next;
		if (strcmp(line, "exit") == 0) {
			quit = 1;
			goto next;
		}

		add_history(line);

		if ((argp = lg_arg2argv(line, &ncmd)) == NULL)
			goto next;

		for (i = 0; cmds[i].name != NULL; i++) {
			ret = lg_checkcmd(ncmd, argp, &v, &cmds[i]);
			if (ret == 0)
				cmd = &cmds[i];
			else if (ret == EINVAL) {
				printf("invalid number of arguments\n");
				goto next;
			}
		}

		if (cmd == NULL) {
			printf("invalid command\n");
		} else if (cmd->func != NULL) {
			cmd->func(cmds, argp);
		} else {
			if ((argp = lg_argextra(argp, ncmd, v, cmd)) == NULL)
				goto next;
			lg_exec(cmd->earg[0], argp);
		}

 next:
		if (argp != NULL) {
			free(argp);
			argp = NULL;
		}
		if (line != NULL) {
			free(line);
			line = NULL;
		}
		cmd = NULL;
	}

	return (0);
}