/** * Append a new input file/directory to the list of inputs. * * @param arg Directory or file name to add. * @param inputs List of inputs * @param acceptdir 1 if we accept a directory, 0 otherwise */ static void input_append(const char *arg, struct inputs *inputs, int acceptdir, int warn) { struct stat statbuf; if (stat(arg, &statbuf) == -1) { if (warn) { log_warn("lldpctl", "cannot find configuration file/directory %s", arg); } else { log_debug("lldpctl", "cannot find configuration file/directory %s", arg); } return; } if (!S_ISDIR(statbuf.st_mode)) { struct input *input = malloc(sizeof(struct input)); if (!input) { log_warn("lldpctl", "not enough memory to process %s", arg); return; } log_debug("lldpctl", "input: %s", arg); input->name = strdup(arg); TAILQ_INSERT_TAIL(inputs, input, next); return; } if (!acceptdir) { log_debug("lldpctl", "skip directory %s", arg); return; } struct dirent **namelist = NULL; int n = scandir(arg, &namelist, filter, alphasort); if (n < 0) { log_warnx("lldpctl", "unable to read directory %s", arg); return; } for (int i=0; i < n; i++) { char *fullname; if (asprintf(&fullname, "%s/%s", arg, namelist[i]->d_name) != -1) { input_append(fullname, inputs, 0, 1); free(fullname); } free(namelist[i]); } free(namelist); }
int main(int argc, char *argv[]) { int ch, debug = 1, rc = EXIT_FAILURE; const char *fmt = "plain"; lldpctl_conn_t *conn = NULL; const char *options = is_lldpctl(argv[0])?"hdvf:":"hdsvf:c:u:"; int gotinputs = 0; struct inputs inputs; TAILQ_INIT(&inputs); ctlname = lldpctl_get_default_transport(); signal(SIGHUP, SIG_IGN); /* Initialize logging */ while ((ch = getopt(argc, argv, options)) != -1) { switch (ch) { case 'd': debug++; break; case 's': debug--; break; } } log_init(debug, __progname); /* Get and parse command line options */ optind = 1; while ((ch = getopt(argc, argv, options)) != -1) { switch (ch) { case 'd': break; case 's': break; case 'h': usage(); break; case 'u': ctlname = optarg; break; case 'v': fprintf(stdout, "%s\n", PACKAGE_VERSION); exit(0); break; case 'f': fmt = optarg; break; case 'c': gotinputs = 1; input_append(optarg, &inputs, 1); break; default: usage(); } } /* Disable SIGPIPE */ signal(SIGPIPE, SIG_IGN); /* Register commands */ root = register_commands(); /* Make a connection */ log_debug("lldpctl", "connect to lldpd"); conn = lldpctl_new_name(ctlname, NULL, NULL, NULL); if (conn == NULL) goto end; /* Process file inputs */ while (gotinputs && !TAILQ_EMPTY(&inputs)) { /* coverity[use_after_free] TAILQ_REMOVE does the right thing */ struct input *first = TAILQ_FIRST(&inputs); log_debug("lldpctl", "process: %s", first->name); FILE *file = fopen(first->name, "r"); if (file) { size_t len; char *line; while ((line = fgetln(file, &len))) { line = strndup(line, len); if (line[len - 1] == '\n') { line[len - 1] = '\0'; parse_and_exec(conn, fmt, line); } free(line); } fclose(file); } else { log_warn("lldpctl", "unable to open %s", first->name); } TAILQ_REMOVE(&inputs, first, next); free(first->name); free(first); } /* Process additional arguments. First if we are lldpctl (interfaces) */ if (is_lldpctl(NULL)) { char *line = NULL; for (int i = optind; i < argc; i++) { char *prev = line; if (asprintf(&line, "%s%s%s", prev?prev:"show neigh ports ", argv[i], (i == argc - 1)?" details":",") == -1) { log_warnx("lldpctl", "not enough memory to build list of interfaces"); free(prev); goto end; } free(prev); } if (line == NULL && (line = strdup("show neigh details")) == NULL) { log_warnx("lldpctl", "not enough memory to build command line"); goto end; } log_debug("lldpctl", "execute %s", line); if (parse_and_exec(conn, fmt, line) != -1) rc = EXIT_SUCCESS; free(line); goto end; } /* Then, if we are regular lldpcli (command line) */ if (optind < argc) { const char **cargv; int cargc; cargv = &((const char **)argv)[optind]; cargc = argc - optind; if (cmd_exec(conn, fmt, cargc, cargv) != -1) rc = EXIT_SUCCESS; goto end; } if (gotinputs) { rc = EXIT_SUCCESS; goto end; } /* Interactive session */ #ifdef HAVE_LIBREADLINE rl_bind_key('?', cmd_help); rl_bind_key('\t', cmd_complete); #endif const char *line; do { if ((line = readline(prompt()))) { int n = parse_and_exec(conn, fmt, line); (void)n; #ifdef HAVE_READLINE_HISTORY if (n != 0) add_history(line); #endif } } while (!must_exit && line != NULL); rc = EXIT_SUCCESS; end: while (!TAILQ_EMPTY(&inputs)) { /* coverity[use_after_free] TAILQ_REMOVE does the right thing */ struct input *first = TAILQ_FIRST(&inputs); TAILQ_REMOVE(&inputs, first, next); free(first->name); free(first); } if (conn) lldpctl_release(conn); if (root) commands_free(root); return rc; }