1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 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.
20 #include <sys/queue.h>
21 #include <sys/types.h>
24 #include <sys/socket.h>
29 * An element of the environment (a key and a value).
32 TAILQ_ENTRY(cmd_env_el
) next
; /**< Next environment element */
33 const char *key
; /**< Key for this element */
34 const char *value
; /**< Value for this element */
40 struct cmd_env_stack
{
41 TAILQ_ENTRY(cmd_env_stack
) next
; /**< Next element, down the stack */
42 struct cmd_node
*el
; /**< Stored element */
46 * Structure representing an environment for the current command.
48 * An environment is a list of values stored for use for the function executing
49 * as well as the current command, the current position in the command and a
53 TAILQ_HEAD(, cmd_env_el
) elements
; /**< List of environment variables */
54 TAILQ_HEAD(, cmd_env_stack
) stack
; /**< Stack */
55 int argc
; /**< Number of argument in the command */
56 int argp
; /**< Current argument */
57 const char **argv
; /**< Arguments */
61 * Structure representing a command node.
63 * Such a node contains a token accepted to enter the node (or @c NULL if there
64 * is no token needed), a documentation string to present the user, a function
65 * to validate the user input (or @c NULL if no function is needed) and a
66 * function to execute when entering the node. Because we can enter a node just
67 * by completing, the execution part should have no other effect than modifying
68 * the environment, with the exception of execution on @c NEWLINE (which cannot
69 * happen when completing).
72 TAILQ_ENTRY(cmd_node
) next
; /**< Next sibling */
74 const char *token
; /**< Token to enter this cnode */
75 const char *doc
; /**< Documentation string */
76 int privileged
; /**< Privileged command? */
77 int lock
; /**< Lock required for execution? */
78 int hidden
; /**< Hidden command? */
81 * Function validating entry in this node. Can be @c NULL.
83 int (*validate
)(struct cmd_env
*, const void *);
85 * Function to execute when entering this node. May be @c NULL.
87 * This function can alter the environment
89 int (*execute
)(struct lldpctl_conn_t
*, struct writer
*, struct cmd_env
*,
91 const void *arg
; /**< Magic argument for the previous two functions */
93 /* List of possible subentries */
94 TAILQ_HEAD(, cmd_node
) subentries
; /* List of subnodes */
100 * @return the root node.
105 struct cmd_node
*new = calloc(1, sizeof(struct cmd_node
));
106 if (new == NULL
) fatalx("lldpctl", "out of memory");
107 TAILQ_INIT(&new->subentries
);
112 * Make a node accessible only to privileged users.
114 * @param node node to change privileges
115 * @return the modified node
117 * The node is modified. It is returned to ease chaining.
120 commands_privileged(struct cmd_node
*node
)
122 if (node
) node
->privileged
= 1;
127 * Make a node accessible only with a lock.
129 * @param node node to use lock to execute
130 * @return the modified node
132 * The node is modified. It is returned to ease chaining.
135 commands_lock(struct cmd_node
*node
)
137 if (node
) node
->lock
= 1;
142 * Hide a node from help or completion.
144 * @param node node to hide
145 * @return the modified node
147 * The node is modified. It is returned to ease chaining.
150 commands_hidden(struct cmd_node
*node
)
152 if (node
) node
->hidden
= 1;
157 * Create a new node acessible by any user.
159 * @param root The node we want to attach this node.
160 * @param token Token to enter this node. Or @c NULL if no token is needed.
161 * @param doc Documentation for this node.
162 * @param validate Function that should return 1 if we can enter the node.
163 * @param execute Function that should return 1 on successful execution of this node.
164 * @param arg Magic argument for precedent functions.
165 * @return the newly created node
168 commands_new(struct cmd_node
*root
, const char *token
, const char *doc
,
169 int (*validate
)(struct cmd_env
*, const void *),
170 int (*execute
)(struct lldpctl_conn_t
*, struct writer
*, struct cmd_env
*,
174 struct cmd_node
*new = calloc(1, sizeof(struct cmd_node
));
175 if (new == NULL
) fatalx("lldpctl", "out of memory");
178 new->validate
= validate
;
179 new->execute
= execute
;
181 TAILQ_INIT(&new->subentries
);
182 TAILQ_INSERT_TAIL(&root
->subentries
, new, next
);
187 * Free a command tree.
189 * @param root The node we want to free.
192 commands_free(struct cmd_node
*root
)
194 struct cmd_node
*subcmd
, *subcmd_next
;
195 for (subcmd
= TAILQ_FIRST(&root
->subentries
); subcmd
!= NULL
;
196 subcmd
= subcmd_next
) {
197 subcmd_next
= TAILQ_NEXT(subcmd
, next
);
198 TAILQ_REMOVE(&root
->subentries
, subcmd
, next
);
199 commands_free(subcmd
);
205 * Return the current argument in the environment. This can be @c NEWLINE or
208 * @param env The environment.
209 * @return current argument.
212 cmdenv_arg(struct cmd_env
*env
)
214 if (env
->argp
< env
->argc
) return env
->argv
[env
->argp
];
215 if (env
->argp
== env
->argc
) return NEWLINE
;
220 * Get a value from the environment.
222 * @param env The environment.
223 * @param key The key for the requested value.
224 * @return @c NULL if not found or the requested value otherwise. If no value is
225 * associated, return the key.
228 cmdenv_get(struct cmd_env
*env
, const char *key
)
230 struct cmd_env_el
*el
;
231 TAILQ_FOREACH (el
, &env
->elements
, next
)
232 if (!strcmp(el
->key
, key
)) return el
->value
? el
->value
: el
->key
;
237 * Put a value in the environment.
239 * @param env The environment.
240 * @param key The key for the value.
241 * @param value The value.
242 * @return 0 on success, -1 otherwise.
245 cmdenv_put(struct cmd_env
*env
, const char *key
, const char *value
)
247 struct cmd_env_el
*el
= malloc(sizeof(struct cmd_env_el
));
250 "unable to allocate memory for new environment variable");
255 TAILQ_INSERT_TAIL(&env
->elements
, el
, next
);
260 * Pop some node from the execution stack.
262 * This allows to resume parsing on a previous state. Useful to call after
263 * parsing optional arguments.
265 * @param env The environment.
266 * @param n How many element we want to pop.
267 * @return 0 on success, -1 otherwise.
270 cmdenv_pop(struct cmd_env
*env
, int n
)
273 if (TAILQ_EMPTY(&env
->stack
)) {
274 log_warnx("lldpctl", "environment stack is empty");
277 struct cmd_env_stack
*first
= TAILQ_FIRST(&env
->stack
);
278 TAILQ_REMOVE(&env
->stack
, first
, next
);
285 * Push some node on the execution stack.
287 * @param env The environment.
288 * @param node The node to push.
289 * @return 0 on success, -1 on error.
292 cmdenv_push(struct cmd_env
*env
, struct cmd_node
*node
)
294 struct cmd_env_stack
*el
= malloc(sizeof(struct cmd_env_stack
));
296 log_warn("lldpctl", "not enough memory to allocate a stack element");
300 TAILQ_INSERT_HEAD(&env
->stack
, el
, next
);
305 * Return the top of the stack, without poping it.
307 * @param env The environment.
308 * @return the top element or @c NULL is the stack is empty.
310 static struct cmd_node
*
311 cmdenv_top(struct cmd_env
*env
)
313 if (TAILQ_EMPTY(&env
->stack
)) return NULL
;
314 return TAILQ_FIRST(&env
->stack
)->el
;
318 * Free execution environment.
320 * @param env The environment.
323 cmdenv_free(struct cmd_env
*env
)
325 while (!TAILQ_EMPTY(&env
->stack
))
328 struct cmd_env_el
*first
;
329 while (!TAILQ_EMPTY(&env
->elements
)) {
330 first
= TAILQ_FIRST(&env
->elements
);
331 TAILQ_REMOVE(&env
->elements
, first
, next
);
336 struct candidate_word
{
337 TAILQ_ENTRY(candidate_word
) next
;
344 * Execute or complete a command from the given node.
346 * @param conn Connection to lldpd.
347 * @param w Writer for output.
348 * @param root Root node we want to start from.
349 * @param argc Number of arguments.
350 * @param argv Array of arguments.
351 * @param word Completed word. Or NULL when no completion is required.
352 * @param all When completing, display possible completions even if only one choice
354 * @param priv Is the current user privileged?
355 * @return 0 on success, -1 otherwise.
358 _commands_execute(struct lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_node
*root
,
359 int argc
, const char **argv
, char **word
, int all
, int priv
)
361 int n
, rc
= 0, completion
= (word
!= NULL
);
362 int help
= 0; /* Are we asking for help? */
363 int complete
= 0; /* Are we asking for possible completions? */
364 int needlock
= 0; /* Do we need a lock? */
365 struct cmd_env env
= { .elements
= TAILQ_HEAD_INITIALIZER(env
.elements
),
366 .stack
= TAILQ_HEAD_INITIALIZER(env
.stack
),
370 static int lockfd
= -1;
371 static char *lockname
= NULL
; /* Name of lockfile */
372 cmdenv_push(&env
, root
);
374 for (n
= 0; n
< argc
; n
++)
375 log_debug("lldpctl", "argument %02d: `%s`", n
, argv
[n
]);
376 if (completion
) *word
= NULL
;
378 #define CAN_EXECUTE(candidate) \
379 ((!candidate->privileged || priv || complete) && \
380 (!candidate->validate || candidate->validate(&env, candidate->arg) == 1))
382 /* When completion is in progress, we use the same algorithm than for
383 * execution until we reach the cursor position. */
384 struct cmd_node
*current
= NULL
;
385 while ((current
= cmdenv_top(&env
))) {
387 help
= !!cmdenv_get(&env
, "help"); /* Are we asking for help? */
388 complete
= !!cmdenv_get(&env
, "complete"); /* Or completion? */
391 struct cmd_node
*candidate
, *best
= NULL
;
392 const char *token
= (env
.argp
< env
.argc
) ? env
.argv
[env
.argp
] :
393 (env
.argp
== env
.argc
&& !help
&& !complete
) ? NEWLINE
:
395 if (token
== NULL
|| (completion
&& env
.argp
== env
.argc
- 1)) goto end
;
397 log_debug("lldpctl", "process argument %02d: `%s`", env
.argp
,
399 TAILQ_FOREACH (candidate
, ¤t
->subentries
, next
) {
400 if (candidate
->token
&&
401 !strncmp(candidate
->token
, token
, strlen(token
)) &&
402 CAN_EXECUTE(candidate
)) {
403 if (candidate
->token
&&
404 !strcmp(candidate
->token
, token
)) {
407 needlock
= needlock
|| candidate
->lock
;
415 "ambiguous token: %s (%s or %s)",
416 token
, candidate
->token
,
424 /* Take first that validate */
425 TAILQ_FOREACH (candidate
, ¤t
->subentries
, next
) {
426 if (!candidate
->token
&& CAN_EXECUTE(candidate
)) {
428 needlock
= needlock
|| candidate
->lock
;
433 if (!best
&& env
.argp
== env
.argc
) goto end
;
437 "unknown command from argument %d: `%s`",
438 env
.argp
+ 1, token
);
443 /* Push and execute */
444 cmdenv_push(&env
, best
);
448 if (lockname
== NULL
&&
449 asprintf(&lockname
, "%s.lock", ctlname
) ==
452 "not enough memory to build lock filename");
456 log_debug("lldpctl", "open %s for locking",
458 if ((lockfd
= open(lockname
, O_RDWR
)) == -1) {
460 "cannot open lock %s", lockname
);
465 if (lockf(lockfd
, F_LOCK
, 0) == -1) {
466 log_warn("lldpctl", "cannot get lock on %s",
474 rc
= best
->execute(conn
, w
, &env
, best
->arg
) != 1 ? -1 : rc
;
475 if (needlock
&& lockf(lockfd
, F_ULOCK
, 0) == -1) {
476 log_warn("lldpctl", "cannot unlock %s", lockname
);
480 if (rc
== -1) goto end
;
485 if (!completion
&& !help
&& !complete
) {
486 if (rc
== 0 && env
.argp
!= env
.argc
+ 1) {
487 log_warnx("lldpctl", "incomplete command");
490 } else if (rc
== 0 && (env
.argp
== env
.argc
- 1 || help
|| complete
)) {
491 /* We need to complete. Let's build the list of candidate words. */
492 struct cmd_node
*candidate
= NULL
;
493 size_t maxl
= 10; /* Max length of a word */
494 TAILQ_HEAD(, candidate_word
) words
; /* List of subnodes */
496 current
= cmdenv_top(&env
);
497 if (!TAILQ_EMPTY(¤t
->subentries
)) {
498 TAILQ_FOREACH (candidate
, ¤t
->subentries
, next
) {
499 if ((!candidate
->token
|| help
|| complete
||
500 !strncmp(env
.argv
[env
.argc
- 1],
502 strlen(env
.argv
[env
.argc
- 1]))) &&
503 CAN_EXECUTE(candidate
)) {
504 struct candidate_word
*cword
=
505 malloc(sizeof(struct candidate_word
));
507 cword
->word
= candidate
->token
;
508 cword
->doc
= candidate
->doc
;
509 cword
->hidden
= candidate
->hidden
;
510 if (cword
->word
&& strlen(cword
->word
) > maxl
)
511 maxl
= strlen(cword
->word
);
512 TAILQ_INSERT_TAIL(&words
, cword
, next
);
516 if (!TAILQ_EMPTY(&words
)) {
517 /* Search if there is a common prefix, then return it. */
518 char prefix
[maxl
+ 2]; /* Extra space may be added at the end */
519 struct candidate_word
*cword
, *cword_next
;
520 memset(prefix
, 0, maxl
+ 2);
521 for (size_t n
= 0; n
< maxl
; n
++) {
522 int c
= 1; /* Set to 0 to exit outer loop */
523 TAILQ_FOREACH (cword
, &words
, next
) {
525 if (cword
->hidden
) continue;
526 if (cword
->word
== NULL
) break;
527 if (!strcmp(cword
->word
, NEWLINE
)) break;
528 if (strlen(cword
->word
) == n
) break;
529 if (prefix
[n
] == '\0')
530 prefix
[n
] = cword
->word
[n
];
531 else if (prefix
[n
] != cword
->word
[n
])
540 /* If the prefix is complete, add a space, otherwise,
541 * just return it as is. */
542 if (!all
&& !help
&& !complete
&& strcmp(prefix
, NEWLINE
) &&
543 strlen(prefix
) > 0 &&
544 strlen(env
.argv
[env
.argc
- 1]) < strlen(prefix
)) {
545 TAILQ_FOREACH (cword
, &words
, next
) {
547 !strcmp(prefix
, cword
->word
)) {
548 prefix
[strlen(prefix
)] = ' ';
552 *word
= strdup(prefix
);
554 /* No common prefix, print possible completions */
556 fprintf(stderr
, "\n-- \033[1;34m%s\033[0m\n",
557 current
->doc
? current
->doc
: "Help");
558 TAILQ_FOREACH (cword
, &words
, next
) {
559 if (cword
->hidden
) continue;
563 snprintf(fmt
, sizeof(fmt
),
564 "%s%%%ds%s %%s\n", "\033[1m",
565 (int)maxl
, "\033[0m");
567 cword
->word
? cword
->word
: "WORD",
568 cword
->doc
? cword
->doc
: "...");
571 !strcmp(cword
->word
, NEWLINE
))
573 fprintf(stdout
, "%s %s\n",
574 cword
->word
? cword
->word
: "WORD",
575 cword
->doc
? cword
->doc
: "...");
579 for (cword
= TAILQ_FIRST(&words
); cword
!= NULL
;
580 cword
= cword_next
) {
581 cword_next
= TAILQ_NEXT(cword
, next
);
582 TAILQ_REMOVE(&words
, cword
, next
);
592 * Complete the given command.
595 commands_complete(struct cmd_node
*root
, int argc
, const char **argv
, int all
,
599 if (_commands_execute(NULL
, NULL
, root
, argc
, argv
, &word
, all
, privileged
) ==
606 * Execute the given commands.
609 commands_execute(struct lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_node
*root
,
610 int argc
, const char **argv
, int privileged
)
612 return _commands_execute(conn
, w
, root
, argc
, argv
, NULL
, 0, privileged
);
616 * Check if the environment does not contain the given key.
618 * @param env The environment.
619 * @param key The key to search for.
620 * @return 1 if the environment does not contain the key. 0 otherwise.
623 cmd_check_no_env(struct cmd_env
*env
, const void *key
)
625 return cmdenv_get(env
, (const char *)key
) == NULL
;
629 * Check if the environment does contain the given key.
631 * @param env The environment.
632 * @param key The key to search for. Can be a comma separated list.
633 * @return 1 if the environment does contain the key. 0 otherwise.
636 cmd_check_env(struct cmd_env
*env
, const void *key
)
638 struct cmd_env_el
*el
;
639 const char *list
= key
;
641 TAILQ_FOREACH (el
, &env
->elements
, next
) {
642 if (contains(list
, el
->key
)) count
++;
644 while ((list
= strchr(list
, ','))) {
652 * Store the given key in the environment.
654 * @param conn The connection.
655 * @param w The writer (not used).
656 * @param env The environment.
657 * @param key The key to store.
658 * @return 1 if the key was stored
661 cmd_store_env(struct lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
,
664 return cmdenv_put(env
, key
, NULL
) != -1;
668 * Store the given key in the environment and pop one element from the stack.
670 * @param conn The connection.
671 * @param w The writer (not used).
672 * @param env The environment.
673 * @param key The key to store.
674 * @return 1 if the key was stored
677 cmd_store_env_and_pop(struct lldpctl_conn_t
*conn
, struct writer
*w
,
678 struct cmd_env
*env
, const void *key
)
680 return (cmd_store_env(conn
, w
, env
, key
) != -1 && cmdenv_pop(env
, 1) != -1);
684 * Store the given key with a value being the current keyword in the environment
685 * and pop X elements from the stack.
687 * @param conn The connection.
688 * @param w The writer (not used).
689 * @param env The environment.
690 * @param key The key to store.
691 * @return 1 if the key was stored
694 cmd_store_env_value_and_pop(struct lldpctl_conn_t
*conn
, struct writer
*w
,
695 struct cmd_env
*env
, const void *key
)
698 cmdenv_put(env
, key
, cmdenv_arg(env
)) != -1 && cmdenv_pop(env
, 1) != -1);
701 cmd_store_env_value_and_pop2(struct lldpctl_conn_t
*conn
, struct writer
*w
,
702 struct cmd_env
*env
, const void *key
)
705 cmdenv_put(env
, key
, cmdenv_arg(env
)) != -1 && cmdenv_pop(env
, 2) != -1);
708 cmd_store_env_value(struct lldpctl_conn_t
*conn
, struct writer
*w
, struct cmd_env
*env
,
711 return (cmdenv_put(env
, key
, cmdenv_arg(env
)) != -1);
714 cmd_store_env_value_and_pop3(struct lldpctl_conn_t
*conn
, struct writer
*w
,
715 struct cmd_env
*env
, const void *key
)
718 cmdenv_put(env
, key
, cmdenv_arg(env
)) != -1 && cmdenv_pop(env
, 3) != -1);
721 cmd_store_something_env_value_and_pop2(const char *what
, struct cmd_env
*env
,
724 return (cmdenv_put(env
, what
, value
) != -1 && cmdenv_pop(env
, 2) != -1);
727 cmd_store_something_env_value(const char *what
, struct cmd_env
*env
, const void *value
)
729 return (cmdenv_put(env
, what
, value
) != -1);
733 * Provide an iterator on all interfaces contained in "ports".
735 * @warning This function is not reentrant. It uses static variables to keep
736 * track of ports that have already been provided. Moreover, to release all
737 * resources, the iterator should be used until its end.
739 * @param conn The connection.
740 * @param env The environment.
741 * @return The next interface in the set of ports (or in all ports if no `ports`
742 * variable is present in the environment)
745 cmd_iterate_on_interfaces(struct lldpctl_conn_t
*conn
, struct cmd_env
*env
)
747 static lldpctl_atom_iter_t
*iter
= NULL
;
748 static lldpctl_atom_t
*iface_list
= NULL
;
749 static lldpctl_atom_t
*iface
= NULL
;
750 const char *interfaces
= cmdenv_get(env
, "ports");
754 iface_list
= lldpctl_get_interfaces(conn
);
757 "not able to get the list of interfaces. %s",
758 lldpctl_last_strerror(conn
));
761 iter
= lldpctl_atom_iter(iface_list
);
762 if (!iter
) return NULL
;
764 iter
= lldpctl_atom_iter_next(iface_list
, iter
);
766 lldpctl_atom_dec_ref(iface
);
770 lldpctl_atom_dec_ref(iface_list
);
775 iface
= lldpctl_atom_iter_value(iface_list
, iter
);
776 } while (interfaces
&&
777 !contains(interfaces
,
778 lldpctl_atom_get_str(iface
, lldpctl_k_interface_name
)));
784 * Provide an iterator on all ports contained in "ports", as well as the
787 * @warning This function is not reentrant. It uses static variables to keep
788 * track of ports that have already been provided. Moreover, to release all
789 * resources, the iterator should be used until its end.
791 * @param conn The connection.
792 * @param env The environment.
793 * @param name Name of the interface (for logging purpose)
794 * @return The next interface in the set of ports (or in all ports if no `ports`
795 * variable is present in the environment), including the default port
796 * if no `ports` variable is present in the environment.
799 cmd_iterate_on_ports(struct lldpctl_conn_t
*conn
, struct cmd_env
*env
,
802 static int put_default
= 0;
803 static lldpctl_atom_t
*last_port
= NULL
;
804 const char *interfaces
= cmdenv_get(env
, "ports");
807 lldpctl_atom_dec_ref(last_port
);
811 lldpctl_atom_t
*iface
= cmd_iterate_on_interfaces(conn
, env
);
813 *name
= lldpctl_atom_get_str(iface
, lldpctl_k_interface_name
);
814 last_port
= lldpctl_get_port(iface
);
820 last_port
= lldpctl_get_default_port(conn
);
831 * Restrict the command to some ports.
834 cmd_restrict_ports(struct cmd_node
*root
)
836 /* Restrict to some ports. */
837 commands_new(commands_new(root
, "ports", "Restrict configuration to some ports",
838 cmd_check_no_env
, NULL
, "ports"),
840 "Restrict configuration to the specified ports (comma-separated list)",
841 NULL
, cmd_store_env_value_and_pop2
, "ports");
845 * Restrict the command to specific protocol
848 cmd_restrict_protocol(struct cmd_node
*root
)
850 /* Restrict to some ports. */
851 commands_new(commands_new(root
, "protocol", "Restrict to specific protocol",
852 cmd_check_no_env
, NULL
, "protocol"),
853 NULL
, "Restrict display to the specified protocol", NULL
,
854 cmd_store_env_value_and_pop2
, "protocol");