1c78c4633STim J. Robbins /*- 2c78c4633STim J. Robbins * Copyright (c) 2002 Tim J. Robbins. 3c78c4633STim J. Robbins * All rights reserved. 4c78c4633STim J. Robbins * 5c78c4633STim J. Robbins * Redistribution and use in source and binary forms, with or without 6c78c4633STim J. Robbins * modification, are permitted provided that the following conditions 7c78c4633STim J. Robbins * are met: 8c78c4633STim J. Robbins * 1. Redistributions of source code must retain the above copyright 9c78c4633STim J. Robbins * notice, this list of conditions and the following disclaimer. 10c78c4633STim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 11c78c4633STim J. Robbins * notice, this list of conditions and the following disclaimer in the 12c78c4633STim J. Robbins * documentation and/or other materials provided with the distribution. 13c78c4633STim J. Robbins * 14c78c4633STim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c78c4633STim J. Robbins * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c78c4633STim J. Robbins * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c78c4633STim J. Robbins * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c78c4633STim J. Robbins * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c78c4633STim J. Robbins * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c78c4633STim J. Robbins * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c78c4633STim J. Robbins * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c78c4633STim J. Robbins * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c78c4633STim J. Robbins * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c78c4633STim J. Robbins * SUCH DAMAGE. 25c78c4633STim J. Robbins */ 26c78c4633STim J. Robbins 27c78c4633STim J. Robbins /* 28c78c4633STim J. Robbins * pathchk -- check pathnames 29c78c4633STim J. Robbins * 30c78c4633STim J. Robbins * Check whether files could be created with the names specified on the 31c78c4633STim J. Robbins * command line. If -p is specified, check whether the pathname is portable 32c78c4633STim J. Robbins * to all POSIX systems. 33c78c4633STim J. Robbins */ 34c78c4633STim J. Robbins 35c78c4633STim J. Robbins #include <sys/cdefs.h> 36c78c4633STim J. Robbins __FBSDID("$FreeBSD$"); 37c78c4633STim J. Robbins 38c78c4633STim J. Robbins #include <sys/types.h> 39c78c4633STim J. Robbins #include <sys/stat.h> 40c78c4633STim J. Robbins 41c78c4633STim J. Robbins #include <err.h> 42c78c4633STim J. Robbins #include <errno.h> 43c78c4633STim J. Robbins #include <limits.h> 44c78c4633STim J. Robbins #include <stdio.h> 45c78c4633STim J. Robbins #include <stdlib.h> 46c78c4633STim J. Robbins #include <string.h> 47c78c4633STim J. Robbins #include <unistd.h> 48c78c4633STim J. Robbins 49c78c4633STim J. Robbins static int check(const char *); 50c78c4633STim J. Robbins static int portable(const char *); 51c78c4633STim J. Robbins static void usage(void); 52c78c4633STim J. Robbins 53c78c4633STim J. Robbins static int pflag; /* Perform portability checks */ 54c78c4633STim J. Robbins 55c78c4633STim J. Robbins int 56c78c4633STim J. Robbins main(int argc, char *argv[]) 57c78c4633STim J. Robbins { 58c78c4633STim J. Robbins int ch, rval; 59c78c4633STim J. Robbins const char *arg; 60c78c4633STim J. Robbins 61c78c4633STim J. Robbins while ((ch = getopt(argc, argv, "p")) > 0) { 62c78c4633STim J. Robbins switch (ch) { 63c78c4633STim J. Robbins case 'p': 64c78c4633STim J. Robbins pflag = 1; 65c78c4633STim J. Robbins break; 66c78c4633STim J. Robbins default: 67c78c4633STim J. Robbins usage(); 68c78c4633STim J. Robbins /*NOTREACHED*/ 69c78c4633STim J. Robbins } 70c78c4633STim J. Robbins } 71c78c4633STim J. Robbins argc -= optind; 72c78c4633STim J. Robbins argv += optind; 73c78c4633STim J. Robbins 74c78c4633STim J. Robbins if (argc == 0) 75c78c4633STim J. Robbins usage(); 76c78c4633STim J. Robbins 77c78c4633STim J. Robbins rval = 0; 78c78c4633STim J. Robbins while ((arg = *argv++) != NULL) 79c78c4633STim J. Robbins rval |= check(arg); 80c78c4633STim J. Robbins 81c78c4633STim J. Robbins exit(rval); 82c78c4633STim J. Robbins } 83c78c4633STim J. Robbins 84c78c4633STim J. Robbins static void 85c78c4633STim J. Robbins usage(void) 86c78c4633STim J. Robbins { 87c78c4633STim J. Robbins 88c78c4633STim J. Robbins fprintf(stderr, "usage: pathchk [-p] pathname...\n"); 89c78c4633STim J. Robbins exit(1); 90c78c4633STim J. Robbins } 91c78c4633STim J. Robbins 92c78c4633STim J. Robbins static int 93c78c4633STim J. Robbins check(const char *path) 94c78c4633STim J. Robbins { 95c78c4633STim J. Robbins struct stat sb; 96c78c4633STim J. Robbins long complen, namemax, pathmax, svnamemax; 97c78c4633STim J. Robbins int badch, last; 98c78c4633STim J. Robbins char *end, *p, *pathd; 99c78c4633STim J. Robbins 100c78c4633STim J. Robbins if ((pathd = strdup(path)) == NULL) 101c78c4633STim J. Robbins err(1, "strdup"); 102c78c4633STim J. Robbins 103c78c4633STim J. Robbins p = pathd; 104c78c4633STim J. Robbins 105c78c4633STim J. Robbins if (!pflag) { 106c78c4633STim J. Robbins errno = 0; 107c78c4633STim J. Robbins namemax = pathconf(*p == '/' ? "/" : ".", _PC_NAME_MAX); 108c78c4633STim J. Robbins if (namemax == -1 && errno != 0) 109c78c4633STim J. Robbins namemax = NAME_MAX; 110c78c4633STim J. Robbins } else 111c78c4633STim J. Robbins namemax = _POSIX_NAME_MAX; 112c78c4633STim J. Robbins 113c78c4633STim J. Robbins for (;;) { 114c78c4633STim J. Robbins p += strspn(p, "/"); 115c78c4633STim J. Robbins complen = (long)strcspn(p, "/"); 116c78c4633STim J. Robbins end = p + complen; 117c78c4633STim J. Robbins last = *end == '\0'; 118c78c4633STim J. Robbins *end = '\0'; 119c78c4633STim J. Robbins 120c78c4633STim J. Robbins if (namemax != -1 && complen > namemax) { 121c78c4633STim J. Robbins warnx("%s: %s: component too long (limit %ld)", path, 122c78c4633STim J. Robbins p, namemax); 123c78c4633STim J. Robbins goto bad; 124c78c4633STim J. Robbins } 125c78c4633STim J. Robbins 126c78c4633STim J. Robbins if (!pflag && stat(pathd, &sb) == -1 && errno != ENOENT) { 127c78c4633STim J. Robbins warn("%s", pathd); 128c78c4633STim J. Robbins goto bad; 129c78c4633STim J. Robbins } 130c78c4633STim J. Robbins 131c78c4633STim J. Robbins if (pflag && (badch = portable(p)) >= 0) { 132c78c4633STim J. Robbins warnx("%s: %s: component contains non-portable " 133c78c4633STim J. Robbins "character `%c'", path, p, badch); 134c78c4633STim J. Robbins goto bad; 135c78c4633STim J. Robbins } 136c78c4633STim J. Robbins 137c78c4633STim J. Robbins if (last) 138c78c4633STim J. Robbins break; 139c78c4633STim J. Robbins 140c78c4633STim J. Robbins if (!pflag) { 141c78c4633STim J. Robbins errno = 0; 142c78c4633STim J. Robbins svnamemax = namemax; 143c78c4633STim J. Robbins namemax = pathconf(pathd, _PC_NAME_MAX); 144c78c4633STim J. Robbins if (namemax == -1 && errno != 0) 145c78c4633STim J. Robbins namemax = svnamemax; 146c78c4633STim J. Robbins } 147c78c4633STim J. Robbins 148c78c4633STim J. Robbins *end = '/'; 149c78c4633STim J. Robbins p = end + 1; 150c78c4633STim J. Robbins } 151c78c4633STim J. Robbins 152c78c4633STim J. Robbins if (!pflag) { 153c78c4633STim J. Robbins errno = 0; 154c78c4633STim J. Robbins pathmax = pathconf(path, _PC_PATH_MAX); 155c78c4633STim J. Robbins if (pathmax == -1 && errno != 0) 156c78c4633STim J. Robbins pathmax = PATH_MAX; 157c78c4633STim J. Robbins } else 158c78c4633STim J. Robbins pathmax = _POSIX_PATH_MAX; 159c78c4633STim J. Robbins if (pathmax != -1 && strlen(path) > (size_t)pathmax) { 160c78c4633STim J. Robbins warnx("%s: path too long (limit %ld)", path, pathmax); 161c78c4633STim J. Robbins goto bad; 162c78c4633STim J. Robbins } 163c78c4633STim J. Robbins 164c78c4633STim J. Robbins free(pathd); 165c78c4633STim J. Robbins return (0); 166c78c4633STim J. Robbins 167c78c4633STim J. Robbins bad: free(pathd); 168c78c4633STim J. Robbins return (1); 169c78c4633STim J. Robbins } 170c78c4633STim J. Robbins 171c78c4633STim J. Robbins /* 172c78c4633STim J. Robbins * Check whether a path component contains only portable characters. Return 173c78c4633STim J. Robbins * the first non-portable character found. 174c78c4633STim J. Robbins */ 175c78c4633STim J. Robbins static int 176c78c4633STim J. Robbins portable(const char *path) 177c78c4633STim J. Robbins { 178c78c4633STim J. Robbins static const char charset[] = 179c78c4633STim J. Robbins "abcdefghijklmnopqrstuvwxyz" 180c78c4633STim J. Robbins "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 181c78c4633STim J. Robbins "0123456789._-"; 182c78c4633STim J. Robbins long s; 183c78c4633STim J. Robbins 184c78c4633STim J. Robbins if (*path == '-') 185c78c4633STim J. Robbins return (*path); 186c78c4633STim J. Robbins 187c78c4633STim J. Robbins s = strspn(path, charset); 188c78c4633STim J. Robbins if (path[s] != '\0') 189c78c4633STim J. Robbins return (path[s]); 190c78c4633STim J. Robbins 191c78c4633STim J. Robbins return (-1); 192c78c4633STim J. Robbins } 193