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