pathchk.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       pathchk.c (2341B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <sys/stat.h>
            3 
            4 #include <errno.h>
            5 #include <limits.h>
            6 #include <stdint.h>
            7 #include <stdio.h>
            8 #include <stdlib.h>
            9 #include <string.h>
           10 
           11 #include "util.h"
           12 
           13 #define PORTABLE_CHARACTER_SET "0123456789._-qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
           14 /* If your system supports more other characters, but not all non-NUL characters, define SYSTEM_CHARACTER_SET. */
           15 
           16 static int most = 0;
           17 static int extra = 0;
           18 
           19 static int
           20 pathchk(char *filename)
           21 {
           22         char *invalid, *invalid_end, *p, *q;
           23         const char *character_set;
           24         size_t len, maxlen;
           25         struct stat st;
           26 
           27         /* Empty? */
           28         if (extra && !*filename)
           29                 eprintf("empty filename\n");
           30 
           31         /* Leading hyphen? */
           32         if (extra && ((*filename == '-') || strstr(filename, "/-")))
           33                 eprintf("%s: leading '-' in component of filename\n", filename);
           34 
           35         /* Nonportable character? */
           36 #ifdef SYSTEM_CHARACTER_SET
           37         character_set = "/"SYSTEM_CHARACTER_SET;
           38 #else
           39         character_set = 0;
           40 #endif
           41         if (most)
           42                 character_set = "/"PORTABLE_CHARACTER_SET;
           43         if (character_set && *(invalid = filename + strspn(filename, character_set))) {
           44                 for (invalid_end = invalid + 1; *invalid_end & 0x80; invalid_end++);
           45                 p = estrdup(filename);
           46                 *invalid_end = 0;
           47                 eprintf("%s: nonportable character '%s'\n", p, invalid);
           48         }
           49 
           50         /* Symlink error? Non-searchable directory? */
           51         if (lstat(filename, &st) && errno != ENOENT) {
           52                 /* lstat rather than stat, so that if filename is a bad symlink, but
           53                  * all parents are OK, no error will be detected. */
           54                 eprintf("%s:", filename);
           55         }
           56 
           57         /* Too long pathname? */
           58         maxlen = most ? _POSIX_PATH_MAX : PATH_MAX;
           59         if (strlen(filename) >= maxlen)
           60                 eprintf("%s: is longer than %zu bytes\n", filename, maxlen);
           61 
           62         /* Too long component? */
           63         maxlen = most ? _POSIX_NAME_MAX : NAME_MAX;
           64         for (p = filename; p; p = q) {
           65                 q = strchr(p, '/');
           66                 len = q ? (size_t)(q++ - p) : strlen(p);
           67                 if (len > maxlen)
           68                         eprintf("%s: includes component longer than %zu bytes\n",
           69                                  filename, maxlen);
           70         }
           71 
           72         return 0;
           73 }
           74 
           75 static void
           76 usage(void)
           77 {
           78         eprintf("usage: %s [-pP] filename...\n", argv0);
           79 }
           80 
           81 int
           82 main(int argc, char *argv[])
           83 {
           84         int ret = 0;
           85 
           86         ARGBEGIN {
           87         case 'p':
           88                 most = 1;
           89                 break;
           90         case 'P':
           91                 extra = 1;
           92                 break;
           93         default:
           94                 usage();
           95         } ARGEND
           96 
           97         if (!argc)
           98                 usage();
           99 
          100         for (; argc--; argv++)
          101                 ret |= pathchk(*argv);
          102 
          103         return ret;
          104 }