diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 9a1e090..8e907e4 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -75,6 +75,8 @@ usage() fprintf(stderr, " -I, --include PATTERN only match against interfaces matching PATTERN\n"); fprintf(stderr, " -X, --exclude PATTERN never match against interfaces matching PATTERN\n"); fprintf(stderr, " -P, --pretty-print pretty print the interfaces instead of just listing\n"); + fprintf(stderr, " -S, --state-file FILE use FILE for state\n"); + fprintf(stderr, " -s, --state show configured state\n"); exit(1); } @@ -114,10 +116,32 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts) } } +void +list_state(struct lif_dict *state, struct match_options *opts) +{ + struct lif_node *iter; + + LIF_DICT_FOREACH(iter, state) + { + struct lif_dict_entry *entry = iter->data; + + if (opts->exclude_pattern != NULL && + !fnmatch(opts->exclude_pattern, entry->key, 0)) + continue; + + if (opts->include_pattern != NULL && + fnmatch(opts->include_pattern, entry->key, 0)) + continue; + + printf("%s=%s\n", entry->key, (const char *) entry->data); + } +} + int main(int argc, char *argv[]) { - struct lif_dict collection; + struct lif_dict state = {}; + struct lif_dict collection = {}; struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -127,15 +151,18 @@ main(int argc, char *argv[]) {"include", required_argument, 0, 'I'}, {"exclude", required_argument, 0, 'X'}, {"pretty-print", no_argument, 0, 'P'}, + {"state-file", required_argument, 0, 'S'}, + {"state", no_argument, 0, 's'}, {NULL, 0, 0, 0} }; struct match_options match_opts = {}; - bool listing = false; + bool listing = false, listing_stat = false; char *interfaces_file = INTERFACES_FILE; + char *state_file = STATE_FILE; for (;;) { - int c = getopt_long(argc, argv, "hVi:LaI:X:P", long_options, NULL); + int c = getopt_long(argc, argv, "hVi:LaI:X:PS:s", long_options, NULL); if (c == -1) break; @@ -164,20 +191,41 @@ main(int argc, char *argv[]) case 'P': match_opts.pretty_print = true; break; + case 'S': + state_file = optarg; + break; + case 's': + listing_stat = true; + break; } } + if (!lif_state_read_path(&state, state_file)) + { + fprintf(stderr, "ifquery: could not parse %s\n", state_file); + return EXIT_FAILURE; + } + if (!lif_interface_file_parse(&collection, interfaces_file)) { fprintf(stderr, "ifquery: could not parse %s\n", interfaces_file); return EXIT_FAILURE; } + /* --list --state is not allowed */ + if (listing && listing_stat) + usage(); + if (listing) { list_interfaces(&collection, &match_opts); return EXIT_SUCCESS; } + else if (listing_stat) + { + list_state(&state, &match_opts); + return EXIT_SUCCESS; + } if (optind >= argc) usage(); @@ -185,14 +233,14 @@ main(int argc, char *argv[]) int idx = optind; for (; idx < argc; idx++) { - struct lif_dict_entry *entry = lif_dict_find(&collection, argv[idx]); - if (entry == NULL) + struct lif_interface *iface = lif_state_lookup(&state, &collection, argv[idx]); + if (iface == NULL) { fprintf(stderr, "ifquery: unknown interface %s\n", argv[idx]); return EXIT_FAILURE; } - print_interface(entry->data); + print_interface(iface); } return EXIT_SUCCESS; diff --git a/libifupdown/libifupdown.h b/libifupdown/libifupdown.h index 8d2f95b..2f9c24b 100644 --- a/libifupdown/libifupdown.h +++ b/libifupdown/libifupdown.h @@ -22,5 +22,6 @@ #include "libifupdown/interface-file.h" #include "libifupdown/fgetline.h" #include "libifupdown/version.h" +#include "libifupdown/state.h" #endif diff --git a/libifupdown/state.c b/libifupdown/state.c index fbb50a5..e9856dd 100644 --- a/libifupdown/state.c +++ b/libifupdown/state.c @@ -1,5 +1,5 @@ /* - * libifupdown/state.h + * libifupdown/state.c * Purpose: state management * * Copyright (c) 2020 Ariadne Conill @@ -15,6 +15,44 @@ #include #include "libifupdown/state.h" +#include "libifupdown/fgetline.h" + +bool +lif_state_read(struct lif_dict *state, FILE *fd) +{ + char linebuf[4096]; + while (lif_fgetline(linebuf, sizeof linebuf, fd)) + { + char *ifname = linebuf; + char *equals_p = strchr(linebuf, '='); + + if (equals_p == NULL) + { + lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname }); + continue; + } + + *equals_p++ = '\0'; + lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p }); + } + + return true; +} + +bool +lif_state_read_path(struct lif_dict *state, const char *path) +{ + FILE *fd = fopen(path, "r"); + bool ret; + + if (fd == NULL) + return false; + + ret = lif_state_read(state, fd); + fclose(fd); + + return ret; +} void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface) @@ -47,6 +85,20 @@ lif_state_write(const struct lif_dict *state, FILE *f) } } +bool +lif_state_write_path(const struct lif_dict *state, const char *path) +{ + FILE *fd = fopen(path, "w"); + + if (fd == NULL) + return false; + + lif_state_write(state, fd); + fclose(fd); + + return true; +} + struct lif_interface * lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const char *ifname) { diff --git a/libifupdown/state.h b/libifupdown/state.h index c97ad3c..36cb59e 100644 --- a/libifupdown/state.h +++ b/libifupdown/state.h @@ -19,9 +19,12 @@ #include #include "libifupdown/interface.h" +extern bool lif_state_read(struct lif_dict *state, FILE *f); +extern bool lif_state_read_path(struct lif_dict *state, const char *path); extern void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface); extern void lif_state_delete(struct lif_dict *state, const char *ifname); extern void lif_state_write(const struct lif_dict *state, FILE *f); +extern bool lif_state_write_path(const struct lif_dict *state, const char *path); extern struct lif_interface *lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const char *ifname); #endif