xref: /onnv-gate/usr/src/lib/libcmd/common/pathchk.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1992-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                                                                      *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin  * pathchk
244887Schin  *
254887Schin  * Written by David Korn
264887Schin  */
274887Schin 
284887Schin static const char usage[] =
2910898Sroland.mainz@nrubsig.org "[-?\n@(#)$Id: pathchk (AT&T Research) 2009-07-24 $\n]"
304887Schin USAGE_LICENSE
314887Schin "[+NAME?pathchk - check pathnames for portability]"
3210898Sroland.mainz@nrubsig.org "[+DESCRIPTION?\bpathchk\b checks each \apathname\a to see if it is "
3310898Sroland.mainz@nrubsig.org     "valid and/or portable. A \apathname\a is valid if it can be used to "
3410898Sroland.mainz@nrubsig.org     "access or create a file without causing syntax errors. A file is "
3510898Sroland.mainz@nrubsig.org     "portable if no truncation will result on any conforming POSIX.1 "
3610898Sroland.mainz@nrubsig.org     "implementation.]"
374887Schin "[+?By default \bpathchk\b checks each component of each \apathname\a "
3810898Sroland.mainz@nrubsig.org     "based on the underlying file system. A diagnostic is written to "
3910898Sroland.mainz@nrubsig.org     "standard error for each pathname that:]"
4010898Sroland.mainz@nrubsig.org     "{"
4110898Sroland.mainz@nrubsig.org         "[+-?Is longer than \b$(getconf PATH_MAX)\b bytes.]"
4210898Sroland.mainz@nrubsig.org         "[+-?Contains any component longer than \b$(getconf NAME_MAX)\b "
4310898Sroland.mainz@nrubsig.org             "bytes.]"
4410898Sroland.mainz@nrubsig.org         "[+-?Contains any directory component in a directory that is not "
4510898Sroland.mainz@nrubsig.org             "searchable.]"
4610898Sroland.mainz@nrubsig.org         "[+-?Contains any character in any component that is not valid "
4710898Sroland.mainz@nrubsig.org             "in its containing directory.]"
4810898Sroland.mainz@nrubsig.org         "[+-?Is empty.]"
4910898Sroland.mainz@nrubsig.org     "}"
5010898Sroland.mainz@nrubsig.org "[p:components?Instead of performing length checks on the underlying "
5110898Sroland.mainz@nrubsig.org     "file system, write a diagnostic for each pathname operand that:]"
5210898Sroland.mainz@nrubsig.org     "{"
5310898Sroland.mainz@nrubsig.org         "[+-?Is longer than \b$(getconf _POSIX_PATH_MAX)\b bytes.]"
5410898Sroland.mainz@nrubsig.org         "[+-?Contains any component longer than \b$(getconf "
5510898Sroland.mainz@nrubsig.org             "_POSIX_NAME_MAX)\b bytes.]"
564887Schin         "[+-?Contains any character in any component that is not in the "
5710898Sroland.mainz@nrubsig.org             "portable filename character set.]"
5810898Sroland.mainz@nrubsig.org     "}"
5910898Sroland.mainz@nrubsig.org "[P:path?Write a diagnostic for each pathname operand that:]"
6010898Sroland.mainz@nrubsig.org     "{"
6110898Sroland.mainz@nrubsig.org         "[+-?Contains any component with \b-\b as the first character.]"
6210898Sroland.mainz@nrubsig.org         "[+-?Is empty.]"
6310898Sroland.mainz@nrubsig.org     "}"
6410898Sroland.mainz@nrubsig.org "[a:all|portability?Equivalent to \b--components\b \b--path\b.]"
654887Schin "\n"
664887Schin "\npathname ...\n"
674887Schin "\n"
6810898Sroland.mainz@nrubsig.org "[+EXIT STATUS?]"
6910898Sroland.mainz@nrubsig.org     "{"
704887Schin         "[+0?All \apathname\a operands passed all of the checks.]"
714887Schin         "[+>0?An error occurred.]"
7210898Sroland.mainz@nrubsig.org     "}"
734887Schin "[+SEE ALSO?\bgetconf\b(1), \bcreat\b(2), \bpathchk\b(2)]"
744887Schin ;
754887Schin 
764887Schin 
774887Schin #include	<cmd.h>
784887Schin #include	<ls.h>
794887Schin 
8010898Sroland.mainz@nrubsig.org #define COMPONENTS	0x1
8110898Sroland.mainz@nrubsig.org #define PATH	0x2
8210898Sroland.mainz@nrubsig.org 
834887Schin #define isport(c)	(((c)>='a' && (c)<='z') || ((c)>='A' && (c)<='Z') || ((c)>='0' && (c)<='9') || (strchr("._-",(c))!=0) )
844887Schin 
854887Schin /*
864887Schin  * call pathconf and handle unlimited sizes
874887Schin  */
mypathconf(const char * path,int op)884887Schin static long mypathconf(const char *path, int op)
894887Schin {
908462SApril.Chin@Sun.COM 	register long			r;
914887Schin 
928462SApril.Chin@Sun.COM 	static const char* const	ops[] = { "NAME_MAX", "PATH_MAX" };
934887Schin 
9410898Sroland.mainz@nrubsig.org 	errno = 0;
9510898Sroland.mainz@nrubsig.org 	if ((r = strtol(astconf(ops[op], path, NiL), NiL, 0)) < 0 && !errno)
9610898Sroland.mainz@nrubsig.org 		return LONG_MAX;
9710898Sroland.mainz@nrubsig.org 	return r;
984887Schin }
994887Schin 
1004887Schin /*
1014887Schin  * returns 1 if <path> passes test
1024887Schin  */
pathchk(char * path,int mode)1034887Schin static int pathchk(char* path, int mode)
1044887Schin {
1054887Schin 	register char *cp=path, *cpold;
1064887Schin 	register int c;
1074887Schin 	register long r,name_max,path_max;
1084887Schin 	char buf[2];
1094887Schin 
1104887Schin 	if(!*path)
1114887Schin 	{
11210898Sroland.mainz@nrubsig.org 		if (mode & PATH)
11310898Sroland.mainz@nrubsig.org 			error(2,"path is empty");
11410898Sroland.mainz@nrubsig.org 		return -1;
1154887Schin 	}
11610898Sroland.mainz@nrubsig.org 	if(mode & COMPONENTS)
1174887Schin 	{
1184887Schin 		name_max = _POSIX_NAME_MAX;
1194887Schin 		path_max = _POSIX_PATH_MAX;
1204887Schin 	}
1214887Schin 	else
1224887Schin 	{
1234887Schin 		char tmp[2];
1244887Schin 		name_max = path_max = 0;
1254887Schin 		tmp[0] = (*cp=='/'? '/': '.');
1264887Schin 		tmp[1] = 0;
1274887Schin 		if((r=mypathconf(tmp, 0)) > _POSIX_NAME_MAX)
1284887Schin 			name_max = r;
1294887Schin 		if((r=mypathconf(tmp, 1)) > _POSIX_PATH_MAX)
1304887Schin 			path_max = r;
1314887Schin 		if(*cp!='/')
1324887Schin 		{
1334887Schin 			if(name_max==0||path_max==0)
1344887Schin 			{
1354887Schin 				if(!(cpold = getcwd((char*)0, 0)) && errno == EINVAL && (cpold = newof(0, char, PATH_MAX, 0)) && !getcwd(cpold, PATH_MAX))
1364887Schin 				{
1374887Schin 					free(cpold);
1384887Schin 					cpold = 0;
1394887Schin 				}
1404887Schin 				if(cpold)
1414887Schin 				{
1424887Schin 					cp = cpold + strlen(cpold);
1434887Schin 					while(name_max==0 || path_max==0)
1444887Schin 					{
1454887Schin 						if(cp>cpold)
1464887Schin 							while(--cp>cpold && *cp=='/');
1474887Schin 						*++cp = 0;
1484887Schin 						if(name_max==0 && (r=mypathconf(cpold, 0)) > _POSIX_NAME_MAX)
1494887Schin 							name_max = r;
1504887Schin 						if(path_max==0 && (r=mypathconf(cpold, 1)) > _POSIX_PATH_MAX)
1514887Schin 							path_max=r;
1524887Schin 						if(--cp==cpold)
1534887Schin 						{
1544887Schin 							free(cpold);
1554887Schin 							break;
1564887Schin 						}
1574887Schin 						while(*cp!='/')
1584887Schin 							cp--;
1594887Schin 					}
1604887Schin 					cp=path;
1614887Schin 				}
1624887Schin 			}
1634887Schin 			while(*cp=='/')
1644887Schin 				cp++;
1654887Schin 		}
1664887Schin 		if(name_max==0)
1674887Schin 			name_max=_POSIX_NAME_MAX;
1684887Schin 		if(path_max==0)
1694887Schin 			path_max=_POSIX_PATH_MAX;
1704887Schin 		while(*(cpold=cp))
1714887Schin 		{
1724887Schin 			while((c= *cp++) && c!='/');
1734887Schin 			if((cp-cpold) > name_max)
1744887Schin 				goto err;
1754887Schin 			errno=0;
1764887Schin 			cp[-1] = 0;
1774887Schin 			r = mypathconf(path, 0);
1784887Schin 			if((cp[-1]=c)==0)
1794887Schin 				cp--;
1804887Schin 			else while(*cp=='/')
1814887Schin 				cp++;
1824887Schin 			if(r>=0)
1834887Schin 				name_max=(r<_POSIX_NAME_MAX?_POSIX_NAME_MAX:r);
1844887Schin 			else if(errno==EINVAL)
1854887Schin 				continue;
1864887Schin #ifdef ENAMETOOLONG
1874887Schin 			else if(errno==ENAMETOOLONG)
1884887Schin 			{
1894887Schin 				error(2,"%s: pathname too long",path);
19010898Sroland.mainz@nrubsig.org 				return -1;
1914887Schin 			}
1924887Schin #endif /*ENAMETOOLONG*/
1934887Schin 			else
1944887Schin 				break;
1954887Schin 		}
1964887Schin 	}
1974887Schin 	while(*(cpold=cp))
1984887Schin 	{
19910898Sroland.mainz@nrubsig.org 		if((mode & PATH) && *cp == '-')
2004887Schin 		{
2014887Schin 			error(2,"%s: path component begins with '-'",path,fmtquote(buf, NiL, "'", 1, 0));
20210898Sroland.mainz@nrubsig.org 			return -1;
2034887Schin 		}
2044887Schin 		while((c= *cp++) && c!='/')
20510898Sroland.mainz@nrubsig.org 			if((mode & COMPONENTS) && !isport(c))
2064887Schin 			{
2074887Schin 				buf[0] = c;
2084887Schin 				buf[1] = 0;
2094887Schin 				error(2,"%s: '%s' not in portable character set",path,fmtquote(buf, NiL, "'", 1, 0));
21010898Sroland.mainz@nrubsig.org 				return -1;
2114887Schin 			}
2124887Schin 		if((cp-cpold) > name_max)
2134887Schin 			goto err;
2144887Schin 		if(c==0)
2154887Schin 			break;
2164887Schin 		while(*cp=='/')
2174887Schin 			cp++;
2184887Schin 	}
2194887Schin 	if((cp-path) >= path_max)
2204887Schin 	{
22110898Sroland.mainz@nrubsig.org 		error(2, "%s: pathname too long", path);
22210898Sroland.mainz@nrubsig.org 		return -1;
2234887Schin 	}
22410898Sroland.mainz@nrubsig.org 	return 0;
22510898Sroland.mainz@nrubsig.org  err:
22610898Sroland.mainz@nrubsig.org 	error(2, "%s: component name %.*s too long", path, cp-cpold-1, cpold);
22710898Sroland.mainz@nrubsig.org 	return -1;
2284887Schin }
2294887Schin 
2304887Schin int
b_pathchk(int argc,char ** argv,void * context)2314887Schin b_pathchk(int argc, char** argv, void* context)
2324887Schin {
23310898Sroland.mainz@nrubsig.org 	register int	mode = 0;
23410898Sroland.mainz@nrubsig.org 	register char*	s;
2354887Schin 
2364887Schin 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
23710898Sroland.mainz@nrubsig.org 	for (;;)
2384887Schin 	{
23910898Sroland.mainz@nrubsig.org 		switch (optget(argv, usage))
24010898Sroland.mainz@nrubsig.org 		{
24110898Sroland.mainz@nrubsig.org 		case 0:
24210898Sroland.mainz@nrubsig.org 			break;
24310898Sroland.mainz@nrubsig.org   		case 'a':
24410898Sroland.mainz@nrubsig.org 			mode |= COMPONENTS|PATH;
24510898Sroland.mainz@nrubsig.org 			continue;
24610898Sroland.mainz@nrubsig.org   		case 'p':
24710898Sroland.mainz@nrubsig.org 			mode |= COMPONENTS;
24810898Sroland.mainz@nrubsig.org 			continue;
24910898Sroland.mainz@nrubsig.org   		case 'P':
25010898Sroland.mainz@nrubsig.org 			mode |= PATH;
25110898Sroland.mainz@nrubsig.org 			continue;
25210898Sroland.mainz@nrubsig.org 		case ':':
25310898Sroland.mainz@nrubsig.org 			error(2, "%s", opt_info.arg);
25410898Sroland.mainz@nrubsig.org 			continue;
25510898Sroland.mainz@nrubsig.org 		case '?':
25610898Sroland.mainz@nrubsig.org 			error(ERROR_usage(2), "%s", opt_info.arg);
25710898Sroland.mainz@nrubsig.org 			continue;
25810898Sroland.mainz@nrubsig.org 		}
2594887Schin 		break;
2604887Schin 	}
2614887Schin 	argv += opt_info.index;
26210898Sroland.mainz@nrubsig.org 	if (!*argv || error_info.errors)
26310898Sroland.mainz@nrubsig.org 		error(ERROR_usage(2),"%s", optusage(NiL));
26410898Sroland.mainz@nrubsig.org 	while (s = *argv++)
26510898Sroland.mainz@nrubsig.org 		pathchk(s, mode);
26610898Sroland.mainz@nrubsig.org 	return error_info.errors != 0;
2674887Schin }
268