blob: 84664f92ceabebb20c442b1dedacf2b91dd5f201 [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
40static void print_help()
41{
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,
214};
215
216static struct cmd_node attr_test_node = {
217 ATTR_TEST_NODE,
218 "%s(config-attr-test)# ",
219 1
220};
221
222DEFUN(cfg_attr_test, cfg_attr_test_cmd,
223 "attribute-test",
224 "Enter attribute test node\n")
225{
226 vty->index = NULL;
227 vty->node = ATTR_TEST_NODE;
228 return CMD_SUCCESS;
229}
230
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700231DEFUN_DEPRECATED(cfg_attr_deprecated,
232 cfg_attr_deprecated_cmd,
233 "foo-deprecated",
234 "This command is deprecated\n")
235{
236 return CMD_WARNING;
237}
238
239DEFUN_HIDDEN(cfg_attr_hidden,
240 cfg_attr_hidden_cmd,
241 "foo-hidden [expert-mode]",
242 "This command is hidden\n"
243 "But can be seen in the expert mode\n")
244{
245 return CMD_SUCCESS;
246}
247
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700248DEFUN_ATTR(cfg_attr_immediate, cfg_attr_immediate_cmd,
249 "foo-immediate",
250 "Applies immediately\n",
251 CMD_ATTR_IMMEDIATE)
252{
253 return CMD_SUCCESS;
254}
255
256DEFUN_ATTR(cfg_attr_node_exit, cfg_attr_node_exit_cmd,
257 "foo-node-exit",
258 "Applies on node exit\n",
259 CMD_ATTR_NODE_EXIT)
260{
261 return CMD_SUCCESS;
262}
263
264DEFUN_USRATTR(cfg_app_attr_unbelievable,
265 cfg_app_attr_unbelievable_cmd,
266 X(TEST_ATTR_UNBELIEVABLE),
267 "app-unbelievable",
268 "Unbelievable help message\n")
269{
270 return CMD_SUCCESS;
271}
272
273DEFUN_USRATTR(cfg_app_attr_magnificent,
274 cfg_app_attr_magnificent_cmd,
275 X(TEST_ATTR_MAGNIFICENT),
276 "app-magnificent",
277 "Magnificent help message\n")
278{
279 return CMD_SUCCESS;
280}
281
282DEFUN_USRATTR(cfg_app_attr_wonderful,
283 cfg_app_attr_wonderful_cmd,
284 X(TEST_ATTR_WONDERFUL),
285 "app-wonderful",
286 "Wonderful help message\n")
287{
288 return CMD_SUCCESS;
289}
290
291DEFUN_USRATTR(cfg_app_attr_unbelievable_magnificent,
292 cfg_app_attr_unbelievable_magnificent_cmd,
293 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_MAGNIFICENT),
294 "app-unbelievable-magnificent",
295 "Unbelievable & magnificent help message\n")
296{
297 return CMD_SUCCESS;
298}
299
300DEFUN_USRATTR(cfg_app_attr_unbelievable_wonderful,
301 cfg_app_attr_unbelievable_wonderful_cmd,
302 X(TEST_ATTR_UNBELIEVABLE) | X(TEST_ATTR_WONDERFUL),
303 "app-unbelievable-wonderful",
304 "Unbelievable & wonderful help message\n")
305{
306 return CMD_SUCCESS;
307}
308
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700309DEFUN_ATTR_USRATTR(cfg_attr_hidden_app_attr_unbelievable,
310 cfg_attr_hidden_app_attr_unbelievable_cmd,
311 CMD_ATTR_HIDDEN, X(TEST_ATTR_UNBELIEVABLE),
312 "app-hidden-unbelievable",
313 "Hidden, but still unbelievable help message\n")
314{
315 return CMD_SUCCESS;
316}
317
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100318static void init_vty_cmds()
319{
Pau Espin Pedrol14aadd52019-06-12 18:34:34 +0200320 install_element_ve(&single0_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100321 install_element_ve(&multi0_cmd);
322 install_element_ve(&multi1_cmd);
Neels Hofmeyrb55f4d22019-01-31 08:13:31 +0100323 install_element_ve(&multi2_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700324
325 install_element(CONFIG_NODE, &cfg_attr_test_cmd);
326 install_node(&attr_test_node, NULL);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700327 install_element(ATTR_TEST_NODE, &cfg_attr_deprecated_cmd);
328 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_cmd);
Vadim Yanitskiy9a28d3c2020-10-07 02:47:52 +0700329 install_element(ATTR_TEST_NODE, &cfg_attr_immediate_cmd);
330 install_element(ATTR_TEST_NODE, &cfg_attr_node_exit_cmd);
331
332 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_cmd);
333 install_element(ATTR_TEST_NODE, &cfg_app_attr_magnificent_cmd);
334 install_element(ATTR_TEST_NODE, &cfg_app_attr_wonderful_cmd);
335
336 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_magnificent_cmd);
337 install_element(ATTR_TEST_NODE, &cfg_app_attr_unbelievable_wonderful_cmd);
Vadim Yanitskiy72b90882020-10-21 05:07:34 +0700338 install_element(ATTR_TEST_NODE, &cfg_attr_hidden_app_attr_unbelievable_cmd);
Neels Hofmeyrfaa49e22019-01-31 09:06:53 +0100339}
340
341int main(int argc, char **argv)
342{
343 int rc;
344
345 root_ctx = talloc_named_const(NULL, 0, "vty_transcript_test");
346
347 vty_info.tall_ctx = root_ctx;
348 vty_init(&vty_info);
349 osmo_talloc_vty_add_cmds();
350 init_vty_cmds();
351
352 osmo_init_logging2(root_ctx, &log_info);
353
354 handle_options(argc, argv);
355
356 if (cmdline_config.config_file) {
357 rc = vty_read_config_file(cmdline_config.config_file, NULL);
358 if (rc < 0) {
359 fprintf(stderr, "Failed to parse the config file: '%s'\n", cmdline_config.config_file);
360 return 1;
361 }
362 }
363
364 rc = telnet_init_dynif(root_ctx, NULL, vty_get_bind_addr(), 42042);
365 if (rc < 0)
366 return 2;
367
368 signal(SIGINT, &signal_handler);
369 signal(SIGTERM, &signal_handler);
370 signal(SIGABRT, &signal_handler);
371 signal(SIGUSR1, &signal_handler);
372 signal(SIGUSR2, &signal_handler);
373 osmo_init_ignore_signals();
374
375 if (cmdline_config.daemonize) {
376 rc = osmo_daemonize();
377 if (rc < 0) {
378 perror("Error during daemonize");
379 return 6;
380 }
381 }
382
383 while (!quit) {
384 log_reset_context();
385 osmo_select_main(0);
386 }
387
388 talloc_free(root_ctx);
389 talloc_free(tall_vty_ctx);
390
391 return 0;
392}