home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / misc-utils / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  6.5 KB  |  342 lines

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