From 0f58e58cb96870182760a1161dd709b1b3f7fe6e Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 12 Aug 2002 21:07:38 +0000 Subject: [PATCH] New tools directory -- kes12Aug02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@90 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/Makefile.in | 2 +- bacula/autoconf/Make.common.in | 1 + bacula/autoconf/configure.in | 5 +- bacula/configure | 7 +- bacula/src/cats/Makefile.in | 2 +- bacula/src/dird/Makefile.in | 2 +- bacula/src/lib/Makefile.in | 9 +- bacula/src/stored/Makefile.in | 2 +- bacula/src/tools/dbcheck.c | 410 +++++++++++++++++++++++++++++++++ 9 files changed, 427 insertions(+), 13 deletions(-) create mode 100644 bacula/src/tools/dbcheck.c diff --git a/bacula/Makefile.in b/bacula/Makefile.in index 3f17dcc86d..6c3a64a7ac 100755 --- a/bacula/Makefile.in +++ b/bacula/Makefile.in @@ -17,7 +17,7 @@ dummy: subdirs = src doc src/lib src/findlib src/cats \ @READLINE_SRC@ src/console src/dird src/filed \ - src/stored @GNOME_DIR@ + src/stored @GNOME_DIR@ src/tools FDsubdirs = src/lib src/findlib src/filed diff --git a/bacula/autoconf/Make.common.in b/bacula/autoconf/Make.common.in index e2d86db61d..c4967df87c 100644 --- a/bacula/autoconf/Make.common.in +++ b/bacula/autoconf/Make.common.in @@ -61,6 +61,7 @@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ DINCLUDE = @DINCLUDE@ DLIB = @DLIB@ +DB_LIBS = @DB_LIBS@ # X Include directory #XINC = @X_CFLAGS@ @XPM_CFLAGS@ diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index d75ba911eb..00d71c2bfe 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -992,7 +992,7 @@ AC_DEFINE(FDLIBS) CFLAGS=${CFLAGS--O} LDFLAGS=${LDFLAGS--O} -LIBS="${LIBS} ${SQL_LFLAGS}" +DB_LIBS="${SQL_LFLAGS}" CPPFLAGS="$CPPFLAGS" AC_SUBST(DEBUG) @@ -1003,6 +1003,7 @@ AC_SUBST(LDFLAGS) AC_SUBST(X_CFLAGS) AC_SUBST(LIBS) AC_SUBST(DLIB) +AC_SUBST(DB_LIBS) AC_SUBST(X_LIBS) AC_SUBST(X_EXTRA_LIBS) @@ -1212,6 +1213,7 @@ AC_OUTPUT([autoconf/Make.common \ src/cats/make_bdb_tables \ src/cats/drop_bdb_tables \ src/findlib/Makefile \ + src/tools/Makefile \ $PFILES ], [(echo "Doing make of dependencies"; make depend;) ] ) @@ -1250,6 +1252,7 @@ Configuration on `date`: Libraries: ${LIBS} Database found: ${have_db} Database type: ${db_name} + Database lib: ${DB_LIBS} Job Output Email: ${job_email} Traceback Email: ${dump_email} diff --git a/bacula/configure b/bacula/configure index 9a66191f0d..3728d59fd0 100755 --- a/bacula/configure +++ b/bacula/configure @@ -8861,7 +8861,7 @@ EOF CFLAGS=${CFLAGS--O} LDFLAGS=${LDFLAGS--O} -LIBS="${LIBS} ${SQL_LFLAGS}" +DB_LIBS="${SQL_LFLAGS}" CPPFLAGS="$CPPFLAGS" @@ -8875,6 +8875,7 @@ CPPFLAGS="$CPPFLAGS" + OBJLIST= @@ -9186,6 +9187,7 @@ trap 'rm -fr `echo "autoconf/Make.common \ src/cats/make_bdb_tables \ src/cats/drop_bdb_tables \ src/findlib/Makefile \ + src/tools/Makefile \ $PFILES src/config.h:autoconf/config.h.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF @@ -9646,6 +9650,7 @@ Configuration on `date`: Libraries: ${LIBS} Database found: ${have_db} Database type: ${db_name} + Database lib: ${DB_LIBS} Job Output Email: ${job_email} Traceback Email: ${dump_email} diff --git a/bacula/src/cats/Makefile.in b/bacula/src/cats/Makefile.in index 3be938d7cf..19bf536120 100644 --- a/bacula/src/cats/Makefile.in +++ b/bacula/src/cats/Makefile.in @@ -48,7 +48,7 @@ libsql.a: $(LIBOBJS) $(RANLIB) $@ cats: $(SVROBJS) ../findlib/libfind.a - $(CC) $(LDFLAGS) -L../findlib -L../lib -o $@ $(SVROBJS) $(LIBS) $(DLIB) -lfind -lbac + $(CC) $(LDFLAGS) -L../findlib -L../lib -o $@ $(SVROBJS) $(LIBS) $(DB_LIBS) -lfind -lbac Makefile: $(srcdir)/Makefile.in $(topdir)/config.status cd $(topdir) \ diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index 8dcae47617..f1fbcf3597 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -66,7 +66,7 @@ all: Makefile bacula-dir bacula-dir: $(SVROBJS) ../lib/libbac.a ../cats/libsql.a $(CXX) $(LDFLAGS) -L../lib -L../cats -o $@ $(SVROBJS) \ - -lsql -lbac -lm $(LIBS) $(DLIB) + -lsql -lbac -lm $(LIBS) $(DLIB) $(DB_LIBS) Makefile: $(srcdir)/Makefile.in $(topdir)/config.status cd $(topdir) \ diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 62c6f4eec8..8abc0dcf98 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -83,7 +83,7 @@ EXTRAOBJS = @OBJLIST@ $(XDVI) -s 0 $< #------------------------------------------------------------------------- -all: Makefile libbac.a smtp +all: Makefile libbac.a @echo "==== Make of lib is good ====" @echo " " @@ -96,9 +96,6 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status cd $(topdir) \ && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -smtp: smtp.o - $(CXX) $(LDFLAGS) -L. -o $@ smtp.o $(LIBS) $(DLIB) -lbac -lm - rwlock_test: rwlock.o rm -f rwlock.o $(CXX) -DTEST_RWLOCK $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(GMP_INC) $(CFLAGS) rwlock.c @@ -107,14 +104,12 @@ rwlock_test: rwlock.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(GMP_INC) $(CFLAGS) rwlock.c install: - $(INSTALL_PROGRAM) smtp $(DESTDIR)/$(sbindir)/smtp uninstall: - (cd $(DESTDIR)$(sbindir); $(RMF) smtp) clean: $(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3 - $(RMF) smtp rwlock_test + $(RMF) rwlock_test realclean: clean $(RMF) tags diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 6dac0c8b7b..cdef7ac8be 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -84,7 +84,7 @@ bextract: ../findlib/libfind.a $(BEXTOBJS) ../lib/libbac.a $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ $(BEXTOBJS) $(LIBS) $(DLIB) $(FDLIBS) -lbac -lfind -lm bscan: ../findlib/libfind.a $(SCNOBJS) ../cats/libsql.a - $(CXX) $(LDFLAGS) -L../lib -L../cats -L../findlib -o $@ $(SCNOBJS) -lsql $(LIBS) $(DLIB) $(FDLIBS) -lbac -lfind -lm + $(CXX) $(LDFLAGS) -L../lib -L../cats -L../findlib -o $@ $(SCNOBJS) -lsql $(LIBS) $(DB_LIBS) $(FDLIBS) -lbac -lfind -lm diff --git a/bacula/src/tools/dbcheck.c b/bacula/src/tools/dbcheck.c new file mode 100644 index 0000000000..5c8496a3d2 --- /dev/null +++ b/bacula/src/tools/dbcheck.c @@ -0,0 +1,410 @@ +/* + * + * Program to check a Bacula database for consistency and to + * make repairs + * + * Kern E. Sibbald, August 2002 + * + * Version $Id$ + * + */ +/* + Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "cats/cats.h" + +typedef struct s_id_ctx { + uint32_t *Id; /* ids to be modified */ + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +} ID_LIST; + +typedef struct s_name_ctx { + char **name; /* list of names */ + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +} NAME_LIST; + + + +/* Global variables */ +static int fix = FALSE; +static int interactive = FALSE; +static int verbose = FALSE; +static B_DB *db; +static ID_LIST id_list; +static NAME_LIST name_list; +static char buf[2000]; + +#define MAX_ID_LIST_LEN 1000000 + +/* Forward referenced functions */ +static int make_id_list(char *query, ID_LIST *id_list); +static int delete_id_list(char *query, ID_LIST *id_list); +static int make_name_list(char *query, NAME_LIST *name_list); +static void print_name_list(NAME_LIST *name_list); +static void free_name_list(NAME_LIST *name_list); +static void eliminate_duplicate_filenames(); +static void eliminate_duplicate_paths(); +static void eliminate_orphaned_jobmedia_records(); +static void eliminate_orphaned_file_records(); + +#ifdef xxxx +static void prtit(void *ctx, char *msg) +{ + printf("%s", msg); +} +#endif + +static void usage() +{ + fprintf(stderr, +"Usage: dbcheck [-d debug_level] \n" +" -dnn set debug level to nn\n" +" -f fix inconsistencies\n" +" -i interactive mode\n" +" -? print this message\n\n"); + exit(1); +} + +int main (int argc, char *argv[]) +{ + int ch; + char *user, *password, *db_name; + + my_name_is(argc, argv, "dbcheck"); + init_msg(NULL, NULL); /* setup message handler */ + + memset(&id_list, 0, sizeof(id_list)); + memset(&name_list, 0, sizeof(name_list)); + + + while ((ch = getopt(argc, argv, "d:fi?")) != -1) { + switch (ch) { + case 'd': /* debug level */ + debug_level = atoi(optarg); + if (debug_level <= 0) + debug_level = 1; + break; + + case 'f': /* fix inconsistencies */ + fix = TRUE; + break; + + case 'i': /* interactive */ + interactive = TRUE; + break; + + case '?': + default: + usage(); + + } + } + argc -= optind; + argv += optind; + + if (argc > 4) { + Pmsg0(0, _("Wrong number of arguments.\n")); + usage(); + } + + if (argc < 1) { + Pmsg0(0, _("Working directory not supplied.\n")); + usage(); + } + + /* This is needed by SQLite to find the db */ + working_directory = argv[0]; + db_name = "bacula"; + user = db_name; + password = ""; + + if (argc == 2) { + db_name = argv[1]; + user = db_name; + } else if (argc == 3) { + db_name = argv[1]; + user = argv[2]; + } else if (argc == 4) { + db_name = argv[1]; + user = argv[2]; + password = argv[3]; + } + + /* Open database */ + db = db_init_database(db_name, user, password); + if (!db_open_database(db)) { + Emsg1(M_FATAL, 0, "%s", db_strerror(db)); + } + + eliminate_duplicate_filenames(); + + eliminate_duplicate_paths(); + + eliminate_orphaned_jobmedia_records(); + + eliminate_orphaned_file_records(); + + db_close_database(db); + + close_msg(NULL); + term_msg(); + return 0; +} + +/* + * Called here with each id to be added to the list + */ +static int id_list_handler(void *ctx, int num_fields, char **row) +{ + ID_LIST *lst = (ID_LIST *)ctx; + + if (lst->num_ids == MAX_ID_LIST_LEN) { + return 1; + } + if (lst->num_ids == lst->max_ids) { + if (lst->max_ids == 0) { + lst->max_ids = 1000; + lst->Id = (uint32_t *)malloc(sizeof(uint32_t) * lst->max_ids); + } else { + lst->max_ids = (lst->max_ids * 3) / 2; + lst->Id = (uint32_t *)brealloc(lst->Id, sizeof(uint32_t) * lst->max_ids); + } + } + lst->Id[lst->num_ids++] = (uint32_t)strtod(row[0], NULL); + return 0; +} + +/* + * Construct record id list + */ +static int make_id_list(char *query, ID_LIST *id_list) +{ + id_list->num_ids = 0; + id_list->num_del = 0; + id_list->tot_ids = 0; + + if (!db_sql_query(db, query, id_list_handler, (void *)id_list)) { + printf("%s", db_strerror(db)); + return 0; + } + return 1; +} + +/* + * Delete all entries in the list + */ +static int delete_id_list(char *query, ID_LIST *id_list) +{ + int i; + + for (i=0; i < id_list->num_ids; i++) { + sprintf(buf, query, id_list->Id[i]); + db_sql_query(db, buf, NULL, NULL); + } + return 1; +} + +/* + * Called here with each name to be added to the list + */ +static int name_list_handler(void *ctx, int num_fields, char **row) +{ + NAME_LIST *name = (NAME_LIST *)ctx; + + if (name->num_ids == MAX_ID_LIST_LEN) { + return 1; + } + if (name->num_ids == name->max_ids) { + if (name->max_ids == 0) { + name->max_ids = 1000; + name->name = (char **)malloc(sizeof(char *) * name->max_ids); + } else { + name->max_ids = (name->max_ids * 3) / 2; + name->name = (char **)brealloc(name->name, sizeof(char *) * name->max_ids); + } + } + name->name[name->num_ids++] = bstrdup(row[0]); + return 0; +} + + +/* + * Construct name list + */ +static int make_name_list(char *query, NAME_LIST *name_list) +{ + name_list->num_ids = 0; + name_list->num_del = 0; + name_list->tot_ids = 0; + + if (!db_sql_query(db, query, name_list_handler, (void *)name_list)) { + printf("%s", db_strerror(db)); + return 0; + } + return 1; +} + + +/* + * Print names in the list + */ +static void print_name_list(NAME_LIST *name_list) +{ + int i; + + for (i=0; i < name_list->num_ids; i++) { + printf("%s\n", name_list->name[i]); + } +} + + +/* + * Free names in the list + */ +static void free_name_list(NAME_LIST *name_list) +{ + int i; + + for (i=0; i < name_list->num_ids; i++) { + free(name_list->name[i]); + } + name_list->num_ids = 0; +} + +static void eliminate_duplicate_filenames() +{ + char *query; + + printf("Checking for duplicate Filename entries.\n"); + + /* Make list of duplicated names */ + query = "SELECT Name FROM Filename " + "GROUP BY Name HAVING COUNT(FilenameId) > 1"; + if (!make_name_list(query, &name_list)) { + exit(1); + } + printf("Found %d duplicate Filename records.\n", name_list.num_ids); + if (verbose) { + print_name_list(&name_list); + } + if (fix) { + /* Loop through list of duplicate names */ + for (int i=0; i 1"; + if (!make_name_list(query, &name_list)) { + exit(1); + } + printf("Found %d duplicate Path records.\n", name_list.num_ids); + if (verbose) { + print_name_list(&name_list); + } + if (fix) { + /* Loop through list of duplicate names */ + for (int i=0; i 0) { + printf("Deleting %d orphaned JobMedia records.\n", id_list.num_ids); + delete_id_list("DELETE FROM JobMedia WHERE JobMediaId=%u", &id_list); + } +} + +static void eliminate_orphaned_file_records() +{ + char *query; + + printf("Checking for orphaned File entries.\n"); + query = "SELECT FileId,Job FROM File LEFT OUTER JOIN Job ON" + " (Job.JobId=File.JobId) GROUP BY FileId HAVING Job IS NULL"; + if (!make_id_list(query, &id_list)) { + exit(1); + } + printf("Found %d orphaned File records.\n", id_list.num_ids); + + if (fix && id_list.num_ids > 0) { + printf("Deleting %d orphaned File records.\n", id_list.num_ids); + delete_id_list("DELETE FROM File WHERE FileIdId=%u", &id_list); + } +} -- 2.39.5