blob: 5602c5056b1ca31908fb6ed0a7c3cae2996a91d7 [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.
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +010020 */
21
22#define _GNU_SOURCE
23#include <getopt.h>
24#include <signal.h>
25#include <limits.h>
26#include <string.h>
27
28#include <osmocom/core/application.h>
29
30#include <osmocom/vty/command.h>
31#include <osmocom/vty/misc.h>
32#include <osmocom/vty/telnet_interface.h>
33
34#include <stdlib.h>
35
36#include "config.h"
37
38void *root_ctx = NULL;
39
Harald Weltee61d4592022-11-03 11:05:58 +010040static void print_help(void)
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +010041{
42 printf( "options:\n"
43 " -h --help this text\n"
44 " -d --debug MASK Enable debugging (e.g. -d DRSL:DOML:DLAPDM)\n"
45 " -D --daemonize For the process into a background daemon\n"
46 " -c --config-file Specify the filename of the config file\n"
47 " -s --disable-color Don't use colors in stderr log output\n"
48 " -T --timestamp Prefix every log line with a timestamp\n"
49 " -V --version Print version information and exit\n"
50 " -e --log-level Set a global log-level\n"
51 );
52}
53
54static struct {
55 const char *config_file;
56 int daemonize;
57} cmdline_config = {};
58
59static void handle_options(int argc, char **argv)
60{
61 while (1) {
62 int option_idx = 0, c;
63 static const struct option long_options[] = {
64 { "help", 0, 0, 'h' },
65 { "debug", 1, 0, 'd' },
66 { "daemonize", 0, 0, 'D' },
67 { "config-file", 1, 0, 'c' },
68 { "disable-color", 0, 0, 's' },
69 { "timestamp", 0, 0, 'T' },
70 { "version", 0, 0, 'V' },
71 { "log-level", 1, 0, 'e' },
72 {}
73 };
74
75 c = getopt_long(argc, argv, "hc:d:Dc:sTVe:",
76 long_options, &option_idx);
77 if (c == -1)
78 break;
79
80 switch (c) {
81 case 'h':
82 print_help();
83 exit(0);
84 case 's':
85 log_set_use_color(osmo_stderr_target, 0);
86 break;
87 case 'd':
88 log_parse_category_mask(osmo_stderr_target, optarg);
89 break;
90 case 'D':
91 cmdline_config.daemonize = 1;
92 break;
93 case 'c':
94 cmdline_config.config_file = optarg;
95 break;
96 case 'T':
97 log_set_print_timestamp(osmo_stderr_target, 1);
98 break;
99 case 'e':
100 log_set_log_level(osmo_stderr_target, atoi(optarg));
101 break;
102 case 'V':
103 print_version(1);
104 exit(0);
105 break;
106 default:
107 /* catch unknown options *as well as* missing arguments. */
108 fprintf(stderr, "Error in command line options. Exiting.\n");
109 exit(-1);
110 }
111 }
112}
113
114static int quit = 0;
115
116static void signal_handler(int signal)
117{
118 fprintf(stdout, "signal %u received\n", signal);
119
120 switch (signal) {
121 case SIGINT:
122 case SIGTERM:
123 quit++;
124 break;
125 case SIGABRT:
126 osmo_generate_backtrace();
127 /* in case of abort, we want to obtain a talloc report
128 * and then return to the caller, who will abort the process */
129 case SIGUSR1:
130 talloc_report(tall_vty_ctx, stderr);
131 talloc_report_full(root_ctx, stderr);
132 break;
133 case SIGUSR2:
134 talloc_report_full(tall_vty_ctx, stderr);
135 break;
136 default:
137 break;
138 }
139}
140
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700141/* Application specific VTY attributes */
142enum {
143 TEST_ATTR_UNBELIEVABLE,
144 TEST_ATTR_MAGNIFICENT,
145 TEST_ATTR_WONDERFUL,
146 TEST_ATTR_UNUSED,
147};
148
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100149static struct vty_app_info vty_info = {
150 .name = "vty_transcript_test",
151 .version = PACKAGE_VERSION,
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700152 .usr_attr_desc = {
153 /* Some random description strings, who cares... */
154 [TEST_ATTR_UNBELIEVABLE] = \
155 "Unbelievable: not able to be believed; unlikely to be true",
156 [TEST_ATTR_MAGNIFICENT] = \
157 "Magnificent: impressively beautiful, elaborate, or extravagant",
158 [TEST_ATTR_WONDERFUL] = \
159 "Wonderful: inspiring delight, pleasure, or admiration",
160 [TEST_ATTR_UNUSED] = \
161 "Intentionally unused attribute, ignore me",
162 },
163 .usr_attr_letters = {
164 [TEST_ATTR_UNBELIEVABLE] = 'u',
165 [TEST_ATTR_MAGNIFICENT] = 'm',
166 [TEST_ATTR_WONDERFUL] = 'w',
167 [TEST_ATTR_UNUSED] = 'n',
168 },
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100169};
170
171static const struct log_info_cat default_categories[] = {};
172
173const struct log_info log_info = {
174 .cat = default_categories,
175 .num_cat = ARRAY_SIZE(default_categories),
176};
177
Pau Espin Pedrol14aadd52019-06-12 18:34:34 +0200178DEFUN(single0, single0_cmd,
179 "single0 [one]",
180 "single0 test command\n" "1\n")
181{
182 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
183 return CMD_SUCCESS;
184}
185
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100186DEFUN(multi0, multi0_cmd,
187 "multi0 (one|two|three)",
188 "multi0 test command\n" "1\n2\n3\n")
189{
190 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
191 return CMD_SUCCESS;
192}
193
194DEFUN(multi1, multi1_cmd,
195 "multi1 ([one]|[two]|[three])",
196 "multi1 test command\n" "1\n2\n3\n")
197{
198 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
199 return CMD_SUCCESS;
200}
201
Neels Hofmeyrb55f4d22019-01-31 08:13:31 +0100202DEFUN(multi2, multi2_cmd,
203 "multi2 [(one|two|three)]",
204 "multi2 test command\n" "1\n2\n3\n")
205{
206 vty_out(vty, "ok argc=%d%s%s%s", argc, argc ? " " : "", argc ? argv[0] : "", VTY_NEWLINE);
207 return CMD_SUCCESS;
208}
209
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700210#define X(f) (1 << f)
211
212enum {
213 ATTR_TEST_NODE = _LAST_OSMOVTY_NODE + 1,
Neels Hofmeyrcc9b6992023-05-01 02:59:01 +0200214 NEST_A_NODE,
215 NEST_B_NODE,
216 NEST_C_NODE,
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700217};
218
219static struct cmd_node attr_test_node = {
220 ATTR_TEST_NODE,
221 "%s(config-attr-test)# ",
222 1
223};
224
225DEFUN(cfg_attr_test, cfg_attr_test_cmd,
226 "attribute-test",
227 "Enter attribute test node\n")
228{
229 vty->index = NULL;
230 vty->node = ATTR_TEST_NODE;
231 return CMD_SUCCESS;
232}
233
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700234DEFUN_DEPRECATED(cfg_attr_deprecated,
235 cfg_attr_deprecated_cmd,
236 "foo-deprecated",
237 "This command is deprecated\n")
238{
239 return CMD_WARNING;
240}
241
242DEFUN_HIDDEN(cfg_attr_hidden,
243 cfg_attr_hidden_cmd,
244 "foo-hidden [expert-mode]",
245 "This command is hidden\n"
246 "But can be seen in the expert mode\n")
247{
248 return CMD_SUCCESS;
249}
250
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700251DEFUN_ATTR(cfg_attr_immediate, cfg_attr_immediate_cmd,
252 "foo-immediate",
253 "Applies immediately\n",
254 CMD_ATTR_IMMEDIATE)
255{
256 return CMD_SUCCESS;
257}
258
259DEFUN_ATTR(cfg_attr_node_exit, cfg_attr_node_exit_cmd,
260 "foo-node-exit",
261 "Applies on node exit\n",
262 CMD_ATTR_NODE_EXIT)
263{
264 return CMD_SUCCESS;
265}
266
267DEFUN_USRATTR(cfg_app_attr_unbelievable,
268 cfg_app_attr_unbelievable_cmd,
269 X(TEST_ATTR_UNBELIEVABLE),
270 "app-unbelievable",
271 "Unbelievable help message\n")
272{
273 return CMD_SUCCESS;
274}
275
276DEFUN_USRATTR(cfg_app_attr_magnificent,
277 cfg_app_attr_magnificent_cmd,
278 X(TEST_ATTR_MAGNIFICENT),
279 "app-magnificent",
280 "Magnificent help message\n")
281{
282 return CMD_SUCCESS;
283}
284
285DEFUN_USRATTR(cfg_app_attr_wonderful,
286 cfg_app_attr_wonderful_cmd,
287 X(TEST_ATTR_WONDERFUL),
288 "app-wonderful",
289 "Wonderful help message\n")
290{
291 return CMD_SUCCESS;
292}
293
294DEFUN_USRATTR(cfg_app_attr_unbelievable_magnificent,
295 cfg_app_attr_unbelievable_magnificent_cmd,
296 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_MAGNIFICENT),
297 "app-unbelievable-magnificent",
298 "Unbelievable & magnificent help message\n")
299{
300 return CMD_SUCCESS;
301}
302
303DEFUN_USRATTR(cfg_app_attr_unbelievable_wonderful,
304 cfg_app_attr_unbelievable_wonderful_cmd,
305 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_WONDERFUL),
306 "app-unbelievable-wonderful",
307 "Unbelievable & wonderful help message\n")
308{
309 return CMD_SUCCESS;
310}
311
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700312DEFUN_ATTR_USRATTR(cfg_attr_hidden_app_attr_unbelievable,
313 cfg_attr_hidden_app_attr_unbelievable_cmd,
314 CMD_ATTR_HIDDEN, X(TEST_ATTR_UNBELIEVABLE),
315 "app-hidden-unbelievable",
316 "Hidden, but still unbelievable help message\n")
317{
318 return CMD_SUCCESS;
319}
320
Neels Hofmeyrcc9b6992023-05-01 02:59:01 +0200321static struct cmd_node nest_a_node = {
322 NEST_A_NODE,
323 "%s(config-a)# ",
324 1
325};
326
327static struct cmd_node nest_b_node = {
328 NEST_B_NODE,
329 "%s(config-b)# ",
330 1
331};
332
333static struct cmd_node nest_c_node = {
334 NEST_C_NODE,
335 "%s(config-c)# ",
336 1
337};
338
339DEFUN(cfg_nest_a, cfg_nest_a_cmd,
340 "nest NAME",
341 "Enter nest level a\n"
342 "Set a name to mark the node's state\n")
343{
344 vty->index = talloc_strdup(root_ctx, argv[0]);
345 vty->node = NEST_A_NODE;
346 return CMD_SUCCESS;
347}
348
349DEFUN(cfg_nest_b, cfg_nest_b_cmd,
350 "nest NAME",
351 "Enter nest level b\n"
352 "Set a name to mark the node's state\n")
353{
354 vty->index = talloc_strdup(root_ctx, argv[0]);
355 vty->node = NEST_B_NODE;
356 return CMD_SUCCESS;
357}
358
359DEFUN(cfg_nest_c, cfg_nest_c_cmd,
360 "nest NAME",
361 "Enter nest level c\n"
362 "Set a name to mark the node's state\n")
363{
364 vty->index = talloc_strdup(root_ctx, argv[0]);
365 vty->node = NEST_C_NODE;
366 return CMD_SUCCESS;
367}
368
369DEFUN(cfg_nest_state, cfg_nest_state_cmd,
370 "state",
371 "Show this node's mark\n")
372{
373 vty_out(vty, "%s%s", (const char *)vty->index, VTY_NEWLINE);
374 return CMD_SUCCESS;
375}
376
Harald Weltee61d4592022-11-03 11:05:58 +0100377static void init_vty_cmds(void)
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100378{
Pau Espin Pedrol14aadd52019-06-12 18:34:34 +0200379 install_element_ve(&single0_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100380 install_element_ve(&multi0_cmd);
381 install_element_ve(&multi1_cmd);
Neels Hofmeyrb55f4d22019-01-31 08:13:31 +0100382 install_element_ve(&multi2_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700383
384 install_element(CONFIG_NODE, &cfg_attr_test_cmd);
385 install_node(&attr_test_node, NULL);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700386 install_element(ATTR_TEST_NODE, &cfg_attr_deprecated_cmd);
387 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700388 install_element(ATTR_TEST_NODE, &cfg_attr_immediate_cmd);
389 install_element(ATTR_TEST_NODE, &cfg_attr_node_exit_cmd);
390
391 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_cmd);
392 install_element(ATTR_TEST_NODE, &cfg_app_attr_magnificent_cmd);
393 install_element(ATTR_TEST_NODE, &cfg_app_attr_wonderful_cmd);
394
395 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_magnificent_cmd);
396 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_wonderful_cmd);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700397 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_app_attr_unbelievable_cmd);
Neels Hofmeyrcc9b6992023-05-01 02:59:01 +0200398
399 install_element(CONFIG_NODE, &cfg_nest_a_cmd);
400 install_node(&nest_a_node, NULL);
401 install_element(NEST_A_NODE, &cfg_nest_b_cmd);
402 install_node(&nest_b_node, NULL);
403 install_element(NEST_B_NODE, &cfg_nest_c_cmd);
404 install_node(&nest_c_node, NULL);
405
406 install_element(NEST_A_NODE, &cfg_nest_state_cmd);
407 install_element(NEST_B_NODE, &cfg_nest_state_cmd);
408 install_element(NEST_C_NODE, &cfg_nest_state_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100409}
410
411int main(int argc, char **argv)
412{
413 int rc;
414
415 root_ctx = talloc_named_const(NULL, 0, "vty_transcript_test");
416
417 vty_info.tall_ctx = root_ctx;
418 vty_init(&vty_info);
419 osmo_talloc_vty_add_cmds();
420 init_vty_cmds();
421
422 osmo_init_logging2(root_ctx, &log_info);
423
424 handle_options(argc, argv);
425
426 if (cmdline_config.config_file) {
427 rc = vty_read_config_file(cmdline_config.config_file, NULL);
428 if (rc < 0) {
429 fprintf(stderr, "Failed to parse the config file: '%s'\n", cmdline_config.config_file);
430 return 1;
431 }
432 }
433
arehbein0aa84cf2023-01-27 00:49:45 +0100434 rc = telnet_init_default(root_ctx, NULL, 42042);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100435 if (rc < 0)
436 return 2;
437
438 signal(SIGINT, &signal_handler);
439 signal(SIGTERM, &signal_handler);
440 signal(SIGABRT, &signal_handler);
441 signal(SIGUSR1, &signal_handler);
442 signal(SIGUSR2, &signal_handler);
443 osmo_init_ignore_signals();
444
445 if (cmdline_config.daemonize) {
446 rc = osmo_daemonize();
447 if (rc < 0) {
448 perror("Error during daemonize");
449 return 6;
450 }
451 }
452
453 while (!quit) {
454 log_reset_context();
455 osmo_select_main(0);
456 }
457
458 talloc_free(root_ctx);
459 talloc_free(tall_vty_ctx);
460
461 return 0;
462}