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