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