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