]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/namei.c
Imported from util-linux-2.9v tarball.
[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 - = regular file
34 ? = an error of some kind
35
36 The program prints an informative messages when we exceed
37 the maximum number of symbolic links this system can have.
38
39 The program exits with a 1 status ONLY if it finds it cannot
40 chdir to /, or if it encounters an unknown file type.
41
42 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
43 - added Native Language Support
44
45 -------------------------------------------------------------*/
46
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/param.h>
53 #include "nls.h"
54
55 #ifndef __GNU_LIBRARY__
56 extern char *sys_errlist[];
57 #endif
58
59 extern int errno;
60 #define ERR sys_errlist[errno],errno
61
62 int symcount;
63 int mflag = 0;
64 int xflag = 0;
65
66 #ifndef MAXSYMLINKS
67 #define MAXSYMLINKS 256
68 #endif
69
70 static char *pperm();
71
72 int
73 main(argc, argv)
74 int argc;
75 char *argv[];
76 {
77 void namei(), usage();
78 int getopt();
79 extern int optind;
80 register int c;
81 char curdir[MAXPATHLEN];
82
83 setlocale(LC_ALL, "");
84 bindtextdomain(PACKAGE, LOCALEDIR);
85 textdomain(PACKAGE);
86
87 if(argc < 2)
88 usage();
89
90 while((c = getopt(argc, argv, "mx")) != EOF){
91 switch(c){
92 case 'm':
93 mflag = !mflag;
94 break;
95
96 case 'x':
97 xflag = !xflag;
98 break;
99
100 case '?':
101 default:
102 usage();
103 }
104 }
105
106 if(getcwd(curdir, sizeof(curdir)) == NULL){
107 (void)fprintf(stderr, _("namei: unable to get current directory - %s\n"), curdir);
108 exit(1);
109 }
110
111
112 for(; optind < argc; optind++){
113 (void)printf("f: %s\n", argv[optind]);
114 symcount = 1;
115 namei(argv[optind], 0);
116
117 if(chdir(curdir) == -1){
118 (void)fprintf(stderr, _("namei: unable to chdir to %s - %s (%d)\n"), curdir, ERR);
119 exit(1);
120 }
121 }
122 return 0;
123 }
124
125 void
126 usage()
127 {
128 (void)fprintf(stderr,_("usage: namei [-mx] pathname [pathname ...]\n"));
129 exit(1);
130 }
131
132 #ifndef NODEV
133 #define NODEV (dev_t)(-1)
134 #endif
135
136 void
137 namei(file, lev)
138
139 register char *file;
140 register int lev;
141 {
142 register char *cp;
143 char buf[BUFSIZ], sym[BUFSIZ];
144 struct stat stb;
145 register int i;
146 dev_t lastdev = NODEV;
147
148 /*
149 * See if the file has a leading /, and if so cd to root
150 */
151
152 if(*file == '/'){
153 while(*file == '/')
154 file++;
155
156 if(chdir("/") == -1){
157 (void)fprintf(stderr,_("namei: could not chdir to root!\n"));
158 exit(1);
159 }
160 for(i = 0; i < lev; i++)
161 (void)printf(" ");
162
163 if(stat("/", &stb) == -1){
164 (void)fprintf(stderr, _("namei: could not stat root!\n"));
165 exit(1);
166 }
167 lastdev = stb.st_dev;
168
169 if(mflag)
170 (void)printf(" d%s /\n", pperm(stb.st_mode));
171 else
172 (void)printf(" d /\n");
173 }
174
175 for(;;){
176
177 /*
178 * Copy up to the next / (or nil) into buf
179 */
180
181 for(cp = buf; *file != '\0' && *file != '/'; cp++, file++)
182 *cp = *file;
183
184 while(*file == '/') /* eat extra /'s */
185 file++;
186
187 *cp = '\0';
188
189 if(buf[0] == '\0'){
190
191 /*
192 * Buf is empty, so therefore we are done
193 * with this level of file
194 */
195
196 return;
197 }
198
199 for(i = 0; i < lev; i++)
200 (void)printf(" ");
201
202 /*
203 * See what type of critter this file is
204 */
205
206 if(lstat(buf, &stb) == -1){
207 (void)printf(" ? %s - %s (%d)\n", buf, ERR);
208 return;
209 }
210
211 switch(stb.st_mode & S_IFMT){
212 case S_IFDIR:
213
214 /*
215 * File is a directory, chdir to it
216 */
217
218 if(chdir(buf) == -1){
219 (void)printf(_(" ? could not chdir into %s - %s (%d)\n"), buf, ERR );
220 return;
221 }
222 if(xflag && lastdev != stb.st_dev && lastdev != NODEV){
223 /* Across mnt point */
224 if(mflag)
225 (void)printf(" D%s %s\n", pperm(stb.st_mode), buf);
226 else
227 (void)printf(" D %s\n", buf);
228 }
229 else {
230 if(mflag)
231 (void)printf(" d%s %s\n", pperm(stb.st_mode), buf);
232 else
233 (void)printf(" d %s\n", buf);
234 }
235 lastdev = stb.st_dev;
236
237 (void)fflush(stdout);
238 break;
239
240 case S_IFLNK:
241 /*
242 * Sigh, another symlink. Read it's contents and
243 * call namei()
244 */
245
246 bzero(sym, BUFSIZ);
247 if(readlink(buf, sym, BUFSIZ) == -1){
248 (void)printf(_(" ? problems reading symlink %s - %s (%d)\n"), buf, ERR);
249 return;
250 }
251
252 if(mflag)
253 (void)printf(" l%s %s -> %s", pperm(stb.st_mode), buf, sym);
254 else
255 (void)printf(" l %s -> %s", buf, sym);
256
257 if(symcount > 0 && symcount++ > MAXSYMLINKS){
258 (void)printf(_(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***"));
259 symcount = -1;
260 }
261 (void)printf("\n");
262 namei(sym, lev + 1);
263 break;
264
265 case S_IFCHR:
266 if(mflag)
267 (void)printf(" c%s %s\n", pperm(stb.st_mode), buf);
268 else
269 (void)printf(" c %s\n", buf);
270 break;
271
272 case S_IFBLK:
273 if(mflag)
274 (void)printf(" b%s %s\n", pperm(stb.st_mode), buf);
275 else
276 (void)printf(" b %s\n", buf);
277 break;
278
279 case S_IFSOCK:
280 if(mflag)
281 (void)printf(" s%s %s\n", pperm(stb.st_mode), buf);
282 else
283 (void)printf(" s %s\n", buf);
284 break;
285
286 case S_IFREG:
287 if(mflag)
288 (void)printf(" -%s %s\n", pperm(stb.st_mode), buf);
289 else
290 (void)printf(" - %s\n", buf);
291 break;
292
293 default:
294 (void)fprintf(stderr,_("namei: unknown file type 0%06o on file %s\n"), stb.st_mode, buf );
295 exit(1);
296
297 }
298 }
299 }
300
301 /* Take a
302 * Mode word, as from a struct stat, and return
303 * a pointer to a static string containing a printable version like ls.
304 * For example 0755 produces "rwxr-xr-x"
305 */
306 static char *
307 pperm(mode)
308 unsigned short mode;
309 {
310 unsigned short m;
311 static char buf[16];
312 char *bp;
313 char *lschars = "xwrxwrxwr"; /* the complete string backwards */
314 char *cp;
315 int i;
316
317 for(i = 0, cp = lschars, m = mode, bp = &buf[8];
318 i < 9;
319 i++, cp++, m >>= 1, bp--) {
320
321 if(m & 1)
322 *bp = *cp;
323 else
324 *bp = '-';
325 }
326 buf[9] = '\0';
327
328 if(mode & S_ISUID) {
329 if(buf[2] == 'x')
330 buf[2] = 's';
331 else
332 buf[2] = 'S';
333 }
334 if(mode & S_ISGID) {
335 if(buf[5] == 'x')
336 buf[5] = 's';
337 else
338 buf[5] = 'S';
339 }
340 if(mode & S_ISVTX) {
341 if(buf[8] == 'x')
342 buf[8] = 't';
343 else
344 buf[8] = 'T';
345 }
346
347 return &buf[0];
348 }
349
350