sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit b445614f7021c76902ad2ed41e4d3d0087b04e98
parent cfc37be4862574ac68f424a42763cf5681243812
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed,  3 Feb 2016 20:12:26 +0100

Add pathchk(1)

New command, including man page.
UTF-8 compatible and should be POSIX-compliant.

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
MLICENSE | 1+
MMakefile | 1+
MREADME | 1+
MTODO | 1-
Apathchk.1 | 35+++++++++++++++++++++++++++++++++++
Apathchk.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE @@ -59,3 +59,4 @@ Authors/contributors include: © 2015 Quentin Rameau <quinq@quinq.eu.org> © 2015 Dionysis Grigoropoulos <info@erethon.com> © 2015 Wolfgang Corcoran-Mathe <first.lord.of.teal@gmail.com> +© 2016 Mattias Andrée <maandree@kth.se> diff --git a/Makefile b/Makefile @@ -120,6 +120,7 @@ BIN =\ nl\ nohup\ od\ + pathchk\ paste\ printenv\ printf\ diff --git a/README b/README @@ -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 @@ -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 @@ -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 @@ -0,0 +1,123 @@ +/* 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. */ + +#ifndef PATH_MAX +# define PATH_MAX SIZE_MAX +#endif +#ifndef NAME_MAX +# define NAME_MAX SIZE_MAX +#endif + +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; + + /* 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 : PATH_MAX; + 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 : NAME_MAX; + 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; + } + } + + 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 ret; +}