* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: calcsize.c,v 1.36 2006/03/09 16:51:41 martinea Exp $
+ * $Id: calcsize.c,v 1.44 2006/07/25 18:27:56 martinea Exp $
*
* traverse directory tree to get backup size estimates
+ *
+ * argv[0] is the calcsize program name
+ * argv[1] is the config name or NOCONFIG
*/
#include "amanda.h"
-#include "statfs.h"
+#include "match.h"
+#include "conffile.h"
+#include "fsusage.h"
#include "sl.h"
+#include "util.h"
#define ROUND(n,x) ((x) + (n) - 1 - (((x) + (n) - 1) % (n)))
/*
-static unsigned long round_function(n, x)
-unsigned long n, x;
+static off_t
+round_function(n, x)
+ off_t n,
+ off_t x)
{
unsigned long remainder = x % n;
if (remainder)
- x += n-remainder;
+ x += n - remainder;
return x;
}
*/
-#define ST_BLOCKS(s) ((((s).st_blocks * 512) <= (s).st_size) ? (s).st_blocks+1 : ((s).st_size / 512 + (((s).st_size % 512) ? 1 : 0)))
+#define ST_BLOCKS(s) \
+ (((((off_t)(s).st_blocks * (off_t)512) <= (s).st_size)) ? \
+ ((off_t)(s).st_blocks + (off_t)1) : \
+ ((s).st_size / (off_t)512 + \
+ (off_t)((((s).st_size % (off_t)512) != (off_t)0) ? \
+ (off_t)1 : (off_t)0)))
#define FILETYPES (S_IFREG|S_IFLNK|S_IFDIR)
int max_inode;
int total_dirs;
int total_files;
- long total_size;
- long total_size_name;
+ off_t total_size;
+ off_t total_size_name;
} dumpstats[MAXDUMPS];
time_t dumpdate[MAXDUMPS];
int dumplevel[MAXDUMPS];
int ndumps;
-void (*add_file_name) P((int, char *));
-void (*add_file) P((int, struct stat *));
-long (*final_size) P((int, char *));
+void (*add_file_name)(int, char *);
+void (*add_file)(int, struct stat *);
+off_t (*final_size)(int, char *);
+
+int main(int, char **);
+void traverse_dirs(char *, char *);
-int main P((int, char **));
-void traverse_dirs P((char *, char *));
+void add_file_name_dump(int, char *);
+void add_file_dump(int, struct stat *);
+off_t final_size_dump(int, char *);
-void add_file_name_dump P((int, char *));
-void add_file_dump P((int, struct stat *));
-long final_size_dump P((int, char *));
+void add_file_name_star(int, char *);
+void add_file_star(int, struct stat *);
+off_t final_size_star(int, char *);
-void add_file_name_gnutar P((int, char *));
-void add_file_gnutar P((int, struct stat *));
-long final_size_gnutar P((int, char *));
+void add_file_name_gnutar(int, char *);
+void add_file_gnutar(int, struct stat *);
+off_t final_size_gnutar(int, char *);
-void add_file_name_unknown P((int, char *));
-void add_file_unknown P((int, struct stat *));
-long final_size_unknown P((int, char *));
+void add_file_name_unknown(int, char *);
+void add_file_unknown(int, struct stat *);
+off_t final_size_unknown(int, char *);
-sl_t *calc_load_file P((char *filename));
-int calc_check_exclude P((char *filename));
+sl_t *calc_load_file(char *filename);
+int calc_check_exclude(char *filename);
+int use_star_excl = 0;
int use_gtar_excl = 0;
sl_t *include_sl=NULL, *exclude_sl=NULL;
-int main(argc, argv)
-int argc;
-char **argv;
+int
+main(
+ int argc,
+ char ** argv)
{
#ifdef TEST
/* standalone test to ckeck wether the calculated file size is ok */
struct stat finfo;
int i;
- unsigned long dump_total=0, gtar_total=0;
+ off_t dump_total = (off_t)0;
+ off_t gtar_total = (off_t)0;
char *d;
int l, w;
+ /*
+ * Configure program for internationalization:
+ * 1) Only set the message locale for now.
+ * 2) Set textdomain for all amanda related programs to "amanda"
+ * We don't want to be forced to support dozens of message catalogs.
+ */
+ setlocale(LC_MESSAGES, "C");
+ textdomain("amanda");
+
safe_fd(-1, 0);
set_pname("calcsize");
+ dbopen(NULL);
+ config_init(CONFIG_INIT_CLIENT, NULL);
+
/* Don't die when child closes pipe */
signal(SIGPIPE, SIG_IGN);
if (argc < 2) {
- fprintf(stderr,"Usage: %s file[s]\n",argv[0]);
+ g_fprintf(stderr,_("Usage: %s file[s]\n"),argv[0]);
return 1;
}
for(i=1; i<argc; i++) {
if(lstat(argv[i], &finfo) == -1) {
- fprintf(stderr, "%s: %s\n", argv[i], strerror(errno));
+ g_fprintf(stderr, "%s: %s\n", argv[i], strerror(errno));
continue;
}
- printf("%s: st_size=%lu", argv[i],(unsigned long)finfo.st_size);
- printf(": blocks=%lu\n", (unsigned long)ST_BLOCKS(finfo));
- dump_total += (ST_BLOCKS(finfo) + 1)/2 + 1;
- gtar_total += ROUND(4,(ST_BLOCKS(finfo) + 1));
+ g_printf("%s: st_size=%lu", argv[i],(unsigned long)finfo.st_size);
+ g_printf(": blocks=%llu\n", ST_BLOCKS(finfo));
+ dump_total += (ST_BLOCKS(finfo) + (off_t)1) / (off_t)2 + (off_t)1;
+ gtar_total += ROUND(4,(ST_BLOCKS(finfo) + (off_t)1));
}
- printf(" gtar dump\n");
- printf("total %-9lu %-9lu\n",gtar_total,dump_total);
+ g_printf(" gtar dump\n");
+ g_printf("total %-9lu %-9lu\n",gtar_total,dump_total);
return 0;
#else
int i;
- char *dirname=NULL, *amname=NULL, *filename=NULL;
- unsigned long malloc_hist_1, malloc_size_1;
- unsigned long malloc_hist_2, malloc_size_2;
+ char *dirname=NULL;
+ char *amname=NULL, *qamname=NULL;
+ char *filename=NULL, *qfilename = NULL;
safe_fd(-1, 0);
safe_cd();
set_pname("calcsize");
- malloc_size_1 = malloc_inuse(&malloc_hist_1);
+ dbopen(DBG_SUBDIR_CLIENT);
+ config_init(CONFIG_INIT_CLIENT, NULL);
+ dbprintf(_("version %s\n"), VERSION);
-#if 0
- erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
+ /* drop root privileges; we'll regain them for the required operations */
+#ifdef WANT_SETUID_CLIENT
+ check_running_as(RUNNING_AS_CLIENT_LOGIN | RUNNING_AS_UID_ONLY);
+ if (!set_root_privs(0)) {
+ error(_("calcsize must be run setuid root"));
+ }
+#else
+ check_running_as(RUNNING_AS_CLIENT_LOGIN);
#endif
argc--, argv++; /* skip program name */
/* need at least program, amname, and directory name */
- if(argc < 3) {
- error("Usage: %s [DUMP|GNUTAR] name dir [-X exclude-file] [-I include-file] [level date]*",
+ if(argc < 4) {
+ error(_("Usage: %s config [DUMP|STAR|GNUTAR] name dir [-X exclude-file] [-I include-file] [level date]*"),
get_pname());
- return 1;
+ /*NOTREACHED*/
+ }
+
+ dbprintf(_("config: %s\n"), *argv);
+ if (strcmp(*argv, "NOCONFIG") != 0) {
+ dbrename(*argv, DBG_SUBDIR_CLIENT);
}
+ argc--;
+ argv++;
/* parse backup program name */
if(strcmp(*argv, "DUMP") == 0) {
#if !defined(DUMP) && !defined(XFSDUMP)
error("dump not available on this system");
- return 1;
+ /*NOTREACHED*/
#else
add_file_name = add_file_name_dump;
add_file = add_file_dump;
else if(strcmp(*argv, "GNUTAR") == 0) {
#ifndef GNUTAR
error("gnutar not available on this system");
- return 1;
+ /*NOTREACHED*/
#else
add_file_name = add_file_name_gnutar;
add_file = add_file_gnutar;
if (argc > 0) {
amname = *argv;
+ qamname = quote_string(amname);
argc--, argv++;
- } else
+ } else {
error("missing <name>");
+ /*NOTREACHED*/
+ }
/* the toplevel directory name to search from */
if (argc > 0) {
dirname = *argv;
argc--, argv++;
- } else
+ } else {
error("missing <dir>");
+ /*NOTREACHED*/
+ }
if ((argc > 1) && strcmp(*argv,"-X") == 0) {
argv++;
- if (!use_gtar_excl) {
+ if (!(use_gtar_excl || use_star_excl)) {
error("exclusion specification not supported");
- return 1;
+ /*NOTREACHED*/
}
filename = stralloc(*argv);
+ qfilename = quote_string(filename);
if (access(filename, R_OK) != 0) {
- fprintf(stderr,"Cannot open exclude file %s\n",filename);
- use_gtar_excl = 0;
+ g_fprintf(stderr,"Cannot open exclude file %s\n", qfilename);
+ use_gtar_excl = use_star_excl = 0;
} else {
- exclude_sl = calc_load_file(filename);
+ exclude_sl = calc_load_file(filename);
+ if (!exclude_sl) {
+ g_fprintf(stderr,"Cannot open exclude file %s: %s\n", qfilename,
+ strerror(errno));
+ use_gtar_excl = use_star_excl = 0;
+ }
}
+ amfree(qfilename);
amfree(filename);
argc -= 2;
argv++;
- } else
- use_gtar_excl = 0;
+ } else {
+ use_gtar_excl = use_star_excl = 0;
+ }
if ((argc > 1) && strcmp(*argv,"-I") == 0) {
argv++;
filename = stralloc(*argv);
+ qfilename = quote_string(filename);
if (access(filename, R_OK) != 0) {
- fprintf(stderr,"Cannot open include file %s\n",filename);
- use_gtar_excl = 0;
+ g_fprintf(stderr,"Cannot open include file %s\n", qfilename);
+ use_gtar_excl = use_star_excl = 0;
} else {
- include_sl = calc_load_file(filename);
+ include_sl = calc_load_file(filename);
+ if (!include_sl) {
+ g_fprintf(stderr,"Cannot open include file %s: %s\n", qfilename,
+ strerror(errno));
+ use_gtar_excl = use_star_excl = 0;
+ }
}
+ amfree(qfilename);
amfree(filename);
argc -= 2;
argv++;
}
}
- if(argc)
+ if(argc) {
error("leftover arg \"%s\", expected <level> and <date>", *argv);
+ /*NOTREACHED*/
+ }
if(is_empty_sl(include_sl)) {
traverse_dirs(dirname,".");
amflock(1, "size");
- lseek(1, (off_t)0, SEEK_END);
-
- fprintf(stderr, "%s %d SIZE %ld\n",
- amname, dumplevel[i], final_size(i, dirname));
- fflush(stdout);
+ dbprintf("calcsize: %s %d SIZE %lld\n",
+ qamname, dumplevel[i],
+ (long long)final_size(i, dirname));
+ g_fprintf(stderr, "%s %d SIZE %lld\n",
+ qamname, dumplevel[i],
+ (long long)final_size(i, dirname));
+ fflush(stderr);
amfunlock(1, "size");
}
-
- malloc_size_2 = malloc_inuse(&malloc_hist_2);
-
- if(malloc_size_1 != malloc_size_2) {
- malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
- }
+ amfree(qamname);
return 0;
#endif
*/
#if !defined(HAVE_BASENAME) && defined(BUILTIN_EXCLUDE_SUPPORT)
-static char *basename P((char *));
-static char *basename(file)
-char *file;
+static char *
+basename(
+ char * file)
{
char *cp;
}
#endif
-void push_name P((char *str));
-char *pop_name P((void));
+void push_name(char *str);
+char *pop_name(void);
-void traverse_dirs(parent_dir, include)
-char *parent_dir;
-char *include;
+void
+traverse_dirs(
+ char * parent_dir,
+ char * include)
{
DIR *d;
struct dirent *f;
struct stat finfo;
char *dirname, *newname = NULL;
char *newbase = NULL;
- dev_t parent_dev = 0;
+ dev_t parent_dev = (dev_t)0;
int i;
- int l;
- int parent_len;
- int has_exclude = !is_empty_sl(exclude_sl) && use_gtar_excl;
+ size_t l;
+ size_t parent_len;
+ int has_exclude;
+ char *aparent;
- if(parent_dir == NULL || include == NULL) return;
+ if(parent_dir == NULL || include == NULL)
+ return;
- char *aparent = vstralloc(parent_dir, "/", include, NULL);
+ has_exclude = !is_empty_sl(exclude_sl) && (use_gtar_excl || use_star_excl);
+ aparent = vstralloc(parent_dir, "/", include, NULL);
+ /* We (may) need root privs for the *stat() calls here. */
+ set_root_privs(1);
if(stat(parent_dir, &finfo) != -1)
parent_dev = finfo.st_dev;
push_name(aparent);
- for(dirname = pop_name(); dirname; free(dirname), dirname = pop_name()) {
+ for(; (dirname = pop_name()) != NULL; free(dirname)) {
if(has_exclude && calc_check_exclude(dirname+parent_len+1)) {
continue;
}
newname = newstralloc2(newname, newbase, f->d_name);
if(lstat(newname, &finfo) == -1) {
- fprintf(stderr, "%s/%s: %s\n",
+ g_fprintf(stderr, "%s/%s: %s\n",
dirname, f->d_name, strerror(errno));
continue;
}
int is_excluded = -1;
for(i = 0; i < ndumps; i++) {
add_file_name(i, newname);
- if(is_file && finfo.st_ctime >= dumpdate[i]) {
+ if(is_file && (time_t)finfo.st_ctime >= dumpdate[i]) {
if(has_exclude) {
if(is_excluded == -1)
perror(dirname);
#endif
}
+
+ /* drop root privs -- we're done with the permission-sensitive calls */
+ set_root_privs(0);
+
amfree(newbase);
amfree(newname);
amfree(aparent);
}
-void push_name(str)
-char *str;
+void
+push_name(
+ char * str)
{
Name *newp;
- newp = alloc(sizeof(*newp));
+ newp = alloc(SIZEOF(*newp));
newp->str = stralloc(str);
newp->next = name_stack;
name_stack = newp;
}
-char *pop_name()
+char *
+pop_name(void)
{
Name *newp = name_stack;
char *str;
* requirements for files with holes, nor the dumping of directories that
* are not themselves modified.
*/
-void add_file_name_dump(level, name)
-int level;
-char *name;
+void
+add_file_name_dump(
+ int level,
+ char * name)
{
+ (void)level; /* Quiet unused parameter warning */
+ (void)name; /* Quiet unused parameter warning */
+
return;
}
-void add_file_dump(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_dump(
+ int level,
+ struct stat * sp)
{
/* keep the size in kbytes, rounded up, plus a 1k header block */
if((sp->st_mode & S_IFMT) == S_IFREG || (sp->st_mode & S_IFMT) == S_IFDIR)
- dumpstats[level].total_size += (ST_BLOCKS(*sp) + 1)/2 + 1;
+ dumpstats[level].total_size +=
+ (ST_BLOCKS(*sp) + (off_t)1) / (off_t)2 + (off_t)1;
}
-long final_size_dump(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_dump(
+ int level,
+ char * topdir)
{
- generic_fs_stats_t stats;
- int mapsize;
+ struct fs_usage fsusage;
+ off_t mapsize;
char *s;
/* calculate the map sizes */
s = stralloc2(topdir, "/.");
- if(get_fs_stats(s, &stats) == -1) {
+ if(get_fs_usage(s, NULL, &fsusage) == -1) {
error("statfs %s: %s", s, strerror(errno));
+ /*NOTREACHED*/
}
amfree(s);
- mapsize = (stats.files + 7) / 8; /* in bytes */
- mapsize = (mapsize + 1023) / 1024; /* in kbytes */
+ mapsize = (fsusage.fsu_files + (off_t)7) / (off_t)8; /* in bytes */
+ mapsize = (mapsize + (off_t)1023) / (off_t)1024; /* in kbytes */
/* the dump contains three maps plus the files */
- return 3*mapsize + dumpstats[level].total_size;
+ return (mapsize * (off_t)3) + dumpstats[level].total_size;
}
/*
*
* As with DUMP, we only need a reasonable estimate, not an exact figure.
*/
-void add_file_name_gnutar(level, name)
-int level;
-char *name;
+void
+add_file_name_gnutar(
+ int level,
+ char * name)
{
-/* dumpstats[level].total_size_name += strlen(name) + 64;*/
- dumpstats[level].total_size += 1;
+ (void)name; /* Quiet unused parameter warning */
+
+/* dumpstats[level].total_size_name += strlen(name) + 64;*/
+ dumpstats[level].total_size += (off_t)1;
}
-void add_file_gnutar(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_gnutar(
+ int level,
+ struct stat * sp)
{
/* the header takes one additional block */
dumpstats[level].total_size += ST_BLOCKS(*sp);
}
-long final_size_gnutar(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_gnutar(
+ int level,
+ char * topdir)
{
+ (void)topdir; /* Quiet unused parameter warning */
+
/* divide by two to get kbytes, rounded up */
/* + 4 blocks for security */
- return (dumpstats[level].total_size + 5 + (dumpstats[level].total_size_name/512)) / 2;
+ return (dumpstats[level].total_size + (off_t)5 +
+ (dumpstats[level].total_size_name/(off_t)512)) / (off_t)2;
}
/*
* Here we'll just add up the file sizes and output that.
*/
-void add_file_name_unknown(level, name)
-int level;
-char *name;
+void
+add_file_name_unknown(
+ int level,
+ char * name)
{
+ (void)level; /* Quiet unused parameter warning */
+ (void)name; /* Quiet unused parameter warning */
+
return;
}
-void add_file_unknown(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_unknown(
+ int level,
+ struct stat * sp)
{
/* just add up the block counts */
if((sp->st_mode & S_IFMT) == S_IFREG || (sp->st_mode & S_IFMT) == S_IFDIR)
dumpstats[level].total_size += ST_BLOCKS(*sp);
}
-long final_size_unknown(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_unknown(
+ int level,
+ char * topdir)
{
+ (void)topdir; /* Quiet unused parameter warning */
+
/* divide by two to get kbytes, rounded up */
- return (dumpstats[level].total_size + 1) / 2;
+ return (dumpstats[level].total_size + (off_t)1) / (off_t)2;
}
/*
* =========================================================================
*/
-sl_t *calc_load_file(filename)
-char *filename;
+sl_t *
+calc_load_file(
+ char * filename)
{
char pattern[1025];
- sl_t *sl_list = new_sl();
+ sl_t *sl_list;
FILE *file = fopen(filename, "r");
+ if (!file) {
+ return NULL;
+ }
+
+ sl_list = new_sl();
+
while(fgets(pattern, 1025, file)) {
if(strlen(pattern)>0 && pattern[strlen(pattern)-1] == '\n')
pattern[strlen(pattern)-1] = '\0';
return sl_list;
}
-int calc_check_exclude(filename)
-char *filename;
+int
+calc_check_exclude(
+ char * filename)
{
sle_t *an_exclude;
if(is_empty_sl(exclude_sl)) return 0;