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