summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--parse.c35
-rw-r--r--util.c30
-rw-r--r--util.h19
4 files changed, 62 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 7d53e76..9e44fdc 100644
--- a/Makefile
+++ b/Makefile
@@ -73,6 +73,10 @@ else
DISTCHECK_FLAGS := TEST_FLAGS="--verbose"
endif
+ifeq ($(OS),NetBSD)
+LOCAL_LDLIBS += -lutil
+endif
+
ifneq ($(filter asan,$(MAKECMDGOALS)),)
LOCAL_CFLAGS += $(ASAN_CFLAGS)
SANITIZE := y
diff --git a/parse.c b/parse.c
index fd4585c..a315243 100644
--- a/parse.c
+++ b/parse.c
@@ -1163,20 +1163,12 @@ static struct expr *parse_f(struct parser_state *state, int arg1, int arg2) {
* Parse -flags FLAGS.
*/
static struct expr *parse_flags(struct parser_state *state, int arg1, int arg2) {
-#if __APPLE__ || __FreeBSD__
struct expr *expr = parse_unary_test(state, eval_flags);
if (!expr) {
return NULL;
}
- // strtofflags() takes a non-const char *
- char *copy = strdup(expr->sdata);
- if (!copy) {
- parse_perror(state, "strdup()");
- goto err;
- }
-
- char *flags = copy;
+ const char *flags = expr->sdata;
switch (flags[0]) {
case '-':
expr->mode_cmp = MODE_ALL;
@@ -1191,26 +1183,17 @@ static struct expr *parse_flags(struct parser_state *state, int arg1, int arg2)
break;
}
- unsigned long set, clear;
- if (strtofflags(&flags, &set, &clear) != 0) {
- parse_error(state, "${blu}%s${rs}: Invalid flags ${bld}%s${rs}.\n", expr->argv[0], flags);
- goto err;
+ if (xstrtofflags(&flags, &expr->set_flags, &expr->clear_flags) != 0) {
+ if (errno == ENOTSUP) {
+ parse_error(state, "${blu}%s${rs} is missing platform support.\n", expr->argv[0]);
+ } else {
+ parse_error(state, "${blu}%s${rs}: Invalid flags ${bld}%s${rs}.\n", expr->argv[0], flags);
+ }
+ free_expr(expr);
+ return NULL;
}
- expr->set_flags = set;
- expr->clear_flags = clear;
-
- free(copy);
return expr;
-
-err:
- free(copy);
- free_expr(expr);
- return NULL;
-#else // !(__APPLE__ || __FreeBSD)
- parse_error(state, "${blu}%s${rs} is missing platform support.\n", state->argv[0]);
- return NULL;
-#endif
}
/**
diff --git a/util.c b/util.c
index f271dce..63ea756 100644
--- a/util.c
+++ b/util.c
@@ -39,6 +39,10 @@
# include <sys/mkdev.h>
#endif
+#if BFS_HAS_UTIL
+# include <util.h>
+#endif
+
char *xreadlinkat(int fd, const char *path, size_t size) {
ssize_t len;
char *name = NULL;
@@ -232,6 +236,32 @@ int xfaccessat(int fd, const char *path, int amode) {
return ret;
}
+int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear) {
+#if BSD
+ char *str_arg = (char *)*str;
+ unsigned long set_arg = 0;
+ unsigned long clear_arg = 0;
+
+#if __NetBSD__
+ int ret = string_to_flags(&str_arg, &set_arg, &clear_arg);
+#else
+ int ret = strtofflags(&str_arg, &set_arg, &clear_arg);
+#endif
+
+ *str = str_arg;
+ *set = set_arg;
+ *clear = clear_arg;
+
+ if (ret != 0) {
+ errno = EINVAL;
+ }
+ return ret;
+#else // !BSD
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
bool is_nonexistence_error(int error) {
return error == ENOENT || errno == ENOTDIR;
}
diff --git a/util.h b/util.h
index ed47aa2..ca90494 100644
--- a/util.h
+++ b/util.h
@@ -74,6 +74,10 @@
# define BFS_HAS_SYS_XATTR BFS_HAS_INCLUDE(<sys/xattr.h>, __linux__)
#endif
+#ifndef BFS_HAS_UTIL
+# define BFS_HAS_UTIL BFS_HAS_INCLUDE(<util.h>, __NetBSD__)
+#endif
+
#if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
# define FNM_CASEFOLD FNM_IGNORECASE
#endif
@@ -180,6 +184,21 @@ const char *xbasename(const char *path);
int xfaccessat(int fd, const char *path, int amode);
/**
+ * Portability wrapper for strtofflags().
+ *
+ * @param str
+ * The string to parse. The pointee will be advanced to the first
+ * invalid position on error.
+ * @param set
+ * The flags that are set in the string.
+ * @param clear
+ * The flags that are cleared in the string.
+ * @return
+ * 0 on success, -1 on failure.
+ */
+int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear);
+
+/**
* Return whether an error code is due to a path not existing.
*/
bool is_nonexistence_error(int error);