]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/namei.c
namei: non-linux support (get_current_dir_name() and PATH_MAX)
[thirdparty/util-linux.git] / misc-utils / namei.c
1 /*-------------------------------------------------------------
2
3 The namei program
4
5 By: Roger S. Southwick
6
7 May 2, 1990
8
9
10 Modifications by Steve Tell March 28, 1991
11
12 usage: namei pathname [pathname ... ]
13
14 This program reads it's arguments as pathnames to any type
15 of Unix file (symlinks, files, directories, and so forth).
16 The program then follows each pathname until a terminal
17 point is found (a file, directory, char device, etc).
18 If it finds a symbolic link, we show the link, and start
19 following it, indenting the output to show the context.
20
21 This program is useful for finding a "too many levels of
22 symbolic links" problems.
23
24 For each line output, the program puts a file type first:
25
26 f: = the pathname we are currently trying to resolve
27 d = directory
28 D = directory that is a mount point
29 l = symbolic link (both the link and it's contents are output)
30 s = socket
31 b = block device
32 c = character device
33 p = FIFO (named pipe)
34 - = regular file
35 ? = an error of some kind
36
37 The program prints an informative messages when we exceed
38 the maximum number of symbolic links this system can have.
39
40 The program exits with a 1 status ONLY if it finds it cannot
41 chdir to /, or if it encounters an unknown file type.
42
43 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
44 - added Native Language Support
45
46 2006-12-15 Karel Zak <kzak@redhat.com>
47 - fixed logic; don't follow the path if a component is not directory
48 - fixed infinite loop of symbolic links; stack size is very limited
49
50 2007-09-10 Li Zefan <lizf@cn.fujitsu.com>
51 - added to identify FIFO
52
53 -------------------------------------------------------------*/
54
55 #include <stdio.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <strings.h>
59 #include <stdlib.h>
60 #include <errno.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/param.h>
64 #include "nls.h"
65
66 #define ERR strerror(errno),errno
67
68 int symcount;
69 int mflag = 0;
70 int xflag = 0;
71
72 #ifndef MAXSYMLINKS
73 #define MAXSYMLINKS 256
74 #endif
75
76 #ifndef PATH_MAX
77 #define PATH_MAX 4096
78 #endif
79
80 static char *pperm(unsigned short);
81 static void namei(char *, int, mode_t *);
82 static void usage(void);
83
84 int
85 main(int argc, char **argv) {
86 extern int optind;
87 int c;
88 #ifdef HAVE_GET_CURRENT_DIR_NAME
89 char *curdir;
90 #else
91 char curdir[PATH_MAX];
92 #endif
93
94 setlocale(LC_ALL, "");
95 bindtextdomain(PACKAGE, LOCALEDIR);
96 textdomain(PACKAGE);
97
98 if(argc < 2)
99 usage();
100
101 while((c = getopt(argc, argv, "mx")) != -1){
102 switch(c){
103 case 'm':
104 mflag = !mflag;
105 break;
106
107 case 'x':
108 xflag = !xflag;
109 break;
110
111 case '?':
112 default:
113 usage();
114 }
115 }
116
117 #ifdef HAVE_GET_CURRENT_DIR_NAME
118 if (!(curdir = get_current_dir_name()))
119 #else
120 if(getcwd(curdir, sizeof(curdir)) == NULL)
121 #endif
122 {
123 (void)fprintf(stderr,
124 _("namei: unable to get current directory - %s\n"),
125 curdir);
126 exit(1);
127 }
128
129
130 for(; optind < argc; optind++){
131 mode_t lastmode = 0;
132 (void)printf("f: %s\n", argv[optind]);
133 symcount = 1;
134 namei(argv[optind], 0, &lastmode);
135
136 if(chdir(curdir) == -1){
137 (void)fprintf(stderr,
138 _("namei: unable to chdir to %s - %s (%d)\n"),
139 curdir, ERR);
140 exit(1);
141 }
142 }
143 return 0;
144 }
145
146 static void
147 usage(void) {
148 (void)fprintf(stderr,_("usage: namei [-mx] pathname [pathname ...]\n"));
149 exit(1);
150 }
151
152 #ifndef NODEV
153 #define NODEV (dev_t)(-1)
154 #endif
155
156 static void
157 namei(char *file, int lev, mode_t *lastmode) {
158 char *cp;
159 char buf[BUFSIZ], sym[BUFSIZ];
160 struct stat stb;
161 int i;
162 dev_t lastdev = NODEV;
163
164 /*
165 * See if the file has a leading /, and if so cd to root
166 */
167
168 if(file && *file == '/'){
169 while(*file == '/')
170 file++;
171
172 if(chdir("/") == -1){
173 (void)fprintf(stderr,_("namei: could not chdir to root!\n"));
174 exit(1);
175 }
176 for(i = 0; i < lev; i++)
177 (void)printf(" ");
178
179 if(stat("/", &stb) == -1){
180 (void)fprintf(stderr, _("namei: could not stat root!\n"));
181 exit(1);
182 }
183 lastdev = stb.st_dev;
184
185 if(mflag)
186 (void)printf(" d%s /\n", pperm(stb.st_mode));
187 else
188 (void)printf(" d /\n");
189 }
190
191 for(; file && *file;){
192
193 if (strlen(file) >= BUFSIZ) {
194 fprintf(stderr,_("namei: buf overflow\n"));
195 return;
196 }
197
198 /*
199 * Copy up to the next / (or nil) into buf
200 */
201
202 for(cp = buf; *file != '\0' && *file != '/'; cp++, file++)
203 *cp = *file;
204
205 while(*file == '/') /* eat extra /'s */
206 file++;
207
208 *cp = '\0';
209
210 if(buf[0] == '\0'){
211
212 /*
213 * Buf is empty, so therefore we are done
214 * with this level of file
215 */
216
217 return;
218 }
219
220 for(i = 0; i < lev; i++)
221 (void)printf(" ");
222
223
224 /*
225 * We cannot walk on *path* if a previous element, in the path wasn't
226 * directory, because there could be a component with same name. Try:
227 *
228 * $ touch a b
229 * $ namei a/b <-- "a" is not directory so namei shouldn't
230 * check for "b"
231 */
232 if (*lastmode && S_ISDIR(*lastmode)==0 && S_ISLNK(*lastmode)==0){
233 (void)printf(" ? %s - %s (%d)\n", buf, strerror(ENOENT), ENOENT);
234 return;
235 }
236
237 /*
238 * See what type of critter this file is
239 */
240
241 if(lstat(buf, &stb) == -1){
242 (void)printf(" ? %s - %s (%d)\n", buf, ERR);
243 return;
244 }
245
246 *lastmode = stb.st_mode;
247
248 switch(stb.st_mode & S_IFMT){
249 case S_IFDIR:
250
251 /*
252 * File is a directory, chdir to it
253 */
254
255 if(chdir(buf) == -1){
256 (void)printf(_(" ? could not chdir into %s - %s (%d)\n"), buf, ERR );
257 return;
258 }
259 if(xflag && lastdev != stb.st_dev && lastdev != NODEV){
260 /* Across mnt point */
261 if(mflag)
262 (void)printf(" D%s %s\n", pperm(stb.st_mode), buf);
263 else
264 (void)printf(" D %s\n", buf);
265 }
266 else {
267 if(mflag)
268 (void)printf(" d%s %s\n", pperm(stb.st_mode), buf);
269 else
270 (void)printf(" d %s\n", buf);
271 }
272 lastdev = stb.st_dev;
273
274 (void)fflush(stdout);
275 break;
276
277 case S_IFLNK:
278 /*
279 * Sigh, another symlink. Read its contents and
280 * call namei()
281 */
282 bzero(sym, BUFSIZ);
283 if(readlink(buf, sym, BUFSIZ) == -1){
284 (void)printf(_(" ? problems reading symlink %s - %s (%d)\n"), buf, ERR);
285 return;
286 }
287
288 if(mflag)
289 (void)printf(" l%s %s -> %s", pperm(stb.st_mode), buf, sym);
290 else
291 (void)printf(" l %s -> %s", buf, sym);
292
293 if(symcount > 0 && symcount++ > MAXSYMLINKS){
294 (void)printf(_(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***\n"));
295 } else {
296 (void)printf("\n");
297 namei(sym, lev + 1, lastmode);
298 }
299 if (symcount > MAXSYMLINKS)
300 return;
301 break;
302
303 case S_IFCHR:
304 if(mflag)
305 (void)printf(" c%s %s\n", pperm(stb.st_mode), buf);
306 else
307 (void)printf(" c %s\n", buf);
308 break;
309
310 case S_IFBLK:
311 if(mflag)
312 (void)printf(" b%s %s\n", pperm(stb.st_mode), buf);
313 else
314 (void)printf(" b %s\n", buf);
315 break;
316
317 case S_IFSOCK:
318 if(mflag)
319 (void)printf(" s%s %s\n", pperm(stb.st_mode), buf);
320 else
321 (void)printf(" s %s\n", buf);
322 break;
323
324 case S_IFIFO:
325 if (mflag)
326 printf(" p%s %s\n", pperm(stb.st_mode), buf);
327 else
328 printf(" p %s\n", buf);
329 break;
330
331 case S_IFREG:
332 if(mflag)
333 (void)printf(" -%s %s\n", pperm(stb.st_mode), buf);
334 else
335 (void)printf(" - %s\n", buf);
336 break;
337
338 default:
339 (void)fprintf(stderr,_("namei: unknown file type 0%06o on file %s\n"), stb.st_mode, buf );
340 exit(1);
341
342 }
343 }
344 }
345
346 /* Take a
347 * Mode word, as from a struct stat, and return
348 * a pointer to a static string containing a printable version like ls.
349 * For example 0755 produces "rwxr-xr-x"
350 */
351 static char *
352 pperm(unsigned short mode) {
353 unsigned short m;
354 static char buf[16];
355 char *bp;
356 char *lschars = "xwrxwrxwr"; /* the complete string backwards */
357 char *cp;
358 int i;
359
360 for(i = 0, cp = lschars, m = mode, bp = &buf[8];
361 i < 9;
362 i++, cp++, m >>= 1, bp--) {
363
364 if(m & 1)
365 *bp = *cp;
366 else
367 *bp = '-';
368 }
369 buf[9] = '\0';
370
371 if(mode & S_ISUID) {
372 if(buf[2] == 'x')
373 buf[2] = 's';
374 else
375 buf[2] = 'S';
376 }
377 if(mode & S_ISGID) {
378 if(buf[5] == 'x')
379 buf[5] = 's';
380 else
381 buf[5] = 'S';
382 }
383 if(mode & S_ISVTX) {
384 if(buf[8] == 'x')
385 buf[8] = 't';
386 else
387 buf[8] = 'T';
388 }
389
390 return &buf[0];
391 }
392