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

  1. /* frag.c - simple fragmentation checker
  2.             V1.0 by Werner Almesberger
  3.             V1.1 by Steffen Zahn, adding directory recursion
  4.             V1.2 by Rob Hooft, adding hole counts
  5.             V1.3 by Steffen Zahn, email: szahn%masterix@emndev.siemens.co.at
  6.                     14 Nov 93
  7.                     - ignore symlinks,
  8.                     - don't cross filesys borders
  9.                     - get filesystem block size at runtime
  10.         V1.4 by Michael Bischoff <mbi@mo.math.nat.tu-bs.de> to handle
  11.                 indirect blocks better, but only for ext2fs
  12.             (applied by faith@cs.unc.edu, Sat Feb  4 22:06:27 1995)
  13.  
  14.             TODO: - handle hard links
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <fcntl.h>
  20. #include <limits.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <dirent.h>
  24. #include <sys/stat.h>
  25. #include <sys/vfs.h>
  26. #include <linux/fs.h>                      /* for FIBMAP */
  27.  
  28. typedef struct StackElem {
  29.     struct StackElem *backref, *next;
  30.     char name[NAME_MAX];
  31.     char dir_seen;
  32.     char from_cmd_line;
  33. } StackElem;
  34.  
  35. StackElem *top = NULL;
  36.  
  37.  
  38. void discard( void )
  39. {
  40.     StackElem *se = top;
  41.     if( se == NULL )
  42.         return ;
  43.     top = se->next;
  44.     free(se);
  45. }
  46.  
  47. void push( StackElem * se )
  48. {
  49.     se -> next = top;
  50.     top = se;
  51. }
  52.  
  53. char *p2s( StackElem *se, char *path )
  54. {
  55.     char *s;
  56.     if( se->backref!=NULL ) {
  57.         path = p2s( se->backref, path );
  58.         if( path[-1]!='/' )
  59.             *path++ = '/';
  60.     }
  61.     s = se->name;
  62.     while( *s )
  63.         *path++ = *s++;
  64.     return path;
  65. }
  66.  
  67. char *path2str( StackElem *se, char *path )
  68. {
  69.     *(p2s( se, path ))=0;
  70.     return path;
  71. }
  72.               
  73. void *xmalloc( size_t size )
  74. {
  75.     void *p;
  76.     if( (p=malloc(size))==NULL ) {
  77.         fprintf(stderr,"\nvirtual memory exhausted.\n");
  78.         exit(1);
  79.     }
  80.     return p;
  81. }
  82.  
  83. int main(int argc,char **argv)
  84. {
  85.     int fd,last_phys_block,
  86.         fragments_in_file, blocks_in_file,
  87.         blocks,current_phys_block,
  88.         this_fragment, largest_fragment, i;
  89.     long sum_blocks=0, sum_frag_blocks=0, sum_files=0, sum_frag_files=0;
  90.     long num_hole=0, sum_hole=0, hole;
  91.     struct stat st;
  92.     struct statfs stfs;
  93.     StackElem *se, *se1;
  94.     char path[PATH_MAX], pathlink[PATH_MAX], *p;
  95.     DIR *dir;
  96.     struct dirent *de;
  97.     char silent_flag=0;
  98.     dev_t local_fs;
  99.     int block_size;
  100.     
  101.     if (argc < 2)
  102.     {
  103.         fprintf(stderr,"usage: %s [-s [-s]] filename ...\n",argv[0]);
  104.         exit(1);
  105.     }
  106.     argc--; argv++;
  107.     while (argc>0)
  108.     {
  109.         p = *argv;
  110.         if( *p=='-' )
  111.             while( *++p )
  112.                 switch( *p )
  113.                 {
  114.                 case 's':
  115.                     silent_flag++; /* may be 1 or 2 */
  116.                     break;
  117.                 default:
  118.                     fprintf(stderr,"\nunknown flag %c\n", *p );
  119.                     exit(1);
  120.                 }
  121.         else
  122.         {
  123.             se = xmalloc( sizeof(StackElem) );
  124.             se->backref=NULL; se->dir_seen=0; se->from_cmd_line=1;
  125.             strcpy( se->name, p );
  126.             push(se);
  127.         }
  128.         argc--; argv++;
  129.     }
  130.     while ( top != NULL)
  131.     {
  132.         se = top;
  133.         if( se->dir_seen )
  134.             discard();
  135.         else
  136.         {
  137.             path2str( se, path );
  138.             if( readlink( path, pathlink, sizeof(pathlink) )>=0 )
  139.             {                   /* ignore symlinks */
  140.                 if(silent_flag<1)
  141.                 {
  142.                     printf("symlink %s\n", path );
  143.                 }
  144.                 discard();
  145.             }
  146.             else if( stat( path,&st) < 0)
  147.             {
  148.                 perror( path );
  149.                 discard();
  150.             }
  151.             else if( !se->from_cmd_line && (local_fs!=st.st_dev) )
  152.             {                   /* do not cross filesystem borders */
  153.                 if(silent_flag<2)
  154.                 {
  155.                     printf("different filesystem %s\n", path );
  156.                 }
  157.                 discard();
  158.             }
  159.             else
  160.             {
  161.                 if( se->from_cmd_line )
  162.                 {
  163.                     local_fs = st.st_dev;
  164.                     if ( statfs( path, &stfs )<0 )
  165.                     {
  166.                         perror( path );
  167.                         block_size = 1024;
  168.                     }
  169.                     else
  170.                         block_size = stfs.f_bsize;
  171.                 }
  172.                 if( S_ISREG(st.st_mode))   /* regular file */
  173.                 {
  174.                     if ( (fd = open( path ,O_RDONLY)) < 0 )
  175.                     {
  176.                         perror( path );
  177.                         discard();
  178.                     }
  179.                     else
  180.                     {
  181.                         last_phys_block = -1;
  182.                         fragments_in_file = 0;
  183.                         hole = 0; this_fragment=0;
  184.                         largest_fragment=0;
  185.                         blocks_in_file = (st.st_size+block_size-1)/block_size;
  186.                         for (blocks = 0; blocks < blocks_in_file; blocks++)
  187.                         {
  188.                             current_phys_block = blocks;
  189.                             if (ioctl(fd,FIBMAP,¤t_phys_block) < 0)
  190.                             {
  191.                                 perror(path);
  192.                                 break;
  193.                             }
  194.                             if (current_phys_block) { /* no hole here */
  195.                 int indirect;
  196.                 /* indirect is the number of indirection */
  197.                 /* blocks which must be skipped */
  198.                 indirect = 0;
  199.                 /* every 256 blocks there is an indirect block,
  200.                    the first of these is before block 12 */
  201.                 if (blocks >= 12 && (blocks-12) % 256 == 0)
  202.                     ++indirect;
  203.                 /* there is a block pointing to the indirect
  204.                    blocks every 64K blocks */
  205.                 if (blocks >= 256+12 && (blocks-256-12) % 65536 == 0)
  206.                     ++indirect;    /* 2nd indirect block */
  207.                 /* there is a single triple indirect block */
  208.                 if (blocks == 65536 + 256 + 12)
  209.                     ++indirect;
  210.                                 if (last_phys_block == current_phys_block-1-indirect)
  211.                                     this_fragment++;
  212.                 else { /* start of first or new fragment */
  213.                                     if( largest_fragment<this_fragment )
  214.                                         largest_fragment=this_fragment;
  215.                                     this_fragment=1;
  216.                                     fragments_in_file++;
  217.                                 }
  218.                                 last_phys_block = current_phys_block;
  219.                             }
  220.                             else
  221.                             {
  222.                                 hole++;
  223.                             }
  224.                         }
  225.                         if( largest_fragment<this_fragment )
  226.                             largest_fragment=this_fragment;
  227.                         blocks_in_file-=hole;
  228.                                 /* number of allocated blocks in file */
  229.                         if( !silent_flag )
  230.                         {
  231.                             if( fragments_in_file < 2
  232.                                 || blocks_in_file < 2 )
  233.                                 i = 0; /* fragmentation 0 % */
  234.                             else
  235.                                 i = (fragments_in_file - 1) * 100 /
  236.                                     (blocks_in_file-1);
  237.                                 /* maximum fragmentation 100%
  238.                                    means every block is an fragment */
  239.                             printf(" %3d%%  %s  (%d block(s), %d fragment(s), largest %d",
  240.                                    i, path, blocks_in_file,
  241.                                    fragments_in_file,largest_fragment);
  242.                             if (hole)
  243.                             {
  244.                                 printf(", %d hole(s))\n",hole);
  245.                             }
  246.                             else
  247.                             {
  248.                                 printf(")\n");
  249.                             }
  250.                         }
  251.                         sum_blocks+=blocks_in_file;
  252.                         if (hole)
  253.                             num_hole++;
  254.                         sum_hole+=hole;
  255.                         sum_files++;
  256.                         if( fragments_in_file>1 )
  257.                         {
  258.                             sum_frag_blocks+=blocks_in_file-largest_fragment;
  259.                             sum_frag_files++;
  260.                         }
  261.                         discard();
  262.                         close(fd);
  263.                     }
  264.                 }
  265.                 else if( S_ISDIR( st.st_mode ) ) /* push dir contents */
  266.                 {
  267.                     if( (dir=opendir( path ))==NULL )
  268.                     {
  269.                         perror(path);
  270.                         discard();
  271.                     }
  272.                     else
  273.                     {
  274.                         if( silent_flag<2 )
  275.                             printf("reading %s\n", path);
  276.                         while( (de=readdir(dir))!=NULL )
  277.                         {
  278.                             if( (strcmp(de->d_name,".")!=0)
  279.                                 && (strcmp(de->d_name,"..")!=0) )
  280.                             {
  281.                                 se1 = xmalloc( sizeof(StackElem) );
  282.                                 se1->backref=se; se1->dir_seen=0;
  283.                                 se1->from_cmd_line=0;
  284.                                 strcpy( se1->name, de->d_name );
  285.                                 push(se1);
  286.                             }
  287.                         }
  288.                         closedir( dir );
  289.                         se->dir_seen=1;
  290.                     }
  291.                 }
  292.                 else /* if( S_ISREG(st.st_mode)) */
  293.                     discard();
  294.             }
  295.         } /* if( se->dir_seen ) */
  296.     } /* while ( top != NULL) */
  297.     if (sum_files>1)
  298.     {
  299.         printf("\nsummary:\n");
  300.         printf(" %3ld%% file  fragmentation (%ld of %ld files contain fragments)\n",
  301.                sum_files<1 ? 0L : sum_frag_files*100/sum_files,
  302.                sum_frag_files, sum_files);
  303.         printf(" %3ld%% block fragmentation (%ld of %ld blocks are in fragments)\n",
  304.                sum_blocks<1 ? 0L : sum_frag_blocks*100/sum_blocks,
  305.                sum_frag_blocks, sum_blocks);
  306.         if (num_hole>1)
  307.             printf("  %ld files contain %ld blocks in holes\n",
  308.                    num_hole,sum_hole);
  309.     }
  310.     exit(0);
  311. }
  312.