197f17497SC.J. Collier/*-
297f17497SC.J. Collier *   BSD LICENSE
397f17497SC.J. Collier *
497f17497SC.J. Collier *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
597f17497SC.J. Collier *   All rights reserved.
697f17497SC.J. Collier *
797f17497SC.J. Collier *   Redistribution and use in source and binary forms, with or without
897f17497SC.J. Collier *   modification, are permitted provided that the following conditions
997f17497SC.J. Collier *   are met:
1097f17497SC.J. Collier *
1197f17497SC.J. Collier *     * Redistributions of source code must retain the above copyright
1297f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer.
1397f17497SC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
1497f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer in
1597f17497SC.J. Collier *       the documentation and/or other materials provided with the
1697f17497SC.J. Collier *       distribution.
1797f17497SC.J. Collier *     * Neither the name of Intel Corporation nor the names of its
1897f17497SC.J. Collier *       contributors may be used to endorse or promote products derived
1997f17497SC.J. Collier *       from this software without specific prior written permission.
2097f17497SC.J. Collier *
2197f17497SC.J. Collier *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2297f17497SC.J. Collier *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2397f17497SC.J. Collier *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2497f17497SC.J. Collier *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2597f17497SC.J. Collier *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2697f17497SC.J. Collier *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2797f17497SC.J. Collier *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2897f17497SC.J. Collier *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2997f17497SC.J. Collier *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3097f17497SC.J. Collier *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3197f17497SC.J. Collier *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3297f17497SC.J. Collier */
3397f17497SC.J. Collier
3497f17497SC.J. Collier/*
3597f17497SC.J. Collier * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
3697f17497SC.J. Collier * All rights reserved.
3797f17497SC.J. Collier * Redistribution and use in source and binary forms, with or without
3897f17497SC.J. Collier * modification, are permitted provided that the following conditions are met:
3997f17497SC.J. Collier *
4097f17497SC.J. Collier *     * Redistributions of source code must retain the above copyright
4197f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer.
4297f17497SC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
4397f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer in the
4497f17497SC.J. Collier *       documentation and/or other materials provided with the distribution.
4597f17497SC.J. Collier *     * Neither the name of the University of California, Berkeley nor the
4697f17497SC.J. Collier *       names of its contributors may be used to endorse or promote products
4797f17497SC.J. Collier *       derived from this software without specific prior written permission.
4897f17497SC.J. Collier *
4997f17497SC.J. Collier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
5097f17497SC.J. Collier * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5197f17497SC.J. Collier * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5297f17497SC.J. Collier * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
5397f17497SC.J. Collier * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5497f17497SC.J. Collier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5597f17497SC.J. Collier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5697f17497SC.J. Collier * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5797f17497SC.J. Collier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5897f17497SC.J. Collier * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5997f17497SC.J. Collier */
6097f17497SC.J. Collier
6197f17497SC.J. Collier#include <stdio.h>
6297f17497SC.J. Collier#include <string.h>
6397f17497SC.J. Collier#include <unistd.h>
6497f17497SC.J. Collier#include <stdlib.h>
6597f17497SC.J. Collier#include <stdarg.h>
6697f17497SC.J. Collier#include <inttypes.h>
6797f17497SC.J. Collier#include <fcntl.h>
6897f17497SC.J. Collier#include <poll.h>
6997f17497SC.J. Collier#include <errno.h>
7097f17497SC.J. Collier#include <termios.h>
7197f17497SC.J. Collier#include <netinet/in.h>
7297f17497SC.J. Collier
7397f17497SC.J. Collier#include <rte_string_fns.h>
7497f17497SC.J. Collier
7597f17497SC.J. Collier#include "cmdline_parse.h"
7697f17497SC.J. Collier#include "cmdline_rdline.h"
7797f17497SC.J. Collier#include "cmdline.h"
7897f17497SC.J. Collier
7997f17497SC.J. Collierstatic void
8097f17497SC.J. Colliercmdline_valid_buffer(struct rdline *rdl, const char *buf,
8197f17497SC.J. Collier		     __attribute__((unused)) unsigned int size)
8297f17497SC.J. Collier{
8397f17497SC.J. Collier	struct cmdline *cl = rdl->opaque;
8497f17497SC.J. Collier	int ret;
8597f17497SC.J. Collier	ret = cmdline_parse(cl, buf);
8697f17497SC.J. Collier	if (ret == CMDLINE_PARSE_AMBIGUOUS)
8797f17497SC.J. Collier		cmdline_printf(cl, "Ambiguous command\n");
8897f17497SC.J. Collier	else if (ret == CMDLINE_PARSE_NOMATCH)
8997f17497SC.J. Collier		cmdline_printf(cl, "Command not found\n");
9097f17497SC.J. Collier	else if (ret == CMDLINE_PARSE_BAD_ARGS)
9197f17497SC.J. Collier		cmdline_printf(cl, "Bad arguments\n");
9297f17497SC.J. Collier}
9397f17497SC.J. Collier
9497f17497SC.J. Collierstatic int
9597f17497SC.J. Colliercmdline_complete_buffer(struct rdline *rdl, const char *buf,
9697f17497SC.J. Collier			char *dstbuf, unsigned int dstsize,
9797f17497SC.J. Collier			int *state)
9897f17497SC.J. Collier{
9997f17497SC.J. Collier	struct cmdline *cl = rdl->opaque;
10097f17497SC.J. Collier	return cmdline_complete(cl, buf, state, dstbuf, dstsize);
10197f17497SC.J. Collier}
10297f17497SC.J. Collier
10397f17497SC.J. Collierint
10497f17497SC.J. Colliercmdline_write_char(struct rdline *rdl, char c)
10597f17497SC.J. Collier{
10697f17497SC.J. Collier	int ret = -1;
10797f17497SC.J. Collier	struct cmdline *cl;
10897f17497SC.J. Collier
10997f17497SC.J. Collier	if (!rdl)
11097f17497SC.J. Collier		return -1;
11197f17497SC.J. Collier
11297f17497SC.J. Collier	cl = rdl->opaque;
11397f17497SC.J. Collier
11497f17497SC.J. Collier	if (cl->s_out >= 0)
11597f17497SC.J. Collier		ret = write(cl->s_out, &c, 1);
11697f17497SC.J. Collier
11797f17497SC.J. Collier	return ret;
11897f17497SC.J. Collier}
11997f17497SC.J. Collier
12097f17497SC.J. Collier
12197f17497SC.J. Colliervoid
12297f17497SC.J. Colliercmdline_set_prompt(struct cmdline *cl, const char *prompt)
12397f17497SC.J. Collier{
12497f17497SC.J. Collier	if (!cl || !prompt)
12597f17497SC.J. Collier		return;
12697f17497SC.J. Collier	snprintf(cl->prompt, sizeof(cl->prompt), "%s", prompt);
12797f17497SC.J. Collier}
12897f17497SC.J. Collier
12997f17497SC.J. Collierstruct cmdline *
13097f17497SC.J. Colliercmdline_new(cmdline_parse_ctx_t *ctx, const char *prompt, int s_in, int s_out)
13197f17497SC.J. Collier{
13297f17497SC.J. Collier	struct cmdline *cl;
1338b25d1adSChristian Ehrhardt	int ret;
13497f17497SC.J. Collier
13597f17497SC.J. Collier	if (!ctx || !prompt)
13697f17497SC.J. Collier		return NULL;
13797f17497SC.J. Collier
13897f17497SC.J. Collier	cl = malloc(sizeof(struct cmdline));
13997f17497SC.J. Collier	if (cl == NULL)
14097f17497SC.J. Collier		return NULL;
14197f17497SC.J. Collier	memset(cl, 0, sizeof(struct cmdline));
14297f17497SC.J. Collier	cl->s_in = s_in;
14397f17497SC.J. Collier	cl->s_out = s_out;
14497f17497SC.J. Collier	cl->ctx = ctx;
14597f17497SC.J. Collier
1468b25d1adSChristian Ehrhardt	ret = rdline_init(&cl->rdl, cmdline_write_char, cmdline_valid_buffer,
1478b25d1adSChristian Ehrhardt			cmdline_complete_buffer);
1488b25d1adSChristian Ehrhardt	if (ret != 0) {
1498b25d1adSChristian Ehrhardt		free(cl);
1508b25d1adSChristian Ehrhardt		return NULL;
1518b25d1adSChristian Ehrhardt	}
1528b25d1adSChristian Ehrhardt
15397f17497SC.J. Collier	cl->rdl.opaque = cl;
15497f17497SC.J. Collier	cmdline_set_prompt(cl, prompt);
15597f17497SC.J. Collier	rdline_newline(&cl->rdl, cl->prompt);
15697f17497SC.J. Collier
15797f17497SC.J. Collier	return cl;
15897f17497SC.J. Collier}
15997f17497SC.J. Collier
16097f17497SC.J. Colliervoid
16197f17497SC.J. Colliercmdline_free(struct cmdline *cl)
16297f17497SC.J. Collier{
16397f17497SC.J. Collier	dprintf("called\n");
16497f17497SC.J. Collier
16597f17497SC.J. Collier	if (!cl)
16697f17497SC.J. Collier		return;
16797f17497SC.J. Collier
16897f17497SC.J. Collier	if (cl->s_in > 2)
16997f17497SC.J. Collier		close(cl->s_in);
17097f17497SC.J. Collier	if (cl->s_out != cl->s_in && cl->s_out > 2)
17197f17497SC.J. Collier		close(cl->s_out);
17297f17497SC.J. Collier	free(cl);
17397f17497SC.J. Collier}
17497f17497SC.J. Collier
17597f17497SC.J. Colliervoid
17697f17497SC.J. Colliercmdline_printf(const struct cmdline *cl, const char *fmt, ...)
17797f17497SC.J. Collier{
17897f17497SC.J. Collier	va_list ap;
17997f17497SC.J. Collier
18097f17497SC.J. Collier	if (!cl || !fmt)
18197f17497SC.J. Collier		return;
18297f17497SC.J. Collier
18397f17497SC.J. Collier#ifdef _GNU_SOURCE
18497f17497SC.J. Collier	if (cl->s_out < 0)
18597f17497SC.J. Collier		return;
18697f17497SC.J. Collier	va_start(ap, fmt);
18797f17497SC.J. Collier	vdprintf(cl->s_out, fmt, ap);
18897f17497SC.J. Collier	va_end(ap);
18997f17497SC.J. Collier#else
19097f17497SC.J. Collier	int ret;
19197f17497SC.J. Collier	char *buf;
19297f17497SC.J. Collier
19397f17497SC.J. Collier	if (cl->s_out < 0)
19497f17497SC.J. Collier		return;
19597f17497SC.J. Collier
19697f17497SC.J. Collier	buf = malloc(BUFSIZ);
19797f17497SC.J. Collier	if (buf == NULL)
19897f17497SC.J. Collier		return;
19997f17497SC.J. Collier	va_start(ap, fmt);
20097f17497SC.J. Collier	ret = vsnprintf(buf, BUFSIZ, fmt, ap);
20197f17497SC.J. Collier	va_end(ap);
20297f17497SC.J. Collier	if (ret < 0) {
20397f17497SC.J. Collier		free(buf);
20497f17497SC.J. Collier		return;
20597f17497SC.J. Collier	}
20697f17497SC.J. Collier	if (ret >= BUFSIZ)
20797f17497SC.J. Collier		ret = BUFSIZ - 1;
20847d9763aSLuca Boccassi	ret = write(cl->s_out, buf, ret);
20947d9763aSLuca Boccassi	(void)ret;
21097f17497SC.J. Collier	free(buf);
21197f17497SC.J. Collier#endif
21297f17497SC.J. Collier}
21397f17497SC.J. Collier
21497f17497SC.J. Collierint
21597f17497SC.J. Colliercmdline_in(struct cmdline *cl, const char *buf, int size)
21697f17497SC.J. Collier{
21797f17497SC.J. Collier	const char *history, *buffer;
21897f17497SC.J. Collier	size_t histlen, buflen;
21997f17497SC.J. Collier	int ret = 0;
22097f17497SC.J. Collier	int i, same;
22197f17497SC.J. Collier
22297f17497SC.J. Collier	if (!cl || !buf)
22397f17497SC.J. Collier		return -1;
22497f17497SC.J. Collier
22597f17497SC.J. Collier	for (i=0; i<size; i++) {
22697f17497SC.J. Collier		ret = rdline_char_in(&cl->rdl, buf[i]);
22797f17497SC.J. Collier
22897f17497SC.J. Collier		if (ret == RDLINE_RES_VALIDATED) {
22997f17497SC.J. Collier			buffer = rdline_get_buffer(&cl->rdl);
23097f17497SC.J. Collier			history = rdline_get_history_item(&cl->rdl, 0);
23197f17497SC.J. Collier			if (history) {
23297f17497SC.J. Collier				histlen = strnlen(history, RDLINE_BUF_SIZE);
23397f17497SC.J. Collier				same = !memcmp(buffer, history, histlen) &&
23497f17497SC.J. Collier					buffer[histlen] == '\n';
23597f17497SC.J. Collier			}
23697f17497SC.J. Collier			else
23797f17497SC.J. Collier				same = 0;
23897f17497SC.J. Collier			buflen = strnlen(buffer, RDLINE_BUF_SIZE);
23997f17497SC.J. Collier			if (buflen > 1 && !same)
24097f17497SC.J. Collier				rdline_add_history(&cl->rdl, buffer);
24197f17497SC.J. Collier			rdline_newline(&cl->rdl, cl->prompt);
24297f17497SC.J. Collier		}
24397f17497SC.J. Collier		else if (ret == RDLINE_RES_EOF)
24497f17497SC.J. Collier			return -1;
24597f17497SC.J. Collier		else if (ret == RDLINE_RES_EXITED)
24697f17497SC.J. Collier			return -1;
24797f17497SC.J. Collier	}
24897f17497SC.J. Collier	return i;
24997f17497SC.J. Collier}
25097f17497SC.J. Collier
25197f17497SC.J. Colliervoid
25297f17497SC.J. Colliercmdline_quit(struct cmdline *cl)
25397f17497SC.J. Collier{
25497f17497SC.J. Collier	if (!cl)
25597f17497SC.J. Collier		return;
25697f17497SC.J. Collier	rdline_quit(&cl->rdl);
25797f17497SC.J. Collier}
25897f17497SC.J. Collier
25997f17497SC.J. Collierint
26097f17497SC.J. Colliercmdline_poll(struct cmdline *cl)
26197f17497SC.J. Collier{
26297f17497SC.J. Collier	struct pollfd pfd;
26397f17497SC.J. Collier	int status;
26497f17497SC.J. Collier	ssize_t read_status;
26597f17497SC.J. Collier	char c;
26697f17497SC.J. Collier
26797f17497SC.J. Collier	if (!cl)
26897f17497SC.J. Collier		return -EINVAL;
26997f17497SC.J. Collier	else if (cl->rdl.status == RDLINE_EXITED)
27097f17497SC.J. Collier		return RDLINE_EXITED;
27197f17497SC.J. Collier
27297f17497SC.J. Collier	pfd.fd = cl->s_in;
27397f17497SC.J. Collier	pfd.events = POLLIN;
27497f17497SC.J. Collier	pfd.revents = 0;
27597f17497SC.J. Collier
27697f17497SC.J. Collier	status = poll(&pfd, 1, 0);
27797f17497SC.J. Collier	if (status < 0)
27897f17497SC.J. Collier		return status;
27997f17497SC.J. Collier	else if (status > 0) {
28097f17497SC.J. Collier		c = -1;
28197f17497SC.J. Collier		read_status = read(cl->s_in, &c, 1);
28297f17497SC.J. Collier		if (read_status < 0)
28397f17497SC.J. Collier			return read_status;
28497f17497SC.J. Collier
28597f17497SC.J. Collier		status = cmdline_in(cl, &c, 1);
28697f17497SC.J. Collier		if (status < 0 && cl->rdl.status != RDLINE_EXITED)
28797f17497SC.J. Collier			return status;
28897f17497SC.J. Collier	}
28997f17497SC.J. Collier
29097f17497SC.J. Collier	return cl->rdl.status;
29197f17497SC.J. Collier}
29297f17497SC.J. Collier
29397f17497SC.J. Colliervoid
29497f17497SC.J. Colliercmdline_interact(struct cmdline *cl)
29597f17497SC.J. Collier{
29697f17497SC.J. Collier	char c;
29797f17497SC.J. Collier
29897f17497SC.J. Collier	if (!cl)
29997f17497SC.J. Collier		return;
30097f17497SC.J. Collier
30197f17497SC.J. Collier	c = -1;
30297f17497SC.J. Collier	while (1) {
30397f17497SC.J. Collier		if (read(cl->s_in, &c, 1) <= 0)
30497f17497SC.J. Collier			break;
30597f17497SC.J. Collier		if (cmdline_in(cl, &c, 1) < 0)
30697f17497SC.J. Collier			break;
30797f17497SC.J. Collier	}
30897f17497SC.J. Collier}
309