1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <arpa/inet.h>
34 #ifdef HAVE___PROGNAME
35 extern const char *__progname
;
37 # define __progname "lldpcli"
40 /* Global for completion */
41 static struct cmd_node
*root
= NULL
;
46 fprintf(stderr
, "Usage: %s [OPTIONS ...] [COMMAND ...]\n", __progname
);
47 fprintf(stderr
, "Version: %s\n", PACKAGE_STRING
);
49 fprintf(stderr
, "\n");
51 fprintf(stderr
, "-d Enable more debugging information.\n");
52 fprintf(stderr
, "-f format Choose output format (plain, keyvalue or xml).\n");
54 fprintf(stderr
, "\n");
56 fprintf(stderr
, "see manual page lldpcli(8) for more information\n");
63 return (!(getuid() != geteuid() || getgid() != getegid()));
69 int privileged
= is_privileged();
71 return "[lldpcli] # ";
72 return "[lldpcli] $ ";
75 static int must_exit
= 0;
77 * Exit the interpreter.
80 cmd_exit(struct lldpctl_conn_t
*conn
, struct writer
*w
,
81 struct cmd_env
*env
, void *arg
)
83 log_info("lldpctl", "quit lldpcli");
89 * Send an "update" request.
92 cmd_update(struct lldpctl_conn_t
*conn
, struct writer
*w
,
93 struct cmd_env
*env
, void *arg
)
95 log_info("lldpctl", "ask for global update");
97 lldpctl_atom_t
*config
= lldpctl_get_configuration(conn
);
99 log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
100 lldpctl_last_strerror(conn
));
103 if (lldpctl_atom_set_int(config
,
104 lldpctl_k_config_tx_interval
, -1) == NULL
) {
105 log_warnx("lldpctl", "unable to ask lldpd for immediate retransmission. %s",
106 lldpctl_last_strerror(conn
));
107 lldpctl_atom_dec_ref(config
);
110 log_info("lldpctl", "immediate retransmission requested successfuly");
111 lldpctl_atom_dec_ref(config
);
116 _cmd_complete(EditLine
*el
, int ch
, int all
)
120 if ((eltok
= tok_init(NULL
)) == NULL
)
123 const LineInfo
*li
= el_line(el
);
127 int argc
, cursorc
, cursoro
;
128 if (tok_line(eltok
, li
, &argc
, &argv
, &cursorc
, &cursoro
) != 0)
130 compl = commands_complete(root
, argc
, argv
, cursorc
, cursoro
, all
);
132 el_deletestr(el
, cursoro
);
133 if (el_insertstr(el
, compl) == -1) {
141 /* No completion or several completion available. We beep. */
145 if (eltok
) tok_end(eltok
);
150 cmd_complete(EditLine
*el
, int ch
)
152 return _cmd_complete(el
, ch
, 0);
156 cmd_help(EditLine
*el
, int ch
)
158 return _cmd_complete(el
, ch
, 1);
161 static struct cmd_node
*
164 root
= commands_root();
165 register_commands_show(root
);
166 register_commands_watch(root
);
167 if (is_privileged()) {
169 commands_new(root
, "update", "Update information and send LLDPU on all ports",
171 NEWLINE
, "Update information and send LLDPU on all ports",
172 NULL
, cmd_update
, NULL
);
173 register_commands_configure(root
);
176 commands_new(root
, "exit", "Exit interpreter", NULL
, NULL
, NULL
),
177 NEWLINE
, "Exit interpreter", NULL
, cmd_exit
, NULL
);
182 is_lldpctl(const char *name
)
184 static int last_result
= -1;
185 if (last_result
== -1 && name
) {
186 char *basec
= strdup(name
);
187 if (!basec
) return 0;
188 char *bname
= basename(basec
);
189 last_result
= (!strcmp(bname
, "lldpctl"));
192 return (last_result
== -1)?0:last_result
;
196 main(int argc
, char *argv
[])
198 int ch
, debug
= 1, rc
= EXIT_FAILURE
;
200 lldpctl_conn_t
*conn
= NULL
;
204 History
*elhistory
= NULL
;
206 Tokenizer
*eltok
= NULL
;
208 char *interfaces
= NULL
;
210 /* Get and parse command line options */
211 while ((ch
= getopt(argc
, argv
, "hdvf:")) != -1) {
220 fprintf(stdout
, "%s\n", PACKAGE_VERSION
);
231 log_init(debug
, __progname
);
233 /* Register commands */
234 root
= register_commands();
236 if (is_lldpctl(argv
[0])) {
237 for (int i
= optind
; i
< argc
; i
++) {
238 char *prev
= interfaces
;
239 if (asprintf(&interfaces
, "%s%s%s",
240 prev
?prev
:"", prev
?",":"", argv
[i
]) == -1) {
241 log_warnx("lldpctl", "not enough memory to build list of interfaces");
250 /* More arguments! */
256 log_debug("lldpctl", "init editline");
257 el
= el_init("lldpctl", stdin
, stdout
, stderr
);
259 log_warnx("lldpctl", "unable to setup editline");
262 el_set(el
, EL_PROMPT
, prompt
);
263 el_set(el
, EL_SIGNAL
, 1);
264 el_set(el
, EL_EDITOR
, "emacs");
265 /* If on a TTY, setup completion */
266 if (isatty(STDERR_FILENO
)) {
267 el_set(el
, EL_ADDFN
, "command_complete",
268 "Execute completion", cmd_complete
);
269 el_set(el
, EL_ADDFN
, "command_help",
270 "Show completion", cmd_help
);
271 el_set(el
, EL_BIND
, "^I", "command_complete", NULL
);
272 el_set(el
, EL_BIND
, "?", "command_help", NULL
);
276 elhistory
= history_init();
277 if (elhistory
== NULL
) {
278 log_warnx("lldpctl", "unable to enable history");
280 history(elhistory
, &elhistev
, H_SETSIZE
, 800);
281 el_set(el
, EL_HIST
, history
, elhistory
);
285 eltok
= tok_init(NULL
);
287 log_warnx("lldpctl", "unable to initialize tokenizer");
292 /* Make a connection */
293 log_debug("lldpctl", "connect to lldpd");
294 conn
= lldpctl_new(NULL
, NULL
, NULL
);
303 if (!is_lldpctl(NULL
) && (optind
>= argc
)) {
304 /* Read a new line. */
305 line
= el_gets(el
, &count
);
306 if (line
== NULL
) break;
309 log_debug("lldpctl", "tokenize command line");
310 n
= tok_str(eltok
, line
, &cargc
, &cargv
);
313 log_warnx("lldpctl", "internal error while tokenizing");
318 /* TODO: handle multiline statements */
319 log_warnx("lldpctl", "unmatched quotes");
327 if (elhistory
) history(elhistory
, &elhistev
, H_ENTER
, line
);
330 /* Init output formatter */
331 if (strcmp(fmt
, "plain") == 0) w
= txt_init(stdout
);
332 else if (strcmp(fmt
, "keyvalue") == 0) w
= kv_init(stdout
);
334 else if (strcmp(fmt
, "xml") == 0) w
= xml_init(stdout
);
337 else if (strcmp(fmt
, "json") == 0) w
= json_init(stdout
);
339 else w
= txt_init(stdout
);
341 if (is_lldpctl(NULL
)) {
343 cargv
= (const char*[]){ "show", "neighbors", "details" };
346 cargv
= (const char*[]){ "show", "neighbors", "ports", interfaces
, "details" };
349 } else if (optind
< argc
) {
350 cargv
= (const char **)argv
;
351 cargv
= &cargv
[optind
];
352 cargc
= argc
- optind
;
355 /* Execute command */
356 if (commands_execute(conn
, w
,
357 root
, cargc
, cargv
) != 0)
358 log_info("lldpctl", "an error occurred while executing last command");
361 if (eltok
) tok_reset(eltok
);
362 } while (!must_exit
);
366 if (conn
) lldpctl_release(conn
);
367 if (eltok
) tok_end(eltok
);
368 if (elhistory
) history_end(elhistory
);
370 if (root
) commands_free(root
);