--- LICENSE | 1 + Makefile | 1 + README | 1 + TODO | 1 - pathchk.1 | 35 +++++++++++++ pathchk.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 pathchk.1 create mode 100644 pathchk.c diff --git a/LICENSE b/LICENSE index cb5a797..2a26979 100644 --- a/LICENSE +++ b/LICENSE _AT_@ -59,3 +59,4 @@ Authors/contributors include: © 2015 Quentin Rameau <quinq_AT_quinq.eu.org> © 2015 Dionysis Grigoropoulos <info_AT_erethon.com> © 2015 Wolfgang Corcoran-Mathe <first.lord.of.teal_AT_gmail.com> +© 2016 Mattias Andrée <maandree_AT_kth.se> diff --git a/Makefile b/Makefile index 1c09cac..b8cf51a 100644 --- a/Makefile +++ b/Makefile _AT_@ -120,6 +120,7 @@ BIN =\ nl\ nohup\ od\ + pathchk\ paste\ printenv\ printf\ diff --git a/README b/README index c72ed76..b3005dd 100644 --- a/README +++ b/README _AT_@ -58,6 +58,7 @@ The following tools are implemented: #*|o nl . =*|o nohup . =*|o od . +#* o pathchk . #*|o paste . =*|x printenv . #*|o printf . diff --git a/TODO b/TODO index 80dd3ec..a5559d1 100644 --- a/TODO +++ b/TODO _AT_@ -10,7 +10,6 @@ diff ed manpage install patch -pathchk stty If you are looking for some work to do on sbase, another option is to diff --git a/pathchk.1 b/pathchk.1 new file mode 100644 index 0000000..7f36ffc --- /dev/null +++ b/pathchk.1 _AT_@ -0,0 +1,35 @@ +.Dd 2016-02-03 +.Dt PATHCHK 1 +.Os sbase +.Sh NAME +.Nm pathchk +.Nd validate filename validity or portability +.Sh SYNOPSIS +.Nm +.Op Fl p +.Op Fl P +.Ar file Ar ... +.Sh DESCRIPTION +.Nm +checks that filenames are valid for the system, +and optional on other POSIX systems. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl p +Check for most POSIX systems. +.It Fl P +Check for empty pathnames and leading hythens. +.El +.Sh EXIT STATUS +.Bl -tag -width Ds +.It 0 +A filename was not valid or portable. +.It > 0 +An error occurred. +.El +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2013 +specification. diff --git a/pathchk.c b/pathchk.c new file mode 100644 index 0000000..7212863 --- /dev/null +++ b/pathchk.c _AT_@ -0,0 +1,166 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <errno.h> +#include <sys/stat.h> + +#include "util.h" +#include "arg.h" + +#define PORTABLE_CHARACTER_SET "0123456789._-qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" +/* If your system supports more other characters, but not all non-NUL characters, define SYSTEM_CHARACTER_SET. */ + +static int most = 0; +static int extra = 0; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-pP] filename...\n", argv0); + exit(1); +} + +static int +pathchk(char *filename) +{ + char *invalid, *invalid_end, *p, *q; + const char *character_set; + size_t len, maxlen; + struct stat _attr; +#ifdef _PC_NAME_MAX + size_t sysmaxlen; +#endif + + /* Empty? */ + if (extra && !*filename) { + fprintf(stderr, "%s: empty filename\n", argv0); + return 1; + } + + /* Leading hyphen? */ + if (extra && ((*filename == '-') || strstr(filename, "/-"))) { + fprintf(stderr, "%s: %s: leading '-' in component of filename\n", argv0, filename); + return 1; + } + + /* Nonportable character? */ +#ifdef SYSTEM_CHARACTER_SET + character_set = "/"SYSTEM_CHARACTER_SET; +#else + character_set = 0; +#endif + if (most) + character_set = "/"PORTABLE_CHARACTER_SET; + if (character_set && *(invalid = filename + strspn(filename, character_set))) { + for (invalid_end = invalid + 1; *invalid_end & 0x80; invalid_end++); + fprintf(stderr, "%s: %s: ", argv0, filename); + *invalid_end = 0; + fprintf(stderr, "nonportable character '%s'\n", invalid); + return 1; + } + + /* Symlink error? Non-searchable directory? */ + if (lstat(filename, &_attr) && errno != ENOENT) { + /* lstat rather than stat, so that if filename is a bad symlink, but + * all parents are OK, no error will be detected. */ + fprintf(stderr, "%s: %s: %s\n", argv0, filename, strerror(errno)); + return 1; + } + + /* Too long pathname? */ + maxlen = most ? _POSIX_PATH_MAX : SIZE_MAX; +#ifdef PATH_MAX + if (maxlen > PATH_MAX) + maxlen = PATH_MAX; +#endif +#ifdef _PC_PATH_MAX + p = strrchr(filename, '/'); + if (p) + *p = 0; + errno = 0; + len = (size_t)pathconf(p ? *p ? p : "/" : ".", _PC_PATH_MAX); + if (errno) { + perror(argv0); + exit(1); + } + if (p) + *p = '/'; + if (maxlen > len) + maxlen = len; +#endif + if (strlen(filename) >= maxlen) { + fprintf(stderr, "%s: %s: is longer than %zu bytes\n", + argv0, filename, maxlen); + return 1; + } + + /* Too long component? */ + maxlen = most ? _POSIX_NAME_MAX : SIZE_MAX; +#ifdef NAME_MAX + if (maxlen > NAME_MAX) + maxlen = NAME_MAX; +#endif +#ifdef _PC_NAME_MAX + errno = 0; + len = (size_t)pathconf(*filename == '/' ? "/" : ".", _PC_NAME_MAX); + if (errno) { + perror(argv0); + exit(1); + } + if (maxlen > len) + maxlen = len; + sysmaxlen = maxlen; +#endif + for (p = filename; p; p = q) { + q = strchr(p, '/'); + len = q ? (size_t)(q++ - p) : strlen(p); + if (len > maxlen) { + fprintf(stderr, "%s: %s: includes component longer than %zu bytes\n", + argv0, filename, maxlen); + return 1; + } +#ifdef _PC_NAME_MAX + if (q) { + *q = 0; + errno = 0; + len = (size_t)pathconf(filename, _PC_NAME_MAX); + if (errno) { + perror(argv0); + exit(1); + } + maxlen = sysmaxlen < len ? sysmaxlen : len; + *q = '/'; + } +#endif + } + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + + ARGBEGIN { + case 'p': + most = 1; + break; + case 'P': + extra = 1; + break; + default: + usage(); + } ARGEND; + + if (!argc) + usage(); + + for (; argc--; argv++) + ret |= pathchk(*argv); + + return 0; +} -- 2.7.0Received on Wed Feb 03 2016 - 11:12:01 CET
This archive was generated by hypermail 2.3.0 : Wed Feb 03 2016 - 11:24:11 CET