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