Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/pathchk.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* pathchk
24
*
25
* Written by David Korn
26
*/
27
28
static const char usage[] =
29
"[-?\n@(#)$Id: pathchk (AT&T Research) 2009-07-24 $\n]"
30
USAGE_LICENSE
31
"[+NAME?pathchk - check pathnames for portability]"
32
"[+DESCRIPTION?\bpathchk\b checks each \apathname\a to see if it is "
33
"valid and/or portable. A \apathname\a is valid if it can be used to "
34
"access or create a file without causing syntax errors. A file is "
35
"portable if no truncation will result on any conforming POSIX.1 "
36
"implementation.]"
37
"[+?By default \bpathchk\b checks each component of each \apathname\a "
38
"based on the underlying file system. A diagnostic is written to "
39
"standard error for each pathname that:]"
40
"{"
41
"[+-?Is longer than \b$(getconf PATH_MAX)\b bytes.]"
42
"[+-?Contains any component longer than \b$(getconf NAME_MAX)\b "
43
"bytes.]"
44
"[+-?Contains any directory component in a directory that is not "
45
"searchable.]"
46
"[+-?Contains any character in any component that is not valid "
47
"in its containing directory.]"
48
"[+-?Is empty.]"
49
"}"
50
"[p:components?Instead of performing length checks on the underlying "
51
"file system, write a diagnostic for each pathname operand that:]"
52
"{"
53
"[+-?Is longer than \b$(getconf _POSIX_PATH_MAX)\b bytes.]"
54
"[+-?Contains any component longer than \b$(getconf "
55
"_POSIX_NAME_MAX)\b bytes.]"
56
"[+-?Contains any character in any component that is not in the "
57
"portable filename character set.]"
58
"}"
59
"[P:path?Write a diagnostic for each pathname operand that:]"
60
"{"
61
"[+-?Contains any component with \b-\b as the first character.]"
62
"[+-?Is empty.]"
63
"}"
64
"[a:all|portability?Equivalent to \b--components\b \b--path\b.]"
65
"\n"
66
"\npathname ...\n"
67
"\n"
68
"[+EXIT STATUS?]"
69
"{"
70
"[+0?All \apathname\a operands passed all of the checks.]"
71
"[+>0?An error occurred.]"
72
"}"
73
"[+SEE ALSO?\bgetconf\b(1), \bcreat\b(2), \bpathchk\b(2)]"
74
;
75
76
77
#include <cmd.h>
78
#include <ls.h>
79
80
#define COMPONENTS 0x1
81
#define PATH 0x2
82
83
#define isport(c) (((c)>='a' && (c)<='z') || ((c)>='A' && (c)<='Z') || ((c)>='0' && (c)<='9') || (strchr("._-",(c))!=0) )
84
85
/*
86
* call pathconf and handle unlimited sizes
87
*/
88
static long mypathconf(const char *path, int op)
89
{
90
register long r;
91
92
static const char* const ops[] = { "NAME_MAX", "PATH_MAX" };
93
94
errno = 0;
95
if ((r = strtol(astconf(ops[op], path, NiL), NiL, 0)) < 0 && !errno)
96
return LONG_MAX;
97
return r;
98
}
99
100
/*
101
* returns 1 if <path> passes test
102
*/
103
static int pathchk(char* path, int mode)
104
{
105
register char *cp=path, *cpold;
106
register int c;
107
register long r,name_max,path_max;
108
char buf[2];
109
110
if(!*path)
111
{
112
if (mode & PATH)
113
error(2,"path is empty");
114
return -1;
115
}
116
if(mode & COMPONENTS)
117
{
118
name_max = _POSIX_NAME_MAX;
119
path_max = _POSIX_PATH_MAX;
120
}
121
else
122
{
123
char tmp[2];
124
name_max = path_max = 0;
125
tmp[0] = (*cp=='/'? '/': '.');
126
tmp[1] = 0;
127
if((r=mypathconf(tmp, 0)) > _POSIX_NAME_MAX)
128
name_max = r;
129
if((r=mypathconf(tmp, 1)) > _POSIX_PATH_MAX)
130
path_max = r;
131
if(*cp!='/')
132
{
133
if(name_max==0||path_max==0)
134
{
135
if(!(cpold = getcwd((char*)0, 0)) && errno == EINVAL && (cpold = newof(0, char, PATH_MAX, 0)) && !getcwd(cpold, PATH_MAX))
136
{
137
free(cpold);
138
cpold = 0;
139
}
140
if(cpold)
141
{
142
cp = cpold + strlen(cpold);
143
while(name_max==0 || path_max==0)
144
{
145
if(cp>cpold)
146
while(--cp>cpold && *cp=='/');
147
*++cp = 0;
148
if(name_max==0 && (r=mypathconf(cpold, 0)) > _POSIX_NAME_MAX)
149
name_max = r;
150
if(path_max==0 && (r=mypathconf(cpold, 1)) > _POSIX_PATH_MAX)
151
path_max=r;
152
if(--cp==cpold)
153
{
154
free(cpold);
155
break;
156
}
157
while(*cp!='/')
158
cp--;
159
}
160
cp=path;
161
}
162
}
163
while(*cp=='/')
164
cp++;
165
}
166
if(name_max==0)
167
name_max=_POSIX_NAME_MAX;
168
if(path_max==0)
169
path_max=_POSIX_PATH_MAX;
170
while(*(cpold=cp))
171
{
172
while((c= *cp++) && c!='/');
173
if((cp-cpold) > name_max)
174
goto err;
175
errno=0;
176
cp[-1] = 0;
177
r = mypathconf(path, 0);
178
if((cp[-1]=c)==0)
179
cp--;
180
else while(*cp=='/')
181
cp++;
182
if(r>=0)
183
name_max=(r<_POSIX_NAME_MAX?_POSIX_NAME_MAX:r);
184
else if(errno==EINVAL)
185
continue;
186
#ifdef ENAMETOOLONG
187
else if(errno==ENAMETOOLONG)
188
{
189
error(2,"%s: pathname too long",path);
190
return -1;
191
}
192
#endif /*ENAMETOOLONG*/
193
else
194
break;
195
}
196
}
197
while(*(cpold=cp))
198
{
199
if((mode & PATH) && *cp == '-')
200
{
201
error(2,"%s: path component begins with '-'",path,fmtquote(buf, NiL, "'", 1, 0));
202
return -1;
203
}
204
while((c= *cp++) && c!='/')
205
if((mode & COMPONENTS) && !isport(c))
206
{
207
buf[0] = c;
208
buf[1] = 0;
209
error(2,"%s: '%s' not in portable character set",path,fmtquote(buf, NiL, "'", 1, 0));
210
return -1;
211
}
212
if((cp-cpold) > name_max)
213
goto err;
214
if(c==0)
215
break;
216
while(*cp=='/')
217
cp++;
218
}
219
if((cp-path) >= path_max)
220
{
221
error(2, "%s: pathname too long", path);
222
return -1;
223
}
224
return 0;
225
err:
226
error(2, "%s: component name %.*s too long", path, cp-cpold-1, cpold);
227
return -1;
228
}
229
230
int
231
b_pathchk(int argc, char** argv, Shbltin_t* context)
232
{
233
register int mode = 0;
234
register char* s;
235
236
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
237
for (;;)
238
{
239
switch (optget(argv, usage))
240
{
241
case 'a':
242
mode |= COMPONENTS|PATH;
243
continue;
244
case 'p':
245
mode |= COMPONENTS;
246
continue;
247
case 'P':
248
mode |= PATH;
249
continue;
250
case ':':
251
error(2, "%s", opt_info.arg);
252
break;
253
case '?':
254
error(ERROR_usage(2), "%s", opt_info.arg);
255
break;
256
}
257
break;
258
}
259
argv += opt_info.index;
260
if (!*argv || error_info.errors)
261
error(ERROR_usage(2),"%s", optusage(NiL));
262
while (s = *argv++)
263
pathchk(s, mode);
264
return error_info.errors != 0;
265
}
266
267