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 */ 54da219525SJilles Tjoelker static int Pflag; /* Check for empty paths, leading '-' */ 55c78c4633STim J. Robbins 56c78c4633STim J. Robbins int 57c78c4633STim J. Robbins main(int argc, char *argv[]) 58c78c4633STim J. Robbins { 59c78c4633STim J. Robbins int ch, rval; 60c78c4633STim J. Robbins const char *arg; 61c78c4633STim J. Robbins 62da219525SJilles Tjoelker while ((ch = getopt(argc, argv, "pP")) > 0) { 63c78c4633STim J. Robbins switch (ch) { 64c78c4633STim J. Robbins case 'p': 65c78c4633STim J. Robbins pflag = 1; 66c78c4633STim J. Robbins break; 67da219525SJilles Tjoelker case 'P': 68da219525SJilles Tjoelker Pflag = 1; 69da219525SJilles Tjoelker break; 70c78c4633STim J. Robbins default: 71c78c4633STim J. Robbins usage(); 72c78c4633STim J. Robbins /*NOTREACHED*/ 73c78c4633STim J. Robbins } 74c78c4633STim J. Robbins } 75c78c4633STim J. Robbins argc -= optind; 76c78c4633STim J. Robbins argv += optind; 77c78c4633STim J. Robbins 78c78c4633STim J. Robbins if (argc == 0) 79c78c4633STim J. Robbins usage(); 80c78c4633STim J. Robbins 81c78c4633STim J. Robbins rval = 0; 82c78c4633STim J. Robbins while ((arg = *argv++) != NULL) 83c78c4633STim J. Robbins rval |= check(arg); 84c78c4633STim J. Robbins 85c78c4633STim J. Robbins exit(rval); 86c78c4633STim J. Robbins } 87c78c4633STim J. Robbins 88c78c4633STim J. Robbins static void 89c78c4633STim J. Robbins usage(void) 90c78c4633STim J. Robbins { 91c78c4633STim J. Robbins 92c78c4633STim J. Robbins fprintf(stderr, "usage: pathchk [-p] pathname ...\n"); 93c78c4633STim J. Robbins exit(1); 94c78c4633STim J. Robbins } 95c78c4633STim J. Robbins 96c78c4633STim J. Robbins static int 97c78c4633STim J. Robbins check(const char *path) 98c78c4633STim J. Robbins { 99c78c4633STim J. Robbins struct stat sb; 100c78c4633STim J. Robbins long complen, namemax, pathmax, svnamemax; 101*ea624717SJilles Tjoelker int last; 102c78c4633STim J. Robbins char *end, *p, *pathd; 103c78c4633STim J. Robbins 104c78c4633STim J. Robbins if ((pathd = strdup(path)) == NULL) 105c78c4633STim J. Robbins err(1, "strdup"); 106c78c4633STim J. Robbins 107c78c4633STim J. Robbins p = pathd; 108c78c4633STim J. Robbins 109da219525SJilles Tjoelker if (Pflag && *p == '\0') { 110da219525SJilles Tjoelker warnx("%s: empty pathname", path); 111da219525SJilles Tjoelker goto bad; 112da219525SJilles Tjoelker } 113da219525SJilles Tjoelker if ((Pflag || pflag) && (*p == '-' || strstr(p, "/-") != NULL)) { 114da219525SJilles Tjoelker warnx("%s: contains a component starting with '-'", path); 115da219525SJilles Tjoelker goto bad; 116da219525SJilles Tjoelker } 117da219525SJilles Tjoelker 118c78c4633STim J. Robbins if (!pflag) { 119c78c4633STim J. Robbins errno = 0; 120c78c4633STim J. Robbins namemax = pathconf(*p == '/' ? "/" : ".", _PC_NAME_MAX); 121c78c4633STim J. Robbins if (namemax == -1 && errno != 0) 122c78c4633STim J. Robbins namemax = NAME_MAX; 123c78c4633STim J. Robbins } else 124c78c4633STim J. Robbins namemax = _POSIX_NAME_MAX; 125c78c4633STim J. Robbins 126c78c4633STim J. Robbins for (;;) { 127c78c4633STim J. Robbins p += strspn(p, "/"); 128c78c4633STim J. Robbins complen = (long)strcspn(p, "/"); 129c78c4633STim J. Robbins end = p + complen; 130c78c4633STim J. Robbins last = *end == '\0'; 131c78c4633STim J. Robbins *end = '\0'; 132c78c4633STim J. Robbins 133c78c4633STim J. Robbins if (namemax != -1 && complen > namemax) { 134c78c4633STim J. Robbins warnx("%s: %s: component too long (limit %ld)", path, 135c78c4633STim J. Robbins p, namemax); 136c78c4633STim J. Robbins goto bad; 137c78c4633STim J. Robbins } 138c78c4633STim J. Robbins 139c78c4633STim J. Robbins if (!pflag && stat(pathd, &sb) == -1 && errno != ENOENT) { 1402a84afe1STim J. Robbins warn("%s: %.*s", path, (int)(strlen(pathd) - 1412a84afe1STim J. Robbins complen - 1), pathd); 142c78c4633STim J. Robbins goto bad; 143c78c4633STim J. Robbins } 144c78c4633STim J. Robbins 145*ea624717SJilles Tjoelker if (pflag && !portable(p)) { 146c78c4633STim J. Robbins warnx("%s: %s: component contains non-portable " 147*ea624717SJilles Tjoelker "character", path, p); 148c78c4633STim J. Robbins goto bad; 149c78c4633STim J. Robbins } 150c78c4633STim J. Robbins 151c78c4633STim J. Robbins if (last) 152c78c4633STim J. Robbins break; 153c78c4633STim J. Robbins 154c78c4633STim J. Robbins if (!pflag) { 155c78c4633STim J. Robbins errno = 0; 156c78c4633STim J. Robbins svnamemax = namemax; 157c78c4633STim J. Robbins namemax = pathconf(pathd, _PC_NAME_MAX); 158c78c4633STim J. Robbins if (namemax == -1 && errno != 0) 159c78c4633STim J. Robbins namemax = svnamemax; 160c78c4633STim J. Robbins } 161c78c4633STim J. Robbins 162c78c4633STim J. Robbins *end = '/'; 163c78c4633STim J. Robbins p = end + 1; 164c78c4633STim J. Robbins } 165c78c4633STim J. Robbins 166c78c4633STim J. Robbins if (!pflag) { 167c78c4633STim J. Robbins errno = 0; 168c78c4633STim J. Robbins pathmax = pathconf(path, _PC_PATH_MAX); 169c78c4633STim J. Robbins if (pathmax == -1 && errno != 0) 170c78c4633STim J. Robbins pathmax = PATH_MAX; 171c78c4633STim J. Robbins } else 172c78c4633STim J. Robbins pathmax = _POSIX_PATH_MAX; 173ea87e79dSTim J. Robbins if (pathmax != -1 && strlen(path) >= (size_t)pathmax) { 174ea87e79dSTim J. Robbins warnx("%s: path too long (limit %ld)", path, pathmax - 1); 175c78c4633STim J. Robbins goto bad; 176c78c4633STim J. Robbins } 177c78c4633STim J. Robbins 178c78c4633STim J. Robbins free(pathd); 179c78c4633STim J. Robbins return (0); 180c78c4633STim J. Robbins 181c78c4633STim J. Robbins bad: free(pathd); 182c78c4633STim J. Robbins return (1); 183c78c4633STim J. Robbins } 184c78c4633STim J. Robbins 185c78c4633STim J. Robbins /* 186*ea624717SJilles Tjoelker * Check whether a path component contains only portable characters. 187c78c4633STim J. Robbins */ 188c78c4633STim J. Robbins static int 189c78c4633STim J. Robbins portable(const char *path) 190c78c4633STim J. Robbins { 191c78c4633STim J. Robbins static const char charset[] = 192c78c4633STim J. Robbins "abcdefghijklmnopqrstuvwxyz" 193c78c4633STim J. Robbins "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 194c78c4633STim J. Robbins "0123456789._-"; 195c78c4633STim J. Robbins long s; 196c78c4633STim J. Robbins 197c78c4633STim J. Robbins s = strspn(path, charset); 198c78c4633STim J. Robbins if (path[s] != '\0') 199*ea624717SJilles Tjoelker return (0); 200c78c4633STim J. Robbins 201*ea624717SJilles Tjoelker return (1); 202c78c4633STim J. Robbins } 203