1/*
2 * Common hostapd/wpa_supplicant command line interface functions
3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "utils/common.h"
12#include "common/cli.h"
13
14
15const char *const cli_license =
16"This software may be distributed under the terms of the BSD license.\n"
17"See README for more details.\n";
18
19const char *const cli_full_license =
20"This software may be distributed under the terms of the BSD license.\n"
21"\n"
22"Redistribution and use in source and binary forms, with or without\n"
23"modification, are permitted provided that the following conditions are\n"
24"met:\n"
25"\n"
26"1. Redistributions of source code must retain the above copyright\n"
27"   notice, this list of conditions and the following disclaimer.\n"
28"\n"
29"2. Redistributions in binary form must reproduce the above copyright\n"
30"   notice, this list of conditions and the following disclaimer in the\n"
31"   documentation and/or other materials provided with the distribution.\n"
32"\n"
33"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
34"   names of its contributors may be used to endorse or promote products\n"
35"   derived from this software without specific prior written permission.\n"
36"\n"
37"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
38"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
39"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
40"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
41"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
42"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
43"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
44"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
45"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
46"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
47"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
48"\n";
49
50
51void cli_txt_list_free(struct cli_txt_entry *e)
52{
53	dl_list_del(&e->list);
54	os_free(e->txt);
55	os_free(e);
56}
57
58
59void cli_txt_list_flush(struct dl_list *list)
60{
61	struct cli_txt_entry *e;
62
63	while ((e = dl_list_first(list, struct cli_txt_entry, list)))
64		cli_txt_list_free(e);
65}
66
67
68struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
69					const char *txt)
70{
71	struct cli_txt_entry *e;
72
73	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
74		if (os_strcmp(e->txt, txt) == 0)
75			return e;
76	}
77	return NULL;
78}
79
80
81void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
82{
83	struct cli_txt_entry *e;
84
85	e = cli_txt_list_get(txt_list, txt);
86	if (e)
87		cli_txt_list_free(e);
88}
89
90
91void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
92{
93	u8 addr[ETH_ALEN];
94	char buf[18];
95
96	if (hwaddr_aton(txt, addr) < 0)
97		return;
98	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
99	cli_txt_list_del(txt_list, buf);
100}
101
102
103void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
104			   int separator)
105{
106	const char *end;
107	char *buf;
108
109	end = os_strchr(txt, separator);
110	if (end == NULL)
111		end = txt + os_strlen(txt);
112	buf = dup_binstr(txt, end - txt);
113	if (buf == NULL)
114		return;
115	cli_txt_list_del(txt_list, buf);
116	os_free(buf);
117}
118
119
120int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
121{
122	struct cli_txt_entry *e;
123
124	e = cli_txt_list_get(txt_list, txt);
125	if (e)
126		return 0;
127	e = os_zalloc(sizeof(*e));
128	if (e == NULL)
129		return -1;
130	e->txt = os_strdup(txt);
131	if (e->txt == NULL) {
132		os_free(e);
133		return -1;
134	}
135	dl_list_add(txt_list, &e->list);
136	return 0;
137}
138
139
140int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
141{
142	u8 addr[ETH_ALEN];
143	char buf[18];
144
145	if (hwaddr_aton(txt, addr) < 0)
146		return -1;
147	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
148	return cli_txt_list_add(txt_list, buf);
149}
150
151
152int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
153			  int separator)
154{
155	const char *end;
156	char *buf;
157	int ret;
158
159	end = os_strchr(txt, separator);
160	if (end == NULL)
161		end = txt + os_strlen(txt);
162	buf = dup_binstr(txt, end - txt);
163	if (buf == NULL)
164		return -1;
165	ret = cli_txt_list_add(txt_list, buf);
166	os_free(buf);
167	return ret;
168}
169
170
171char ** cli_txt_list_array(struct dl_list *txt_list)
172{
173	unsigned int i, count = dl_list_len(txt_list);
174	char **res;
175	struct cli_txt_entry *e;
176
177	res = os_calloc(count + 1, sizeof(char *));
178	if (res == NULL)
179		return NULL;
180
181	i = 0;
182	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
183		res[i] = os_strdup(e->txt);
184		if (res[i] == NULL)
185			break;
186		i++;
187	}
188
189	return res;
190}
191
192
193int get_cmd_arg_num(const char *str, int pos)
194{
195	int arg = 0, i;
196
197	for (i = 0; i <= pos; i++) {
198		if (str[i] != ' ') {
199			arg++;
200			while (i <= pos && str[i] != ' ')
201				i++;
202		}
203	}
204
205	if (arg > 0)
206		arg--;
207	return arg;
208}
209
210
211int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
212{
213	int i, res;
214	char *pos, *end;
215
216	pos = buf;
217	end = buf + buflen;
218
219	res = os_snprintf(pos, end - pos, "%s", cmd);
220	if (os_snprintf_error(end - pos, res))
221		goto fail;
222	pos += res;
223
224	for (i = 0; i < argc; i++) {
225		res = os_snprintf(pos, end - pos, " %s", argv[i]);
226		if (os_snprintf_error(end - pos, res))
227			goto fail;
228		pos += res;
229	}
230
231	buf[buflen - 1] = '\0';
232	return 0;
233
234fail:
235	printf("Too long command\n");
236	return -1;
237}
238
239
240int tokenize_cmd(char *cmd, char *argv[])
241{
242	char *pos;
243	int argc = 0;
244
245	pos = cmd;
246	for (;;) {
247		while (*pos == ' ')
248			pos++;
249		if (*pos == '\0')
250			break;
251		argv[argc] = pos;
252		argc++;
253		if (argc == max_args)
254			break;
255		if (*pos == '"') {
256			char *pos2 = os_strrchr(pos, '"');
257			if (pos2)
258				pos = pos2 + 1;
259		}
260		while (*pos != '\0' && *pos != ' ')
261			pos++;
262		if (*pos == ' ')
263			*pos++ = '\0';
264	}
265
266	return argc;
267}
268