home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume15 / vtree / vtree.c < prev   
C/C++ Source or Header  |  1988-05-23  |  10KB  |  409 lines

  1. /* vtree
  2.   
  3.    +=======================================+
  4.    | This program is in the public domain. |
  5.    +=======================================+
  6.   
  7.    This program shows the directory structure of a filesystem or 
  8.    part of one.  It also shows the amount of space taken up by files
  9.    in each subdirectory. 
  10.   
  11.    Call via
  12.   
  13.     vtree fn1 fn2 fn3 ...
  14.   
  15.    If any of the given filenames is a directory (the usual case),
  16.    vtree will recursively descend into it, and the output line will
  17.    reflect the accumulated totals for all files in the directory.
  18.    
  19.    This program is based upon "agef" written by David S. Hayes at the 
  20.    Army Artificial Intelligence Center at the Pentagon.
  21.    
  22.    This program is dependent upon the new directory routines written by
  23.    Douglas A. Gwyn at the US Army Ballistic Research Laboratory at the
  24.    Aberdeen Proving Ground in Maryland.
  25. */
  26.  
  27. #include "patchlevel.h"
  28.  
  29. #include <ctype.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <sys/param.h>
  33. #include <stdio.h>
  34.  
  35. #include "customize.h"
  36. #include "hash.h"
  37.  
  38. #define SAME        0    /* for strcmp */
  39. #define BLOCKSIZE    512    /* size of a disk block */
  40.  
  41. #define K(x)        ((x + 1023)/1024)    /* convert stat(2) blocks into
  42.                      * k's.  On my machine, a block
  43.                      * is 512 bytes. */
  44.  
  45. #define    TRUE    1
  46. #define    FALSE    0
  47. #define    V_CHAR    "|"    /*    Vertical character    */
  48. #define    H_CHAR    "-"    /*    Horizontal character    */
  49. #define    A_CHAR    ">"    /*    Arrow char        */
  50. #define    T_CHAR    "+"    /*    Tee char        */
  51. #define    L_CHAR    "\\"    /*    L char, bottom of a branch    */
  52.  
  53. #define    MAX_COL_WIDTH    15
  54. #define    MAX_V_DEPTH    256        /* max depth for visual display */
  55.  
  56. int        indent = 0,        /* current indent */
  57.         depth = 9999,        /* max depth */
  58.         cur_depth = 0,    
  59.         sum = FALSE,        /* sum the subdirectories */
  60.         dup = FALSE,        /* use duplicate inodes */
  61.         cnt_inodes = FALSE,    /* count inodes */
  62.         quick = FALSE;        /* quick display */
  63.         visual = FALSE;        /* visual display */
  64.         version = 0;        /* = 1 display version, = 2 show options */
  65.         sub_dirs[MAX_V_DEPTH];
  66.  
  67. struct    stat    stb;            /* Normally not a good idea, but */
  68.                     /* this structure is used through- */
  69.                     /* out the program           */
  70.  
  71. extern char    *optarg;            /* from getopt(3) */
  72. extern int      optind,
  73.                 opterr;
  74.  
  75.  
  76. char           *Program;        /* our name */
  77. short           sw_follow_links = 1;    /* follow symbolic links */
  78. short           sw_summary;        /* print Grand Total line */
  79.  
  80. int             total_inodes, inodes;    /* inode count */
  81. long            total_sizes, sizes;    /* block count */
  82.  
  83. char            topdir[NAMELEN];    /* our starting directory */
  84.  
  85.  
  86.  /*
  87.   * We ran into a subdirectory.  Go down into it, and read everything
  88.   * in there. 
  89.   */
  90. int    indented = FALSE;    /* These had to be global since they */
  91. int    last_indent = 0;    /* determine what gets displayed during */
  92.                 /* the visual display */
  93.  
  94. down(subdir)
  95. char    *subdir;
  96. {
  97. OPEN    *dp;            /* stream from a directory */
  98. OPEN    *opendir ();
  99. char    cwd[NAMELEN];
  100. READ    *file;            /* directory entry */
  101. READ    *readdir ();
  102. int    i;
  103. struct    stat    stb;
  104.  
  105.     if ( (cur_depth == depth) && (!sum) )
  106.         return;
  107.  
  108. /* display the tree */
  109.  
  110.     if (cur_depth < depth) {
  111.         if (visual) {
  112.             if (!indented) {
  113.                 for (i = 1; i <cur_depth; i++) {
  114.                     if (sub_dirs[i]) {
  115.                         printf("%*s%s   ",MAX_COL_WIDTH-4," ",V_CHAR);
  116.                     }
  117.                     else printf("%*s   ",MAX_COL_WIDTH-3," ");
  118.                 }
  119.                 if (cur_depth>0) {
  120.                     if (sub_dirs[cur_depth] == 0) {
  121.                         printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",L_CHAR,H_CHAR,A_CHAR);
  122.                     }
  123.                     else printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",T_CHAR,H_CHAR,A_CHAR);
  124.                 }
  125.             } else {
  126.                 for (i = 1; i<MAX_COL_WIDTH-last_indent-3; i++)
  127.                     printf("%s",H_CHAR);
  128.                 printf("%s%s%s ",T_CHAR,H_CHAR,A_CHAR);
  129.             }
  130.  
  131. /* This will only happen on the first entry into this routine */
  132.  
  133.             if (strlen(subdir) > MAX_COL_WIDTH - 4) {
  134.                 printf("%s\n",subdir);
  135.                 printf("%s ",&subdir[strlen(subdir)-MAX_COL_WIDTH+5]);
  136.                 last_indent = MAX_COL_WIDTH - 4;
  137.             }
  138.             else {
  139.                 printf("%s ",subdir);
  140.                 last_indent = strlen(subdir)+1;
  141.             }
  142.             indented = TRUE;
  143.         }
  144.         else printf("%*s%s",indent," ",subdir);
  145.     }
  146.  
  147. /* open subdirectory */
  148.  
  149.     if ((dp = opendir(subdir)) == NULL) {
  150.         printf(" - can't read %s\n", subdir);
  151.         indented = FALSE;
  152.         return;
  153.     }
  154.  
  155.     cur_depth++;
  156.     indent+=3;
  157.  
  158.     getcwd(cwd, sizeof(cwd));        /* remember where we are */
  159.     chdir(subdir);                /* go into subdir */
  160.     if ( (!quick) && (!visual) ) {
  161.  
  162. /* accumulate total sizes and inodes in current directory */
  163.  
  164.         for (file = readdir(dp); file != NULL; file = readdir(dp))
  165.             if (strcmp(NAME(*file), "..") != SAME) 
  166.                 get_data(NAME(*file),FALSE);
  167.  
  168.         if (cur_depth<depth) {
  169.             if (cnt_inodes) printf("   %d",inodes);
  170.             printf(" : %ld\n",sizes);
  171.             total_sizes += sizes;
  172.             total_inodes += inodes;
  173.             sizes = 0;
  174.             inodes = 0;
  175.         }
  176.         rewinddir(dp);
  177.     } else if (!visual) printf("\n");
  178.  
  179.     if (visual) {
  180.  
  181. /* count subdirectories */
  182.  
  183.         for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  184.             if ( (strcmp(NAME(*file), "..") != SAME) &&
  185.                  (strcmp(NAME(*file), ".") != SAME) ) {
  186.                 if (chk_4_dir(NAME(*file))) {
  187.                     sub_dirs[cur_depth]++;
  188.                 }
  189.             }
  190.         }
  191.         rewinddir(dp);
  192.     }
  193.     
  194. /* go down into the subdirectory */
  195.  
  196.     for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  197.         if ( (strcmp(NAME(*file), "..") != SAME) &&
  198.              (strcmp(NAME(*file), ".") != SAME) ) {
  199.             if (chk_4_dir(NAME(*file))) 
  200.                 sub_dirs[cur_depth]--;
  201.             get_data(NAME(*file),TRUE);
  202.              }
  203.     }
  204.  
  205.     if ( (!quick) && (!visual) ) {
  206.  
  207. /* print totals */
  208.  
  209.         if (cur_depth == depth) {
  210.             if (cnt_inodes) printf("   %d",inodes);
  211.             printf(" : %ld\n",sizes);
  212.             total_sizes += sizes;
  213.             total_inodes += inodes;
  214.             sizes = 0;
  215.             inodes = 0;
  216.         }
  217.     } else if (visual && indented) {
  218.         printf("\n");
  219.         indented = FALSE;
  220.     }
  221.  
  222.     indent-=3;
  223.     sub_dirs[cur_depth] = 0;
  224.     cur_depth--;
  225.  
  226.     chdir(cwd);            /* go back where we were */
  227.     closedir(dp);            /* shut down the directory */
  228. } /* down */
  229.  
  230.  
  231.  
  232. int    chk_4_dir(path)
  233. char    *path;
  234. {
  235.     if (is_directory(path)) return TRUE;
  236.     else return FALSE;
  237.         
  238. } /* chk_4_dir */
  239.  
  240.  
  241.  
  242. /* Is the specified path a directory ? */
  243.  
  244. int    is_directory(path)
  245. char           *path;
  246. {
  247.  
  248. #ifdef LSTAT
  249.     if (sw_follow_links)
  250.         stat(path, &stb);    /* follows symbolic links */
  251.     else
  252.         lstat(path, &stb);    /* doesn't follow symbolic links */
  253. #else
  254.     stat(path, &stb);
  255. #endif
  256.  
  257.     if ((stb.st_mode & S_IFMT) == S_IFDIR)
  258.         return TRUE;
  259.     else return FALSE;
  260. } /* is_directory */
  261.  
  262.  
  263.  
  264.  /*
  265.   * Get the aged data on a file whose name is given.  If the file is a
  266.   * directory, go down into it, and get the data from all files inside. 
  267.   */
  268.  
  269. get_data(path,cont)
  270. char           *path;
  271. int        cont;    
  272. {
  273. /* struct    stat    stb; */
  274. int        i;
  275.  
  276.     if (cont) { 
  277.         if (is_directory(path)) 
  278.             down(path);
  279.     }
  280.     else {
  281.         if (is_directory(path)) return;
  282.  
  283.             /* Don't do it again if we've already done it once. */
  284.  
  285.         if ( (h_enter(stb.st_dev, stb.st_ino) == OLD) && (!dup) )
  286.             return;
  287.         inodes++;
  288.         sizes+= K(stb.st_size);
  289.     }
  290. } /* get_data */
  291.  
  292.  
  293.  
  294. main(argc, argv)
  295. int    argc;
  296. char    *argv[];
  297. {
  298. int    i,
  299.     j,
  300.     err = FALSE;
  301. int    option;
  302. int    user_file_list_supplied = 0;
  303.  
  304.     Program = *argv;        /* save our name for error messages */
  305.  
  306.     /* Pick up options from command line */
  307.  
  308.     while ((option = getopt(argc, argv, "dh:istqvV")) != EOF) {
  309.         switch (option) {
  310.             case 'h':    depth = atoi(optarg);
  311.                     while (*optarg) {
  312.                         if (!isdigit(*optarg)) {
  313.                             err = TRUE;
  314.                             break;
  315.                         }
  316.                         optarg++;
  317.                     }
  318.                     break;
  319.             case 'd':    dup = TRUE;
  320.                     break;    
  321.             case 'i':    cnt_inodes = TRUE;
  322.                     break;        
  323.             case 's':    sum = TRUE;
  324.                     break;
  325.             case 't':    sw_summary = TRUE;
  326.                     break;
  327.             case 'q':    quick = TRUE;
  328.                     dup = FALSE;
  329.                     sum = FALSE;
  330.                     cnt_inodes = FALSE;
  331.                     break;
  332.             case 'v':    visual = TRUE;
  333.                     break;
  334.             case 'V':    version++;
  335.                     break;
  336.             default:    err = TRUE;
  337.         }
  338.         if (err) {
  339.             fprintf(stderr,"%s: [ -d ] [ -h # ] [ -i ] [ -s ] [ -q ] [ -v ] [ -V ]\n",Program);
  340.             fprintf(stderr,"    -d    count duplicate inodes\n");
  341.             fprintf(stderr,"    -h #    height of tree to look at\n");
  342.             fprintf(stderr,"    -i    count inodes\n");
  343.             fprintf(stderr,"    -s    include subdirectories not shown due to -h option\n");
  344.             fprintf(stderr,"    -t    totals at the end\n");
  345.             fprintf(stderr,"    -q    quick display, no counts\n");
  346.             fprintf(stderr,"    -v    visual display\n");
  347.             fprintf(stderr,"    -V    show current version\n");
  348.             fprintf(stderr,"        (2 Vs shows specified options)\n");
  349.             exit(-1);
  350.         }
  351.     
  352.     }
  353.  
  354.     if (version > 0 ) {
  355.         printf("%s",VERSION);
  356.         if (version>1) {
  357.             printf("Tree height:    %d\n",depth);
  358.             if (dup) printf("Include duplicate inodes\n");
  359.             if (cnt_inodes) printf("Count inodes\n");
  360.             if (sum) printf("Include unseen subdirectories in totals\n");
  361.             if (sw_summary) printf("Print totals at end\n");
  362.             if (quick) printf("Quick display only\n");
  363.             if (visual) printf("Visual tree\n");
  364.         }
  365.     }
  366.     
  367.     /* If user didn't specify targets, inspect current directory. */
  368.  
  369.     if (optind >= argc) {
  370.         user_file_list_supplied = 0;
  371.     } else {
  372.         user_file_list_supplied = 1;
  373.     }
  374.  
  375.     getcwd(topdir, sizeof (topdir));        /* find out where we are */
  376.  
  377.     /* Zero out grand totals */
  378.     total_inodes = total_sizes = 0;
  379.     /* Zero out sub_dirs */
  380.     for (i=0; i<=MAX_V_DEPTH; i++) {
  381.         sub_dirs[i] = 0;
  382.     }
  383.         
  384.     /* Inspect each argument */
  385.     for (i = optind; i < argc || (!user_file_list_supplied && i == argc); i++) {
  386.         cur_depth = inodes = sizes = 0;
  387.  
  388.         chdir(topdir);        /* be sure to start from the same place */
  389.         get_data(user_file_list_supplied?argv[i] : topdir, TRUE);/* this may change our cwd */
  390.  
  391.         total_inodes += inodes;
  392.         total_sizes += sizes;
  393.     }
  394.  
  395.     if (sw_summary) {
  396.         printf("\n\nTotal space used: %ld\n",total_sizes);
  397.         if (cnt_inodes) printf("Total inodes: %d\n",inodes);
  398.     }
  399.     
  400. #ifdef HSTATS
  401.     fflush(stdout);
  402.     h_stats();
  403. #endif
  404.  
  405.     exit(0);
  406. } /* main */
  407.  
  408.  
  409.