rsalz@uunet.uu.net (Rich Salz) (03/27/91)
Submitted-by: Roger Southwick <rogers@fangorn.wr.tek.com> Posting-number: Volume 24, Issue 87 Archive-name: namei [ I wrote the Makefile. --r$ ] This program takes a set of pathnames. It scans each component in turn and follows symlinks until it reaches the end of the pathname. It prints the results of interpreting each directory component. Requires the lstat system call and the S_IFLINK inode type. -Roger (rogers@fangorn.wr.tek.com) #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: README namei.1 namei.c # Wrapped by rogers@fangorn on Wed Mar 20 17:51:06 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(989 characters\) sed "s/^X//" >README <<'END_OF_README' XTired of running into "Too many levels of symlinks" problems on Xyour 4.2 BSD derivitive machine? X XWe sure did... our NFS'ed network of lots of Suns, Vaxen and so forth Xmade it impossible at times to trace down where a file REALLY lived. XI mean ls -l is nice, but wouldn't you like to follow things like Xthe namei routine in the kernel does? X XWell here it is.... the namei program. It follows things out until Xa terminal state is found. X XThis program compiles and runs under: X X SunOS 4.0.1 (sun3's) X SunOS 4.0.3 (sun4's) X SunOS 4.1.1 (sun4's) X Ultrix 3.1 X BSD 4.3 X Xand probably a host of other 4.2 derived systems (but probably not XSystem V). X XAnyway, if anyone has any bugs (or enhancements), please send them to Xme in E-mail form. X XAnd, by the way, if you make LOTS of money off of this program, please Xdon't tell me :-). X X -Roger (rogers@fangorn.wr.tek.com) X UUCP: ...!uunet!tektronix!fangorn.wr.tek.com!rogers X ARPA: <rogers%fangorn.wr.tek.com@RELAY.CS.NET> END_OF_README if test 989 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f namei.1 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"namei.1\" else echo shar: Extracting \"namei.1\" \(1496 characters\) sed "s/^X//" >namei.1 <<'END_OF_namei.1' X.\" X.\" Version 1.4 of namei X.\" X.TH NAMEI 1 "Local" X.SH NAME Xnamei - follow a pathname until a terminal point is found X.SH SYNOPSIS X.B namei X.I [-mx] X.I pathname X.I "[ pathname ... ]" X.SH DESCRIPTION X.I Namei Xuses its arguments as pathnames to any type Xof Unix file (symlinks, files, directories, and so forth). X.I Namei Xthen follows each pathname until a terminal Xpoint is found (a file, directory, char device, etc). XIf it finds a symbolic link, we show the link, and start Xfollowing it, indenting the output to show the context. X.PP XThis program is useful for finding a "too many levels of Xsymbolic links" problems. X.PP XFor each line output, X.I namei Xoutputs a the following characters to identify the file types found: X.LP X.nf X f: = the pathname we are currently trying to resolve X d = directory X l = symbolic link (both the link and it's contents are output) X s = socket X b = block device X c = character device X - = regular file X ? = an error of some kind X.fi X.PP X.I Namei Xprints an informative message when Xthe maximum number of symbolic links this system can have has been exceeded. X.SH OPTIONS X.TP 8 X.B -x XShow mount point directories with a 'D', rather than a 'd'. X.TP 8 X.B -m XShow the mode bits of each file type in octal notation. X.SH AUTHOR XRoger Southwick (rogers@amadeus.wr.tek.com) X.SH BUGS XTo be discovered. X.SH CAVEATS X.I Namei Xwill follow an infinite loop of symbolic links forever. To escape, use XSIGINT (usually ^C). X.SH "SEE ALSO" Xls(1), stat(1) END_OF_namei.1 if test 1496 -ne `wc -c <namei.1`; then echo shar: \"namei.1\" unpacked with wrong size! fi # end of overwriting check fi if test -f namei.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"namei.c\" else echo shar: Extracting \"namei.c\" \(5724 characters\) sed "s/^X//" >namei.c <<'END_OF_namei.c' X/*------------------------------------------------------------- X XThe namei program X XBy: Roger S. Southwick X XMay 2, 1990 X Xusage: namei pathname [pathname ... ] X XThis program reads it's arguments as pathnames to any type Xof Unix file (symlinks, files, directories, and so forth). XThe program then follows each pathname until a terminal Xpoint is found (a file, directory, char device, etc). XIf it finds a symbolic link, we show the link, and start Xfollowing it, indenting the output to show the context. X XThis program is useful for finding a "too many levels of Xsymbolic links" problems. X XFor each line output, the program puts a file type first: X X f: = the pathname we are currently trying to resolve X d = directory X D = directory that is a mount point X l = symbolic link (both the link and it's contents are output) X s = socket X b = block device X c = character device X - = regular file X ? = an error of some kind X XThe program prints an informative messages when we exceed Xthe maximum number of symbolic links this system can have. X XThe program exits with a 1 status ONLY if it finds it cannot Xchdir to /, or if it encounters an unknown file type. X X-------------------------------------------------------------*/ X X#ifndef lint Xstatic char *RCSid = "$Id: namei.c,v 1.4 91/03/20 17:44:11 rogers Release_1 $"; X#endif X X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/param.h> X Xextern char *sys_errlist[]; Xextern int errno; X#define ERR sys_errlist[errno],errno X Xint symcount; Xint mflag = 0; Xint xflag = 0; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X void namei(), usage(); X char *getwd(); X int getopt(); X extern int optind; X register int c; X char curdir[MAXPATHLEN]; X X if(argc < 2) X usage(); X X while((c = getopt(argc, argv, "mx")) != EOF){ X switch(c){ X case 'm': X mflag++; X break; X X case 'x': X xflag++; X break; X X case '?': X default: X usage(); X } X } X X if(getwd(curdir) == NULL){ X (void)fprintf(stderr, "namei: unable to get current directory - %s\n", curdir); X exit(1); X } X X X for(; optind < argc; optind++){ X (void)printf("f: %s\n", argv[optind]); X symcount = 1; X namei(argv[optind], 0); X X if(chdir(curdir) == -1){ X (void)fprintf(stderr, "namei: unable to chdir to %s - %s (%d)\n", curdir, ERR); X exit(1); X } X } X exit(0); X} X Xvoid Xusage() X{ X (void)fprintf(stderr,"usage: namei [-mx] pathname [pathname ...]\n"); X exit(1); X} X X#ifndef NODEV X#define NODEV (dev_t)(-1) X#endif X Xvoid Xnamei(file, lev) X Xregister char *file; Xregister int lev; X{ X register char *cp; X char buf[BUFSIZ], sym[BUFSIZ]; X struct stat stb; X register int i; X dev_t lastdev = NODEV; X X /* X * See if the file has a leading /, and if so cd to root X */ X X if(*file == '/'){ X while(*file == '/') X file++; X X if(chdir("/") == -1){ X (void)fprintf(stderr,"namei: could not chdir to root!\n"); X exit(1); X } X for(i = 0; i < lev; i++) X (void)printf(" "); X X if(stat("/", &stb) == -1){ X (void)fprintf(stderr, "namei: could not stat root!\n"); X exit(1); X } X lastdev = stb.st_dev; X X if(mflag) X (void)printf(" d %04o /\n", stb.st_mode & 07777); X else X (void)printf(" d /\n"); X } X X for(;;){ X X /* X * Copy up to the next / (or nil) into buf X */ X X for(cp = buf; *file != '\0' && *file != '/'; cp++, file++) X *cp = *file; X X while(*file == '/') /* eat extra /'s */ X file++; X X *cp = '\0'; X X if(buf[0] == '\0'){ X X /* X * Buf is empty, so therefore we are done X * with this level of file X */ X X return; X } X X for(i = 0; i < lev; i++) X (void)printf(" "); X X /* X * See what type of critter this file is X */ X X if(lstat(buf, &stb) == -1){ X (void)printf(" ? %s - %s (%d)\n", buf, ERR); X return; X } X X switch(stb.st_mode & S_IFMT){ X case S_IFDIR: X X /* X * File is a directory, chdir to it X */ X X if(chdir(buf) == -1){ X (void)printf(" ? could not chdir into %s - %s (%d)\n", buf, ERR ); X return; X } X if(xflag && lastdev != stb.st_dev && lastdev != NODEV){ X /* Across mnt point */ X if(mflag) X (void)printf(" D %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" D %s\n", buf); X } X else { X if(mflag) X (void)printf(" d %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" d %s\n", buf); X } X lastdev = stb.st_dev; X X (void)fflush(stdout); X break; X X case S_IFLNK: X /* X * Sigh, another symlink. Read it's contents and X * call namei() X */ X X bzero(sym, BUFSIZ); X if(readlink(buf, sym, BUFSIZ) == -1){ X (void)printf(" ? problems reading symlink %s - %s (%d)\n", buf, ERR); X return; X } X X if(mflag) X (void)printf(" l %04o %s -> %s", stb.st_mode & 07777, buf, sym); X else X (void)printf(" l %s -> %s", buf, sym); X X if(symcount > 0 && symcount++ > MAXSYMLINKS){ X (void)printf(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***"); X symcount = -1; X } X (void)printf("\n"); X namei(sym, lev + 1); X break; X X case S_IFCHR: X if(mflag) X (void)printf(" c %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" c %s\n", buf); X break; X X case S_IFBLK: X if(mflag) X (void)printf(" b %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" b %s\n", buf); X break; X X case S_IFSOCK: X if(mflag) X (void)printf(" s %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" s %s\n", buf); X break; X X case S_IFREG: X if(mflag) X (void)printf(" - %04o %s\n", stb.st_mode & 07777, buf); X else X (void)printf(" - %s\n", buf); X break; X X default: X (void)fprintf(stderr,"namei: unknown file type 0%06o on file %s\n", stb.st_mode, buf ); X exit(1); X X } X } X} X END_OF_namei.c if test 5724 -ne `wc -c <namei.c`; then echo shar: \"namei.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 1 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- -Roger (rogers@fangorn.wr.tek.com) UUCP: ...!uunet!tektronix!fangorn.wr.tek.com!rogers ARPA: <rogers%fangorn.wr.tek.com@RELAY.CS.NET> exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.