vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vdu.c (7966B)


      1 // $Id$    --*- c -*--
      2 
      3 // Copyright (C) 2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 //  
      5 // This program is free software; you can redistribute it and/or modify
      6 // it under the terms of the GNU General Public License as published by
      7 // the Free Software Foundation; version 2 of the License.
      8 //  
      9 // This program is distributed in the hope that it will be useful,
     10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 // GNU General Public License for more details.
     13 //  
     14 // You should have received a copy of the GNU General Public License
     15 // along with this program; if not, write to the Free Software
     16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     17 
     18 
     19 #ifdef HAVE_CONFIG_H
     20 #  include <config.h>
     21 #endif
     22 
     23 #include "util.h"
     24 #include <lib/vserver.h>
     25 #include <lib/fmt.h>
     26 
     27 #include <stdlib.h>
     28 #include <getopt.h>
     29 #include <stdint.h>
     30 #include <errno.h>
     31 #include <sys/stat.h>
     32 #include <dirent.h>
     33 #include <fcntl.h>
     34 
     35 #define ENSC_WRAPPERS_PREFIX	"vdu: "
     36 #define ENSC_WRAPPERS_VSERVER	1
     37 #define ENSC_WRAPPERS_UNISTD	1
     38 #define ENSC_WRAPPERS_DIRENT	1
     39 #define ENSC_WRAPPERS_FCNTL	1
     40 #define ENSC_WRAPPERS_STAT	1
     41 #include <wrappers.h>
     42 
     43 #define CMD_HELP		0x1000
     44 #define CMD_VERSION		0x1001
     45 #define CMD_XID			0x2000
     46 #define CMD_SPACE		0x2001
     47 #define CMD_INODES		0x2002
     48 #define CMD_SCRIPT		0x2003
     49 #define CMD_BLOCKSIZE		0x2005
     50 
     51 int			wrapper_exit_code = 1;
     52 
     53 struct option const
     54 CMDLINE_OPTIONS[] = {
     55   { "help",           no_argument,       0, CMD_HELP },
     56   { "version",        no_argument,       0, CMD_VERSION },
     57   { "xid",            required_argument, 0, CMD_XID },
     58   { "space",          no_argument,       0, CMD_SPACE },
     59   { "inodes",         no_argument,       0, CMD_INODES },
     60   { "script",         no_argument,       0, CMD_SCRIPT },
     61   { "blocksize",      required_argument, 0, CMD_BLOCKSIZE },
     62   {0,0,0,0}
     63 };
     64 
     65 struct Arguments {
     66     xid_t		xid;
     67     bool		space;
     68     bool		inodes;
     69     bool		script;
     70     unsigned long	blocksize;
     71 };
     72 
     73 struct Result {
     74     uint_least64_t	blocks;
     75     uint_least64_t	inodes;
     76 };
     77 
     78 struct TraversalParams {
     79     struct Arguments const * const	args;
     80     struct Result * const		result;
     81 };
     82 
     83 static void
     84 showHelp(int fd, char const *cmd, int res)
     85 {
     86   WRITE_MSG(fd, "Usage:\n    ");
     87   WRITE_STR(fd, cmd);
     88   WRITE_MSG(fd,
     89 	    " --xid <xid> (--space|--inodes) [--blocksize <blocksize>] [--script] <directory>*\n"
     90 	    "\n"
     91 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
     92 
     93   exit(res);
     94 }
     95 
     96 static void
     97 showVersion()
     98 {
     99   WRITE_MSG(1,
    100 	    "vdu " VERSION " -- calculates the size of a directory\n"
    101 	    "This program is part of " PACKAGE_STRING "\n\n"
    102 	    "Copyright (C) 2006 Enrico Scholz\n"
    103 	    VERSION_COPYRIGHT_DISCLAIMER);
    104   exit(0);
    105 }
    106 
    107 /* basic hash table implementation for inode tracking */
    108 #define HASH_SIZE 103
    109 typedef struct hash_entry {
    110   struct hash_entry *next;
    111   ino_t inode;
    112 } hash_entry;
    113 
    114 typedef struct hash_table {
    115   hash_entry *entries[HASH_SIZE];
    116 } hash_table;
    117 
    118 static hash_table ht;
    119 
    120 static void
    121 hash_init(void)
    122 {
    123   memset(&ht, 0, sizeof(hash_table));
    124 }
    125 
    126 static void
    127 hash_free(void)
    128 {
    129   int i;
    130   hash_entry *e, *p;
    131   for (i = 0; i < HASH_SIZE; i++) {
    132     for (e = ht.entries[i], p = NULL; e; e = e->next) {
    133       free(p);
    134       p = e;
    135     }
    136     free(p);
    137   }
    138 }
    139 
    140 static int
    141 hash_insert(ino_t inode)
    142 {
    143   hash_entry *e, *p;
    144   unsigned int hashval = inode % HASH_SIZE;
    145 
    146   /* no one else here */
    147   if (ht.entries[hashval] == NULL) {
    148     ht.entries[hashval]        = malloc(sizeof(hash_entry));
    149     ht.entries[hashval]->next  = NULL;
    150     ht.entries[hashval]->inode = inode;
    151     return 0;
    152   }
    153 
    154   for (e = ht.entries[hashval], p = NULL; e; e = e->next) {
    155     /* already in the hash table */
    156     if (e->inode == inode)
    157       return -1;
    158     else if (e->inode > inode) {
    159       /* we're first */
    160       if (p == NULL) {
    161 	ht.entries[hashval]        = malloc(sizeof(hash_entry));
    162 	ht.entries[hashval]->next  = e;
    163 	ht.entries[hashval]->inode = inode;
    164       }
    165       /* we're in the middle */
    166       else {
    167 	p->next        = malloc(sizeof(hash_entry));
    168 	p->next->next  = e;
    169 	p->next->inode = inode;
    170       }
    171       return 0;
    172     }
    173     p = e;
    174   }
    175   /* we're last */
    176   p->next        = malloc(sizeof(hash_entry));
    177   p->next->next  = NULL;
    178   p->next->inode = inode;
    179 
    180   return 0;
    181 }
    182 
    183 static void
    184 visitDirEntry(char const *name, dev_t const dir_dev,
    185 	      struct TraversalParams *params);
    186 
    187 static void
    188 visitDir(char const *name, struct stat const *expected_stat, struct TraversalParams *params)
    189 {
    190   int		fd = Eopen(".", O_RDONLY|O_DIRECTORY, 0);
    191   DIR *		dir;
    192 
    193   EsafeChdir(name, expected_stat);
    194 
    195   dir = Eopendir(".");
    196 
    197   for (;;) {
    198     struct dirent		*ent = Ereaddir(dir);
    199     if (ent==0) break;
    200 
    201     if (isDotfile(ent->d_name)) continue;
    202     visitDirEntry(ent->d_name, expected_stat->st_dev, params);
    203   }
    204 
    205   Eclosedir(dir);
    206 
    207   Efchdir(fd);
    208   Eclose(fd);
    209 }
    210 
    211 static void
    212 visitDirEntry(char const *name, dev_t const dir_dev,
    213 	      struct TraversalParams *params)
    214 {
    215   struct stat		st;
    216   xid_t			xid;
    217   
    218   ElstatD(name, &st);
    219 
    220   xid = vc_getfilecontext(name);
    221   if (xid == params->args->xid &&
    222       (st.st_nlink == 1 || hash_insert(st.st_ino) != -1)) {
    223     params->result->blocks += st.st_blocks;
    224     params->result->inodes += 1;
    225   }
    226 
    227   if (S_ISDIR(st.st_mode) && dir_dev == st.st_dev)
    228     visitDir(name, &st, params);
    229 }
    230 
    231 static void
    232 visitDirStart(char const *name, struct TraversalParams *params)
    233 {
    234   struct stat	st;
    235   int		fd = Eopen(".", O_RDONLY|O_DIRECTORY, 0);
    236 
    237   Estat(name, &st);
    238   Echdir(name);
    239 
    240   visitDirEntry(".", st.st_dev, params);
    241 
    242   Efchdir(fd);
    243   Eclose(fd);  
    244 }
    245 
    246 int main(int argc, char *argv[])
    247 {
    248   struct Arguments		args = {
    249     .xid       = VC_NOCTX,
    250     .space     = false,
    251     .inodes    = false,
    252     .script    = false,
    253     .blocksize = 1024,
    254   };
    255   
    256   while (1) {
    257     int		c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
    258     if (c==-1) break;
    259 
    260     switch (c) {
    261       case CMD_HELP	:  showHelp(1, argv[0], 0);
    262       case CMD_VERSION	:  showVersion();
    263       case CMD_XID	:  args.xid = Evc_xidopt2xid(optarg,true); break;
    264       case CMD_SPACE	:  args.space  = true;                     break;
    265       case CMD_INODES	:  args.inodes = true;                     break;
    266       case CMD_SCRIPT	:  args.script = true;                     break;
    267       case CMD_BLOCKSIZE:
    268 	if (!isNumberUnsigned(optarg, &args.blocksize, false)) {
    269 	  WRITE_MSG(2, "Invalid block size argument: '");
    270 	  WRITE_STR(2, optarg);
    271 	  WRITE_MSG(2, "'; try '--help' for more information\n");
    272 	  return EXIT_FAILURE;
    273 	}
    274 	break;
    275       default		:
    276 	WRITE_MSG(2, "Try '");
    277 	WRITE_STR(2, argv[0]);
    278 	WRITE_MSG(2, " --help' for more information.\n");
    279 	return 255;
    280 	break;
    281     }
    282   }
    283 
    284   if (args.xid==VC_NOCTX)
    285     WRITE_MSG(2, "No xid specified; try '--help' for more information\n");
    286   else if (!args.space && !args.inodes)
    287     WRITE_MSG(2, "Must specify --space or --inodes; try '--help' for more information\n");
    288   else if (optind==argc)
    289     WRITE_MSG(2, "No directory specified; try '--help' for more information\n");
    290   else {
    291     int		i;
    292     size_t	len;
    293     struct Result		result;
    294     struct TraversalParams	params   = {
    295       .args   = &args,
    296       .result = &result
    297     };
    298 
    299     for (i = optind; i < argc; i++) {
    300       uint_least64_t		size;
    301       char			buf[sizeof(size)*3 + 3];
    302       char const *		delim = "";
    303       
    304       result.blocks = 0;
    305       result.inodes = 0;
    306 
    307       hash_init();
    308       visitDirStart(argv[i], &params);
    309       hash_free();
    310 
    311       if (!args.script) {
    312 	WRITE_STR(1, argv[i]);
    313 	WRITE_MSG(1, " ");
    314       }
    315 
    316       if (args.space) {
    317 	len = utilvserver_fmt_uint64(buf, result.blocks*512 / args.blocksize);
    318 	if (*delim) WRITE_STR(1, delim);
    319 	Vwrite(1, buf, len);
    320 	delim = " ";
    321       }
    322       if (args.inodes) {
    323 	len = utilvserver_fmt_uint64(buf, result.inodes);
    324 	if (*delim) WRITE_STR(1, delim);
    325 	Vwrite(1, buf, len);
    326 	delim = " ";
    327       }	
    328       WRITE_MSG(1, "\n");
    329     }
    330     return EXIT_SUCCESS;
    331   }
    332 
    333   return EXIT_FAILURE;
    334 }