pathchk.c revision 98093
197095Stjr/*- 297095Stjr * Copyright (c) 2002 Tim J. Robbins. 397095Stjr * All rights reserved. 497095Stjr * 597095Stjr * Redistribution and use in source and binary forms, with or without 697095Stjr * modification, are permitted provided that the following conditions 797095Stjr * are met: 897095Stjr * 1. Redistributions of source code must retain the above copyright 997095Stjr * notice, this list of conditions and the following disclaimer. 1097095Stjr * 2. Redistributions in binary form must reproduce the above copyright 1197095Stjr * notice, this list of conditions and the following disclaimer in the 1297095Stjr * documentation and/or other materials provided with the distribution. 1397095Stjr * 1497095Stjr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1597095Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1697095Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1797095Stjr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1897095Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1997095Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2097095Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2197095Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2297095Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2397095Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2497095Stjr * SUCH DAMAGE. 2597095Stjr */ 2697095Stjr 2797095Stjr/* 2897095Stjr * pathchk -- check pathnames 2997095Stjr * 3097095Stjr * Check whether files could be created with the names specified on the 3197095Stjr * command line. If -p is specified, check whether the pathname is portable 3297095Stjr * to all POSIX systems. 3397095Stjr */ 3497095Stjr 3597095Stjr#include <sys/cdefs.h> 3697095Stjr__FBSDID("$FreeBSD: head/usr.bin/pathchk/pathchk.c 98093 2002-06-10 10:03:46Z tjr $"); 3797095Stjr 3897095Stjr#include <sys/types.h> 3997095Stjr#include <sys/stat.h> 4097095Stjr 4197095Stjr#include <err.h> 4297095Stjr#include <errno.h> 4397095Stjr#include <limits.h> 4497095Stjr#include <stdio.h> 4597095Stjr#include <stdlib.h> 4697095Stjr#include <string.h> 4797095Stjr#include <unistd.h> 4897095Stjr 4997095Stjrstatic int check(const char *); 5097095Stjrstatic int portable(const char *); 5197095Stjrstatic void usage(void); 5297095Stjr 5397095Stjrstatic int pflag; /* Perform portability checks */ 5497095Stjr 5597095Stjrint 5697095Stjrmain(int argc, char *argv[]) 5797095Stjr{ 5897095Stjr int ch, rval; 5997095Stjr const char *arg; 6097095Stjr 6197095Stjr while ((ch = getopt(argc, argv, "p")) > 0) { 6297095Stjr switch (ch) { 6397095Stjr case 'p': 6497095Stjr pflag = 1; 6597095Stjr break; 6697095Stjr default: 6797095Stjr usage(); 6897095Stjr /*NOTREACHED*/ 6997095Stjr } 7097095Stjr } 7197095Stjr argc -= optind; 7297095Stjr argv += optind; 7397095Stjr 7497095Stjr if (argc == 0) 7597095Stjr usage(); 7697095Stjr 7797095Stjr rval = 0; 7897095Stjr while ((arg = *argv++) != NULL) 7997095Stjr rval |= check(arg); 8097095Stjr 8197095Stjr exit(rval); 8297095Stjr} 8397095Stjr 8497095Stjrstatic void 8597095Stjrusage(void) 8697095Stjr{ 8797095Stjr 8897095Stjr fprintf(stderr, "usage: pathchk [-p] pathname...\n"); 8997095Stjr exit(1); 9097095Stjr} 9197095Stjr 9297095Stjrstatic int 9397095Stjrcheck(const char *path) 9497095Stjr{ 9597095Stjr struct stat sb; 9697095Stjr long complen, namemax, pathmax, svnamemax; 9797095Stjr int badch, last; 9897095Stjr char *end, *p, *pathd; 9997095Stjr 10097095Stjr if ((pathd = strdup(path)) == NULL) 10197095Stjr err(1, "strdup"); 10297095Stjr 10397095Stjr p = pathd; 10497095Stjr 10597095Stjr if (!pflag) { 10697095Stjr errno = 0; 10797095Stjr namemax = pathconf(*p == '/' ? "/" : ".", _PC_NAME_MAX); 10897095Stjr if (namemax == -1 && errno != 0) 10997095Stjr namemax = NAME_MAX; 11097095Stjr } else 11197095Stjr namemax = _POSIX_NAME_MAX; 11297095Stjr 11397095Stjr for (;;) { 11497095Stjr p += strspn(p, "/"); 11597095Stjr complen = (long)strcspn(p, "/"); 11697095Stjr end = p + complen; 11797095Stjr last = *end == '\0'; 11897095Stjr *end = '\0'; 11997095Stjr 12097095Stjr if (namemax != -1 && complen > namemax) { 12197095Stjr warnx("%s: %s: component too long (limit %ld)", path, 12297095Stjr p, namemax); 12397095Stjr goto bad; 12497095Stjr } 12597095Stjr 12697095Stjr if (!pflag && stat(pathd, &sb) == -1 && errno != ENOENT) { 12798093Stjr warn("%s: %.*s", path, (int)(strlen(pathd) - 12898093Stjr complen - 1), pathd); 12997095Stjr goto bad; 13097095Stjr } 13197095Stjr 13297095Stjr if (pflag && (badch = portable(p)) >= 0) { 13397095Stjr warnx("%s: %s: component contains non-portable " 13497095Stjr "character `%c'", path, p, badch); 13597095Stjr goto bad; 13697095Stjr } 13797095Stjr 13897095Stjr if (last) 13997095Stjr break; 14097095Stjr 14197095Stjr if (!pflag) { 14297095Stjr errno = 0; 14397095Stjr svnamemax = namemax; 14497095Stjr namemax = pathconf(pathd, _PC_NAME_MAX); 14597095Stjr if (namemax == -1 && errno != 0) 14697095Stjr namemax = svnamemax; 14797095Stjr } 14897095Stjr 14997095Stjr *end = '/'; 15097095Stjr p = end + 1; 15197095Stjr } 15297095Stjr 15397095Stjr if (!pflag) { 15497095Stjr errno = 0; 15597095Stjr pathmax = pathconf(path, _PC_PATH_MAX); 15697095Stjr if (pathmax == -1 && errno != 0) 15797095Stjr pathmax = PATH_MAX; 15897095Stjr } else 15997095Stjr pathmax = _POSIX_PATH_MAX; 16097095Stjr if (pathmax != -1 && strlen(path) > (size_t)pathmax) { 16197095Stjr warnx("%s: path too long (limit %ld)", path, pathmax); 16297095Stjr goto bad; 16397095Stjr } 16497095Stjr 16597095Stjr free(pathd); 16697095Stjr return (0); 16797095Stjr 16897095Stjrbad: free(pathd); 16997095Stjr return (1); 17097095Stjr} 17197095Stjr 17297095Stjr/* 17397095Stjr * Check whether a path component contains only portable characters. Return 17497095Stjr * the first non-portable character found. 17597095Stjr */ 17697095Stjrstatic int 17797095Stjrportable(const char *path) 17897095Stjr{ 17997095Stjr static const char charset[] = 18097095Stjr "abcdefghijklmnopqrstuvwxyz" 18197095Stjr "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 18297095Stjr "0123456789._-"; 18397095Stjr long s; 18497095Stjr 18597095Stjr if (*path == '-') 18697095Stjr return (*path); 18797095Stjr 18897095Stjr s = strspn(path, charset); 18997095Stjr if (path[s] != '\0') 19097095Stjr return (path[s]); 19197095Stjr 19297095Stjr return (-1); 19397095Stjr} 194