236 lines
5.9 KiB
C
236 lines
5.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2000-2002 Silicon Graphics, Inc.
|
|
* All Rights Reserved.
|
|
*/
|
|
|
|
/*
|
|
* Estimate space of an XFS filesystem
|
|
*
|
|
* XXX: assumes dirv1 format.
|
|
*/
|
|
#include "libxfs.h"
|
|
#include <sys/stat.h>
|
|
#include <ftw.h>
|
|
|
|
static unsigned long long
|
|
cvtnum(char *s)
|
|
{
|
|
unsigned long long i;
|
|
char *sp;
|
|
|
|
i = strtoll(s, &sp, 0);
|
|
if (i == 0 && sp == s)
|
|
return 0LL;
|
|
if (*sp == '\0')
|
|
return i;
|
|
if (*sp =='k' && sp[1] == '\0')
|
|
return 1024LL * i;
|
|
if (*sp =='m' && sp[1] == '\0')
|
|
return 1024LL * 1024LL * i;
|
|
if (*sp =='g' && sp[1] == '\0')
|
|
return 1024LL * 1024LL * 1024LL * i;
|
|
return 0LL;
|
|
}
|
|
|
|
int ffn(const char *, const struct stat *, int, struct FTW *);
|
|
|
|
#define BLOCKSIZE 4096
|
|
#define INODESIZE 256
|
|
#define PERDIRENTRY \
|
|
(sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_data_entry_t))
|
|
#define LOGSIZE 1000
|
|
|
|
#define FBLOCKS(n) ((n)/blocksize)
|
|
|
|
static unsigned long long dirsize=0; /* bytes */
|
|
static unsigned long long logsize=LOGSIZE*BLOCKSIZE; /* bytes */
|
|
static unsigned long long fullblocks=0; /* FS blocks */
|
|
static unsigned long long isize=0; /* inodes bytes */
|
|
static unsigned long long blocksize=BLOCKSIZE;
|
|
static unsigned long long nslinks=0; /* number of symbolic links */
|
|
static unsigned long long nfiles=0; /* number of regular files */
|
|
static unsigned long long ndirs=0; /* number of directories */
|
|
static unsigned long long nspecial=0; /* number of special files */
|
|
static unsigned long long verbose=0; /* verbose mode TRUE/FALSE */
|
|
|
|
static int __debug = 0;
|
|
static int ilog = 0;
|
|
static int elog = 0;
|
|
|
|
static void
|
|
usage(char *progname)
|
|
{
|
|
fprintf(stderr,
|
|
_("Usage: %s [opts] directory [directory ...]\n"
|
|
"\t-b blocksize (fundamental filesystem blocksize)\n"
|
|
"\t-i logsize (internal log size)\n"
|
|
"\t-e logsize (external log size)\n"
|
|
"\t-v prints more verbose messages\n"
|
|
"\t-V prints version and exits\n"
|
|
"\t-h prints this usage message\n\n"
|
|
"Note:\tblocksize may have 'k' appended to indicate x1024\n"
|
|
"\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n"),
|
|
basename(progname));
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
unsigned long long est;
|
|
extern int optind;
|
|
extern char *optarg;
|
|
char dname[40];
|
|
int c;
|
|
|
|
setlocale(LC_ALL, "");
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
textdomain(PACKAGE);
|
|
|
|
while ((c = getopt (argc, argv, "b:hdve:i:V")) != EOF) {
|
|
switch (c) {
|
|
case 'b':
|
|
blocksize=cvtnum(optarg);
|
|
if (blocksize <= 0LL) {
|
|
fprintf(stderr, _("blocksize %llu too small\n"),
|
|
blocksize);
|
|
usage(argv[0]);
|
|
}
|
|
else if (blocksize > 64LL * 1024LL) {
|
|
fprintf(stderr, _("blocksize %llu too large\n"),
|
|
blocksize);
|
|
usage(argv[0]);
|
|
}
|
|
break;
|
|
case 'i':
|
|
if (elog) {
|
|
fprintf(stderr, _("already have external log "
|
|
"noted, can't have both\n"));
|
|
usage(argv[0]);
|
|
}
|
|
logsize=cvtnum(optarg);
|
|
ilog++;
|
|
break;
|
|
case 'e':
|
|
if (ilog) {
|
|
fprintf(stderr, _("already have internal log "
|
|
"noted, can't have both\n"));
|
|
usage(argv[0]);
|
|
}
|
|
logsize=cvtnum(optarg);
|
|
elog++;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case 'd':
|
|
__debug++;
|
|
break;
|
|
case 'V':
|
|
printf(_("%s version %s\n"), basename(argv[0]), VERSION);
|
|
exit(0);
|
|
default:
|
|
case 'h':
|
|
usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
if (optind == argc)
|
|
usage(argv[0]);
|
|
|
|
if (!elog && !ilog) {
|
|
ilog=1;
|
|
logsize=LOGSIZE * blocksize;
|
|
}
|
|
if (verbose)
|
|
printf(_("directory bsize blocks megabytes logsize\n"));
|
|
|
|
for ( ; optind < argc; optind++) {
|
|
dirsize=0LL; /* bytes */
|
|
fullblocks=0LL; /* FS blocks */
|
|
isize=0LL; /* inodes bytes */
|
|
nslinks=0LL; /* number of symbolic links */
|
|
nfiles=0LL; /* number of regular files */
|
|
ndirs=0LL; /* number of directories */
|
|
nspecial=0LL; /* number of special files */
|
|
|
|
nftw(argv[optind], ffn, 40, FTW_PHYS | FTW_MOUNT);
|
|
|
|
if (__debug) {
|
|
printf(_("dirsize=%llu\n"), dirsize);
|
|
printf(_("fullblocks=%llu\n"), fullblocks);
|
|
printf(_("isize=%llu\n"), isize);
|
|
|
|
printf(_("%llu regular files\n"), nfiles);
|
|
printf(_("%llu symbolic links\n"), nslinks);
|
|
printf(_("%llu directories\n"), ndirs);
|
|
printf(_("%llu special files\n"), nspecial);
|
|
}
|
|
|
|
est = FBLOCKS(isize) + 8 /* blocks for inodes */
|
|
+ FBLOCKS(dirsize) + 1 /* blocks for directories */
|
|
+ fullblocks /* blocks for file contents */
|
|
+ (8 * 16) /* fudge for overhead blks (per ag) */
|
|
+ FBLOCKS(isize / INODESIZE); /* 1 byte/inode for map */
|
|
|
|
if (ilog)
|
|
est += (logsize / blocksize);
|
|
|
|
if (!verbose) {
|
|
printf(_("%s will take about %.1f megabytes\n"),
|
|
argv[optind],
|
|
(double)est*(double)blocksize/(1024.0*1024.0));
|
|
} else {
|
|
/* avoid running over 39 characters in field */
|
|
strncpy(dname, argv[optind], 40);
|
|
dname[39] = '\0';
|
|
printf(_("%-39s %5llu %8llu %10.1fMB %10llu\n"),
|
|
dname, blocksize, est,
|
|
(double)est*(double)blocksize/(1024.0*1024.0), logsize);
|
|
}
|
|
|
|
if (!verbose && elog) {
|
|
printf(_("\twith the external log using %llu blocks "),
|
|
logsize/blocksize);
|
|
printf(_("or about %.1f megabytes\n"),
|
|
(double)logsize/(1024.0*1024.0));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ffn(const char *path, const struct stat *stb, int flags, struct FTW *f)
|
|
{
|
|
/* cases are in most-encountered to least-encountered order */
|
|
dirsize+=PERDIRENTRY+strlen(path);
|
|
isize+=INODESIZE;
|
|
switch (S_IFMT & stb->st_mode) {
|
|
case S_IFREG: /* regular files */
|
|
fullblocks+=FBLOCKS(stb->st_blocks * 512 + blocksize-1);
|
|
if (stb->st_blocks * 512 < stb->st_size)
|
|
fullblocks++; /* add one bmap block here */
|
|
nfiles++;
|
|
break;
|
|
case S_IFLNK: /* symbolic links */
|
|
if (stb->st_size >= (INODESIZE - (sizeof(xfs_dinode_t)+4)))
|
|
fullblocks+=FBLOCKS(stb->st_size + blocksize-1);
|
|
nslinks++;
|
|
break;
|
|
case S_IFDIR: /* directories */
|
|
dirsize+=blocksize; /* fudge upwards */
|
|
if (stb->st_size >= blocksize)
|
|
dirsize+=blocksize;
|
|
ndirs++;
|
|
break;
|
|
case S_IFIFO: /* named pipes */
|
|
case S_IFCHR: /* Character Special device */
|
|
case S_IFBLK: /* Block Special device */
|
|
case S_IFSOCK: /* socket */
|
|
nspecial++;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|