[Toybox] [PATCH 1/1] add pathchk
Ilya Kuzmich
ilya.kuzmich at gmail.com
Fri May 26 09:21:28 PDT 2017
Signed-off-by: Ilya Kuzmich <ilya.kuzmich at gmail.com>
---
tests/pathchk.test | 85 ++++++++++++++++++++++++++++++++++++++++++++++
toys/posix/pathchk.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+)
create mode 100644 tests/pathchk.test
create mode 100644 toys/posix/pathchk.c
diff --git a/tests/pathchk.test b/tests/pathchk.test
new file mode 100644
index 0000000..4632399
--- /dev/null
+++ b/tests/pathchk.test
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "zero arguments" "pathchk 2>/dev/null || echo ok" "ok\n" "" ""
+
+mkdir dir_a-rx
+chmod a-rx dir_a-rx
+testing "dir_a-rx/a" "pathchk dir_a-rx/a 2>/dev/null || echo ok" "ok\n" "" ""
+rmdir dir_a-rx
+
+touch file
+testing "file/a" "pathchk file/a 2>/dev/null || echo ok" "ok\n" "" ""
+rm file
+
+mkcomponent() {
+ head -c "$1" /dev/zero | tr '\0' 'a'
+}
+
+mkpath() {
+ to_fill=$1
+ component_len=$2
+
+ while [ "$to_fill" -gt 0 ]; do
+ if [ $component_len -ge $to_fill ]; then
+ component_len=$((to_fill))
+ fi
+ mkcomponent $component_len
+ to_fill=$((to_fill-component_len))
+ if [ "$to_fill" -gt 0 ]; then
+ printf "/"
+ to_fill=$((to_fill-1))
+ fi
+ done
+}
+
+NAME_MAX="$(getconf NAME_MAX .)"
+testing "NAME_MAX" "pathchk '$(mkcomponent $NAME_MAX )' \
+ && echo ok" "ok\n" "" ""
+testing "NAME_MAX+1" "pathchk '$(mkcomponent $((NAME_MAX+1)) )' \
+ 2>/dev/null || echo ok" "ok\n" "" ""
+testing "NAME_MAX/1" "pathchk '$(mkcomponent $NAME_MAX)/a' \
+ 2>/dev/null && echo ok" "ok\n" "" ""
+testing "NAME_MAX+1/1" "pathchk '$(mkcomponent $((NAME_MAX+1)))/a' \
+ 2>/dev/null || echo ok" "ok\n" "" ""
+
+PATH_MAX="$(getconf PATH_MAX .)"
+testing "PATH_MAX-1" "pathchk '$(mkpath $((PATH_MAX-1)) $NAME_MAX)' \
+ && echo ok" "ok\n" "" ""
+testing "PATH_MAX" "pathchk '$(mkpath $PATH_MAX $NAME_MAX)' \
+ 2>/dev/null || echo ok" "ok\n" "" ""
+
+POSIX_NAME_MAX="14"
+testing "-p _POSIX_NAME_MAX" "pathchk -p \
+ '$(mkcomponent $POSIX_NAME_MAX)' && echo ok" "ok\n" "" ""
+testing "-p _POSIX_NAME_MAX+1" "pathchk -p\
+ '$(mkcomponent $((POSIX_NAME_MAX+1)))' 2>/dev/null || echo ok" \
+ "ok\n" "" ""
+testing "-p _POSIX_NAME_MAX/1" "pathchk -p \
+ '$(mkcomponent $POSIX_NAME_MAX)/a' && echo ok" "ok\n" "" ""
+testing "-p _POSIX_NAME_MAX+1/1" "pathchk -p\
+ '$(mkcomponent $((POSIX_NAME_MAX+1)))/1' 2>/dev/null || echo ok" \
+ "ok\n" "" ""
+
+POSIX_PATH_MAX="256"
+testing "-p _POSIX_PATH_MAX-1" "pathchk -p \
+ '$(mkpath $((POSIX_PATH_MAX-1)) $POSIX_NAME_MAX)' && echo ok" \
+ "ok\n" "" ""
+testing "-p _POSIX_PATH_MAX" "pathchk -p \
+ '$(mkpath $POSIX_PATH_MAX $POSIX_NAME_MAX)' 2>/dev/null || \
+ echo ok" "ok\n" "" ""
+
+# portable filename character set
+testing "-p a=b" "pathchk -p a=b 2>/dev/null || echo ok" "ok\n" "" ""
+testing "-p 'a$'" "pathchk -p 'a$' 2>/dev/null || echo ok" "ok\n" "" ""
+testing "-p '+a'" "pathchk -p '+a' 2>/dev/null || echo ok" "ok\n" "" ""
+
+# empty path and leading '-'
+testing "-P ''" "pathchk -P '' 2>/dev/null || echo ok" "ok\n" "" ""
+testing "-P a/-b" "pathchk -P 'a/-b' 2>/dev/null || echo ok" "ok\n" "" ""
+
+# one error message per path
+testing "-P '' '-'" "pathchk -P '' '-' 2>&1 | wc -l" "2\n" "" ""
diff --git a/toys/posix/pathchk.c b/toys/posix/pathchk.c
new file mode 100644
index 0000000..25d76a7
--- /dev/null
+++ b/toys/posix/pathchk.c
@@ -0,0 +1,95 @@
+/* pathchk.c - check pathnames
+ *
+ * Copyright 2017 Ilya Kuzmich <ilya.kuzmich at gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pathchk.html
+
+USE_PATHCHK(NEWTOY(pathchk, "<1pP", TOYFLAG_USR|TOYFLAG_BIN))
+
+config PATHCHK
+ bool "pathchk"
+ default y
+ help
+ usage: pathchk [-p] [-P] [NAME...]
+
+ Check that pathnames are portable and valid on the underlying file system
+
+ -p check instead for POSIX portability
+ -P check for empty names and components with leading "-"
+*/
+
+#define FOR_pathchk
+#include "toys.h"
+
+static long get_pathconf(char *path, int name, long fallback)
+{
+ long ret;
+
+ errno = 0;
+ ret = pathconf(path, name);
+ if (ret == -1 && errno)
+ ret = fallback;
+
+ return ret;
+}
+
+static void do_check_path(char *path)
+{
+ long pathmax, namemax;
+ size_t namelen;
+ char *p = path;
+
+ if (toys.optflags & FLAG_p) {
+ namemax = _POSIX_NAME_MAX;
+ pathmax = _POSIX_PATH_MAX;
+
+ p += strspn(p, "/"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789._-");
+
+ if (*p) {
+ error_msg("%s: nonportable character %c in path", path, *p);
+ return;
+ }
+ } else {
+ struct stat st;
+
+ namemax = get_pathconf(*path == '/' ? "/" : ".", _PC_NAME_MAX, NAME_MAX);
+ pathmax = get_pathconf(path, _PC_PATH_MAX, PATH_MAX);
+
+ errno = 0;
+ if (stat(path, &st) && errno != ENOENT)
+ perror_msg("%s", path);
+ }
+
+ for (namelen = 0, p = path; *p; p += namelen) {
+ p += strspn(p, "/");
+ namelen = strcspn(p, "/");
+
+ if (namemax != -1 && namelen > namemax) {
+ error_msg("%s: component too long (limit %ld)", path, namemax);
+ return;
+ }
+
+ if (toys.optflags & FLAG_P && *p == '-') {
+ error_msg("%s: leading '-' in a path component", path);
+ return;
+ }
+ }
+
+ if (pathmax != -1 && strlen(path) >= (size_t)pathmax) {
+ error_msg("%s: path too long (limit %ld)", path, pathmax);
+ return;
+ }
+
+ if (toys.optflags & FLAG_P && !*path) {
+ error_msg("path is empty");
+ return;
+ }
+}
+
+void pathchk_main(void)
+{
+ while (*toys.optargs) do_check_path(*toys.optargs++);
+}
--
2.7.4
More information about the Toybox
mailing list