]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/namei.c
namei: add to identify FIFO (named pipe) and update manpage
[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 static char *pperm(unsigned short);
77 static void namei(char *, int, mode_t *);
78 static void usage(void);
79
80 int
81 main(int argc, char **argv) {
82 extern int optind;
83 int c;
84 char curdir[MAXPATHLEN];
85
86 setlocale(LC_ALL, "");
87 bindtextdomain(PACKAGE, LOCALEDIR);
88 textdomain(PACKAGE);
89
90 if(argc < 2)
91 usage();
92
93 while((c = getopt(argc, argv, "mx")) != -1){
94 switch(c){
95 case 'm':
96 mflag = !mflag;
97 break;
98
99 case 'x':
100 xflag = !xflag;
101 break;
102
103 case '?':
104 default:
105 usage();
106 }
107 }
108
109 if(getcwd(curdir, sizeof(curdir)) == NULL){
110 (void)fprintf(stderr,
111 _("namei: unable to get current directory - %s\n"),
112 curdir);
113 exit(1);
114 }
115
116
117 for(; optind < argc; optind++){
118 mode_t lastmode = 0;
119 (void)printf("f: %s\n", argv[optind]);
120 symcount = 1;
121 namei(argv[optind], 0, &lastmode);
122
123 if(chdir(curdir) == -1){
124 (void)fprintf(stderr,
125 _("namei: unable to chdir to %s - %s (%d)\n"),
126 curdir, ERR);
127 exit(1);
128 }
129 }
130 return 0;
131 }
132
133 static void
134 usage(void) {
135 (void)fprintf(stderr,_("usage: namei [-mx] pathname [pathname ...]\n"));
136 exit(1);
137 }
138
139 #ifndef NODEV
140 #define NODEV (dev_t)(-1)
141 #endif
142
143 int kzak;
144
145 static void
146 namei(char *file, int lev, mode_t *lastmode) {
147 char *cp;
148 char buf[BUFSIZ], sym[BUFSIZ];
149 struct stat stb;
150 int i;
151 dev_t lastdev = NODEV;
152
153 /*
154 * See if the file has a leading /, and if so cd to root
155 */
156
157 if(file && *file == '/'){
158 while(*file == '/')
159 file++;
160
161 if(chdir("/") == -1){
162 (void)fprintf(stderr,_("namei: could not chdir to root!\n"));
163 exit(1);
164 }
165 for(i = 0; i < lev; i++)
166 (void)printf(" ");
167
168 if(stat("/", &stb) == -1){
169 (void)fprintf(stderr, _("namei: could not stat root!\n"));
170 exit(1);
171 }
172 lastdev = stb.st_dev;
173
174 if(mflag)
175 (void)printf(" d%s /\n", pperm(stb.st_mode));
176 else
177 (void)printf(" d /\n");
178 }
179
180 for(; file && *file;){
181
182 if (strlen(file) >= BUFSIZ) {
183 fprintf(stderr,_("namei: buf overflow\n"));
184 return;
185 }
186
187 /*
188 * Copy up to the next / (or nil) into buf
189 */
190
191 for(cp = buf; *file != '\0' && *file != '/'; cp++, file++)
192 *cp = *file;
193
194 while(*file == '/') /* eat extra /'s */
195 file++;
196
197 *cp = '\0';
198
199 if(buf[0] == '\0'){
200
201 /*
202 * Buf is empty, so therefore we are done
203 * with this level of file
204 */
205
206 return;
207 }
208
209 for(i = 0; i < lev; i++)
210 (void)printf(" ");
211
212
213 /*
214 * We cannot walk on *path* if a previous element, in the path wasn't
215 * directory, because there could be a component with same name. Try:
216 *
217 * $ touch a b
218 * $ namei a/b <-- "a" is not directory so namei shouldn't
219 * check for "b"
220 */
221 if (*lastmode && S_ISDIR(*lastmode)==0 && S_ISLNK(*lastmode)==0){
222 (void)printf(" ? %s - %s (%d)\n", buf, strerror(ENOENT), ENOENT);
223 return;
224 }
225
226 /*
227 * See what type of critter this file is
228 */
229
230 if(lstat(buf, &stb) == -1){
231 (void)printf(" ? %s - %s (%d)\n", buf, ERR);
232 return;
233 }
234
235 *lastmode = stb.st_mode;
236
237 switch(stb.st_mode & S_IFMT){
238 case S_IFDIR:
239
240 /*
241 * File is a directory, chdir to it
242 */
243
244 if(chdir(buf) == -1){
245 (void)printf(_(" ? could not chdir into %s - %s (%d)\n"), buf, ERR );
246 return;
247 }
248 if(xflag && lastdev != stb.st_dev && lastdev != NODEV){
249 /* Across mnt point */
250 if(mflag)
251 (void)printf(" D%s %s\n", pperm(stb.st_mode), buf);
252 else
253 (void)printf(" D %s\n", buf);
254 }
255 else {
256 if(mflag)
257 (void)printf(" d%s %s\n", pperm(stb.st_mode), buf);
258 else
259 (void)printf(" d %s\n", buf);
260 }
261 lastdev = stb.st_dev;
262
263 (void)fflush(stdout);
264 break;
265
266 case S_IFLNK:
267 /*
268 * Sigh, another symlink. Read its contents and
269 * call namei()
270 */
271 bzero(sym, BUFSIZ);
272 if(readlink(buf, sym, BUFSIZ) == -1){
273 (void)printf(_(" ? problems reading symlink %s - %s (%d)\n"), buf, ERR);
274 return;
275 }
276
277 if(mflag)
278 (void)printf(" l%s %s -> %s", pperm(stb.st_mode), buf, sym);
279 else
280 (void)printf(" l %s -> %s", buf, sym);
281
282 if(symcount > 0 && symcount++ > MAXSYMLINKS){
283 (void)printf(_(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***\n"));
284 } else {
285 (void)printf("\n");
286 namei(sym, lev + 1, lastmode);
287 }
288 if (symcount > MAXSYMLINKS)
289 return;
290 break;
291
292 case S_IFCHR:
293 if(mflag)
294 (void)printf(" c%s %s\n", pperm(stb.st_mode), buf);
295 else
296 (void)printf(" c %s\n", buf);
297 break;
298
299 case S_IFBLK:
300 if(mflag)
301 (void)printf(" b%s %s\n", pperm(stb.st_mode), buf);
302 else
303 (void)printf(" b %s\n", buf);
304 break;
305
306 case S_IFSOCK:
307 if(mflag)
308 (void)printf(" s%s %s\n", pperm(stb.st_mode), buf);
309 else
310 (void)printf(" s %s\n", buf);
311 break;
312
313 case S_IFIFO:
314 if (mflag)
315 printf(" p%s %s\n", pperm(stb.st_mode), buf);
316 else
317 printf(" p %s\n", buf);
318 break;
319
320 case S_IFREG:
321 if(mflag)
322 (void)printf(" -%s %s\n", pperm(stb.st_mode), buf);
323 else
324 (void)printf(" - %s\n", buf);
325 break;
326
327 default:
328 (void)fprintf(stderr,_("namei: unknown file type 0%06o on file %s\n"), stb.st_mode, buf );
329 exit(1);
330
331 }
332 }
333 }
334
335 /* Take a
336 * Mode word, as from a struct stat, and return
337 * a pointer to a static string containing a printable version like ls.
338 * For example 0755 produces "rwxr-xr-x"
339 */
340 static char *
341 pperm(unsigned short mode) {
342 unsigned short m;
343 static char buf[16];
344 char *bp;
345 char *lschars = "xwrxwrxwr"; /* the complete string backwards */
346 char *cp;
347 int i;
348
349 for(i = 0, cp = lschars, m = mode, bp = &buf[8];
350 i < 9;
351 i++, cp++, m >>= 1, bp--) {
352
353 if(m & 1)
354 *bp = *cp;
355 else
356 *bp = '-';
357 }
358 buf[9] = '\0';
359
360 if(mode & S_ISUID) {
361 if(buf[2] == 'x')
362 buf[2] = 's';
363 else
364 buf[2] = 'S';
365 }
366 if(mode & S_ISGID) {
367 if(buf[5] == 'x')
368 buf[5] = 's';
369 else
370 buf[5] = 'S';
371 }
372 if(mode & S_ISVTX) {
373 if(buf[8] == 'x')
374 buf[8] = 't';
375 else
376 buf[8] = 'T';
377 }
378
379 return &buf[0];
380 }
381
382