Convert opt_F_t to support directories as well as files, store in vector
Also allow parsing colon-separated lists into opt_F. This will be useful
for -F as well as for parsing some environment variables.
This removes bits related to default directories to look into. This will
eventually be moved to os_get_config_dirs, currently it's simply disabled.
The code in libltrace.c is currently incompatible with opt_F being a vector,
so it's disabled as well. Revamp of the whole configury shebang underway.
diff --git a/options.c b/options.c
index 93dea31..f24acac 100644
--- a/options.c
+++ b/options.c
@@ -26,6 +26,8 @@
#include "config.h"
#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -41,13 +43,6 @@
#include "glob.h"
#include "demangle.h"
-#ifndef SYSCONFDIR
-#define SYSCONFDIR "/etc"
-#endif
-
-#define SYSTEM_CONFIG_FILE SYSCONFDIR "/ltrace.conf"
-#define USER_CONFIG_FILE "~/.ltrace.conf"
-
struct options_t options = {
.align = DEFAULT_ALIGN, /* alignment column for results */
.user = NULL, /* username to run command as */
@@ -73,8 +68,8 @@
/* List of pids given to option -p: */
struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */
-/* List of filenames give to option -F: */
-struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */
+/* Vector of struct opt_F_t. */
+struct vect opt_F;
static void
err_usage(void) {
@@ -443,9 +438,83 @@
return (int)l;
}
+int
+parse_colon_separated_list(const char *paths, struct vect *vec)
+{
+ /* PATHS contains a colon-separated list of directories and
+ * files to load. It's modeled after shell PATH variable,
+ * which doesn't allow escapes. PYTHONPATH in CPython behaves
+ * the same way. So let's follow suit, it makes things easier
+ * to us. */
+
+ char *clone = strdup(paths);
+ if (clone == NULL) {
+ fprintf(stderr, "Couldn't parse argument %s: %s.\n",
+ paths, strerror(errno));
+ return -1;
+ }
+
+ /* It's undesirable to use strtok, because we want the string
+ * "a::b" to have three elements. */
+ char *tok = clone - 1;
+ char *end = clone + strlen(clone);
+ while (tok < end) {
+ ++tok;
+ size_t len = strcspn(tok, ":");
+ tok[len] = 0;
+
+ struct opt_F_t arg = {
+ .pathname = tok,
+ .own_pathname = tok == clone,
+ };
+ if (VECT_PUSHBACK(vec, &arg) < 0)
+ /* Presumably this is not a deal-breaker. */
+ fprintf(stderr, "Couldn't store component of %s: %s.\n",
+ paths, strerror(errno));
+
+ tok += len;
+ }
+
+ return 0;
+}
+
+void
+opt_F_destroy(struct opt_F_t *entry)
+{
+ if (entry == NULL)
+ return;
+ if (entry->own_pathname)
+ free(entry->pathname);
+}
+
+enum opt_F_kind
+opt_F_get_kind(struct opt_F_t *entry)
+{
+ if (entry->kind == OPT_F_UNKNOWN) {
+ struct stat st;
+ if (lstat(entry->pathname, &st) < 0) {
+ fprintf(stderr, "Couldn't stat %s: %s\n",
+ entry->pathname, strerror(errno));
+ entry->kind = OPT_F_BROKEN;
+ } else if (S_ISDIR(st.st_mode)) {
+ entry->kind = OPT_F_DIR;
+ } else if (S_ISREG(st.st_mode)) {
+ entry->kind = OPT_F_FILE;
+ } else {
+ fprintf(stderr, "%s is neither a regular file, "
+ "nor a directory.\n", entry->pathname);
+ entry->kind = OPT_F_BROKEN;
+ }
+ }
+ assert(entry->kind != OPT_F_UNKNOWN);
+ return entry->kind;
+}
+
char **
process_options(int argc, char **argv)
{
+ VECT_INIT(&opt_F, struct opt_F_t);
+
progname = argv[0];
options.output = stderr;
options.no_signals = 0;
@@ -537,23 +606,8 @@
options.follow = 1;
break;
case 'F':
- {
- struct opt_F_t *tmp = malloc(sizeof(*tmp));
- if (tmp == NULL) {
- fail:
- fprintf(stderr, "%s\n",
- strerror(errno));
- free(tmp);
- exit(1);
- }
- tmp->filename = strdup(optarg);
- if (tmp->filename == NULL)
- goto fail;
- tmp->own_filename = 1;
- tmp->next = opt_F;
- opt_F = tmp;
- break;
- }
+ parse_colon_separated_list(optarg, &opt_F);
+ break;
case 'h':
usage();
exit(0);
@@ -643,31 +697,6 @@
argc -= optind;
argv += optind;
- if (!opt_F) {
- opt_F = malloc(sizeof(struct opt_F_t));
- opt_F->next = malloc(sizeof(struct opt_F_t));
- opt_F->next->next = NULL;
- opt_F->filename = USER_CONFIG_FILE;
- opt_F->own_filename = 0;
- opt_F->next->filename = SYSTEM_CONFIG_FILE;
- opt_F->next->own_filename = 0;
- }
- /* Reverse the config file list since it was built by
- * prepending, and it would make more sense to process the
- * files in the order they were given. Probably it would make
- * more sense to keep a tail pointer instead? */
- {
- struct opt_F_t *egg = NULL;
- struct opt_F_t *chicken;
- while (opt_F) {
- chicken = opt_F->next;
- opt_F->next = egg;
- egg = opt_F;
- opt_F = chicken;
- }
- opt_F = egg;
- }
-
/* If neither -e, nor -l, nor -L are used, set default -e.
* Use @MAIN for now, as that's what ltrace used to have in
* the past. XXX Maybe we should make this "*" instead. */