blob: c9ecf186db44c48ef2276a8fb17854f3ae23a9a5 [file] [log] [blame]
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +01001/* Test implementation for VTY transcript testing. */
2/*
3 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 *
5 * All Rights Reserved
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#define _GNU_SOURCE
27#include <getopt.h>
28#include <signal.h>
29#include <limits.h>
30#include <string.h>
31
32#include <osmocom/core/application.h>
33
34#include <osmocom/vty/command.h>
35#include <osmocom/vty/misc.h>
36#include <osmocom/vty/telnet_interface.h>
37
38#include <stdlib.h>
39
40#include "config.h"
41
42void *root_ctx = NULL;
43
44static void print_help()
45{
46 printf( "options:\n"
47 " -h --help this text\n"
48 " -d --debug MASK Enable debugging (e.g. -d DRSL:DOML:DLAPDM)\n"
49 " -D --daemonize For the process into a background daemon\n"
50 " -c --config-file Specify the filename of the config file\n"
51 " -s --disable-color Don't use colors in stderr log output\n"
52 " -T --timestamp Prefix every log line with a timestamp\n"
53 " -V --version Print version information and exit\n"
54 " -e --log-level Set a global log-level\n"
55 );
56}
57
58static struct {
59 const char *config_file;
60 int daemonize;
61} cmdline_config = {};
62
63static void handle_options(int argc, char **argv)
64{
65 while (1) {
66 int option_idx = 0, c;
67 static const struct option long_options[] = {
68 { "help", 0, 0, 'h' },
69 { "debug", 1, 0, 'd' },
70 { "daemonize", 0, 0, 'D' },
71 { "config-file", 1, 0, 'c' },
72 { "disable-color", 0, 0, 's' },
73 { "timestamp", 0, 0, 'T' },
74 { "version", 0, 0, 'V' },
75 { "log-level", 1, 0, 'e' },
76 {}
77 };
78
79 c = getopt_long(argc, argv, "hc:d:Dc:sTVe:",
80 long_options, &option_idx);
81 if (c == -1)
82 break;
83
84 switch (c) {
85 case 'h':
86 print_help();
87 exit(0);
88 case 's':
89 log_set_use_color(osmo_stderr_target, 0);
90 break;
91 case 'd':
92 log_parse_category_mask(osmo_stderr_target, optarg);
93 break;
94 case 'D':
95 cmdline_config.daemonize = 1;
96 break;
97 case 'c':
98 cmdline_config.config_file = optarg;
99 break;
100 case 'T':
101 log_set_print_timestamp(osmo_stderr_target, 1);
102 break;
103 case 'e':
104 log_set_log_level(osmo_stderr_target, atoi(optarg));
105 break;
106 case 'V':
107 print_version(1);
108 exit(0);
109 break;
110 default:
111 /* catch unknown options *as well as* missing arguments. */
112 fprintf(stderr, "Error in command line options. Exiting.\n");
113 exit(-1);
114 }
115 }
116}
117
118static int quit = 0;
119
120static void signal_handler(int signal)
121{
122 fprintf(stdout, "signal %u received\n", signal);
123
124 switch (signal) {
125 case SIGINT:
126 case SIGTERM:
127 quit++;
128 break;
129 case SIGABRT:
130 osmo_generate_backtrace();
131 /* in case of abort, we want to obtain a talloc report
132 * and then return to the caller, who will abort the process */
133 case SIGUSR1:
134 talloc_report(tall_vty_ctx, stderr);
135 talloc_report_full(root_ctx, stderr);
136 break;
137 case SIGUSR2:
138 talloc_report_full(tall_vty_ctx, stderr);
139 break;
140 default:
141 break;
142 }
143}
144
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700145/* Application specific VTY attributes */
146enum {
147 TEST_ATTR_UNBELIEVABLE,
148 TEST_ATTR_MAGNIFICENT,
149 TEST_ATTR_WONDERFUL,
150 TEST_ATTR_UNUSED,
151};
152
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100153static struct vty_app_info vty_info = {
154 .name = "vty_transcript_test",
155 .version = PACKAGE_VERSION,
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700156 .usr_attr_desc = {
157 /* Some random description strings, who cares... */
158 [TEST_ATTR_UNBELIEVABLE] = \
159 "Unbelievable: not able to be believed; unlikely to be true",
160 [TEST_ATTR_MAGNIFICENT] = \
161 "Magnificent: impressively beautiful, elaborate, or extravagant",
162 [TEST_ATTR_WONDERFUL] = \
163 "Wonderful: inspiring delight, pleasure, or admiration",
164 [TEST_ATTR_UNUSED] = \
165 "Intentionally unused attribute, ignore me",
166 },
167 .usr_attr_letters = {
168 [TEST_ATTR_UNBELIEVABLE] = 'u',
169 [TEST_ATTR_MAGNIFICENT] = 'm',
170 [TEST_ATTR_WONDERFUL] = 'w',
171 [TEST_ATTR_UNUSED] = 'n',
172 },
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100173};
174
175static const struct log_info_cat default_categories[] = {};
176
177const struct log_info log_info = {
178 .cat = default_categories,
179 .num_cat = ARRAY_SIZE(default_categories),
180};
181
Pau Espin Pedrol14aadd52019-06-12 18:34:34 +0200182DEFUN(single0, single0_cmd,
183 "single0 [one]",
184 "single0 test command\n" "1\n")
185{
186 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
187 return CMD_SUCCESS;
188}
189
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100190DEFUN(multi0, multi0_cmd,
191 "multi0 (one|two|three)",
192 "multi0 test command\n" "1\n2\n3\n")
193{
194 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
195 return CMD_SUCCESS;
196}
197
198DEFUN(multi1, multi1_cmd,
199 "multi1 ([one]|[two]|[three])",
200 "multi1 test command\n" "1\n2\n3\n")
201{
202 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
203 return CMD_SUCCESS;
204}
205
Neels Hofmeyrb55f4d22019-01-31 08:13:31 +0100206DEFUN(multi2, multi2_cmd,
207 "multi2 [(one|two|three)]",
208 "multi2 test command\n" "1\n2\n3\n")
209{
210 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
211 return CMD_SUCCESS;
212}
213
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700214#define X(f) (1 << f)
215
216enum {
217 ATTR_TEST_NODE = _LAST_OSMOVTY_NODE + 1,
218};
219
220static struct cmd_node attr_test_node = {
221 ATTR_TEST_NODE,
222 "%s(config-attr-test)# ",
223 1
224};
225
226DEFUN(cfg_attr_test, cfg_attr_test_cmd,
227 "attribute-test",
228 "Enter attribute test node\n")
229{
230 vty->index = NULL;
231 vty->node = ATTR_TEST_NODE;
232 return CMD_SUCCESS;
233}
234
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700235DEFUN_DEPRECATED(cfg_attr_deprecated,
236 cfg_attr_deprecated_cmd,
237 "foo-deprecated",
238 "This command is deprecated\n")
239{
240 return CMD_WARNING;
241}
242
243DEFUN_HIDDEN(cfg_attr_hidden,
244 cfg_attr_hidden_cmd,
245 "foo-hidden [expert-mode]",
246 "This command is hidden\n"
247 "But can be seen in the expert mode\n")
248{
249 return CMD_SUCCESS;
250}
251
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700252DEFUN_ATTR(cfg_attr_immediate, cfg_attr_immediate_cmd,
253 "foo-immediate",
254 "Applies immediately\n",
255 CMD_ATTR_IMMEDIATE)
256{
257 return CMD_SUCCESS;
258}
259
260DEFUN_ATTR(cfg_attr_node_exit, cfg_attr_node_exit_cmd,
261 "foo-node-exit",
262 "Applies on node exit\n",
263 CMD_ATTR_NODE_EXIT)
264{
265 return CMD_SUCCESS;
266}
267
268DEFUN_USRATTR(cfg_app_attr_unbelievable,
269 cfg_app_attr_unbelievable_cmd,
270 X(TEST_ATTR_UNBELIEVABLE),
271 "app-unbelievable",
272 "Unbelievable help message\n")
273{
274 return CMD_SUCCESS;
275}
276
277DEFUN_USRATTR(cfg_app_attr_magnificent,
278 cfg_app_attr_magnificent_cmd,
279 X(TEST_ATTR_MAGNIFICENT),
280 "app-magnificent",
281 "Magnificent help message\n")
282{
283 return CMD_SUCCESS;
284}
285
286DEFUN_USRATTR(cfg_app_attr_wonderful,
287 cfg_app_attr_wonderful_cmd,
288 X(TEST_ATTR_WONDERFUL),
289 "app-wonderful",
290 "Wonderful help message\n")
291{
292 return CMD_SUCCESS;
293}
294
295DEFUN_USRATTR(cfg_app_attr_unbelievable_magnificent,
296 cfg_app_attr_unbelievable_magnificent_cmd,
297 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_MAGNIFICENT),
298 "app-unbelievable-magnificent",
299 "Unbelievable & magnificent help message\n")
300{
301 return CMD_SUCCESS;
302}
303
304DEFUN_USRATTR(cfg_app_attr_unbelievable_wonderful,
305 cfg_app_attr_unbelievable_wonderful_cmd,
306 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_WONDERFUL),
307 "app-unbelievable-wonderful",
308 "Unbelievable & wonderful help message\n")
309{
310 return CMD_SUCCESS;
311}
312
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700313DEFUN_ATTR_USRATTR(cfg_attr_hidden_app_attr_unbelievable,
314 cfg_attr_hidden_app_attr_unbelievable_cmd,
315 CMD_ATTR_HIDDEN, X(TEST_ATTR_UNBELIEVABLE),
316 "app-hidden-unbelievable",
317 "Hidden, but still unbelievable help message\n")
318{
319 return CMD_SUCCESS;
320}
321
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100322static void init_vty_cmds()
323{
Pau Espin Pedrol14aadd52019-06-12 18:34:34 +0200324 install_element_ve(&single0_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100325 install_element_ve(&multi0_cmd);
326 install_element_ve(&multi1_cmd);
Neels Hofmeyrb55f4d22019-01-31 08:13:31 +0100327 install_element_ve(&multi2_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700328
329 install_element(CONFIG_NODE, &cfg_attr_test_cmd);
330 install_node(&attr_test_node, NULL);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700331 install_element(ATTR_TEST_NODE, &cfg_attr_deprecated_cmd);
332 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700333 install_element(ATTR_TEST_NODE, &cfg_attr_immediate_cmd);
334 install_element(ATTR_TEST_NODE, &cfg_attr_node_exit_cmd);
335
336 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_cmd);
337 install_element(ATTR_TEST_NODE, &cfg_app_attr_magnificent_cmd);
338 install_element(ATTR_TEST_NODE, &cfg_app_attr_wonderful_cmd);
339
340 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_magnificent_cmd);
341 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_wonderful_cmd);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700342 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_app_attr_unbelievable_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100343}
344
345int main(int argc, char **argv)
346{
347 int rc;
348
349 root_ctx = talloc_named_const(NULL, 0, "vty_transcript_test");
350
351 vty_info.tall_ctx = root_ctx;
352 vty_init(&vty_info);
353 osmo_talloc_vty_add_cmds();
354 init_vty_cmds();
355
356 osmo_init_logging2(root_ctx, &log_info);
357
358 handle_options(argc, argv);
359
360 if (cmdline_config.config_file) {
361 rc = vty_read_config_file(cmdline_config.config_file, NULL);
362 if (rc < 0) {
363 fprintf(stderr, "Failed to parse the config file: '%s'\n", cmdline_config.config_file);
364 return 1;
365 }
366 }
367
368 rc = telnet_init_dynif(root_ctx, NULL, vty_get_bind_addr(), 42042);
369 if (rc < 0)
370 return 2;
371
372 signal(SIGINT, &signal_handler);
373 signal(SIGTERM, &signal_handler);
374 signal(SIGABRT, &signal_handler);
375 signal(SIGUSR1, &signal_handler);
376 signal(SIGUSR2, &signal_handler);
377 osmo_init_ignore_signals();
378
379 if (cmdline_config.daemonize) {
380 rc = osmo_daemonize();
381 if (rc < 0) {
382 perror("Error during daemonize");
383 return 6;
384 }
385 }
386
387 while (!quit) {
388 log_reset_context();
389 osmo_select_main(0);
390 }
391
392 talloc_free(root_ctx);
393 talloc_free(tall_vty_ctx);
394
395 return 0;
396}