X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=bacula%2Fsrc%2Ftools%2Fdbcheck.c;h=819b39e543d896a0fc52645900df2000bcf11b10;hb=1f3edf3a27024df37e6de3d9b63b6d744808f628;hp=eafcc748bce78ce7783ab218196d2ed620257cd3;hpb=f52955c3e03b6fef083df5b77ce25a75213e2539;p=bacula%2Fbacula diff --git a/bacula/src/tools/dbcheck.c b/bacula/src/tools/dbcheck.c index eafcc748bc..819b39e543 100644 --- a/bacula/src/tools/dbcheck.c +++ b/bacula/src/tools/dbcheck.c @@ -9,7 +9,7 @@ * */ /* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2000-2003 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 @@ -51,7 +51,7 @@ typedef struct s_name_ctx { /* Global variables */ static int fix = FALSE; -static int interactive = FALSE; +static int batch = FALSE; static int verbose = FALSE; static B_DB *db; static ID_LIST id_list; @@ -66,25 +66,26 @@ 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 char *get_cmd(char *prompt); static void eliminate_duplicate_filenames(); static void eliminate_duplicate_paths(); static void eliminate_orphaned_jobmedia_records(); static void eliminate_orphaned_file_records(); +static void eliminate_orphaned_path_records(); +static void eliminate_orphaned_filename_records(); +static void eliminate_orphaned_fileset_records(); +static void do_interactive_mode(); +static int yes_no(char *prompt); -#ifdef xxxx -static void prtit(void *ctx, char *msg) -{ - printf("%s", msg); -} -#endif static void usage() { fprintf(stderr, "Usage: dbcheck [-d debug_level] \n" +" -b batch mode\n" " -dnn set debug level to nn\n" " -f fix inconsistencies\n" -" -i interactive mode\n" +" -v verbose\n" " -? print this message\n\n"); exit(1); } @@ -101,8 +102,12 @@ int main (int argc, char *argv[]) memset(&name_list, 0, sizeof(name_list)); - while ((ch = getopt(argc, argv, "d:fi?")) != -1) { + while ((ch = getopt(argc, argv, "bd:fv?")) != -1) { switch (ch) { + case 'b': /* batch */ + batch = TRUE; + break; + case 'd': /* debug level */ debug_level = atoi(optarg); if (debug_level <= 0) @@ -113,8 +118,8 @@ int main (int argc, char *argv[]) fix = TRUE; break; - case 'i': /* interactive */ - interactive = TRUE; + case 'v': + verbose++; break; case '?': @@ -156,24 +161,149 @@ int main (int argc, char *argv[]) /* Open database */ db = db_init_database(NULL, db_name, user, password); - if (!db_open_database(db)) { + if (!db_open_database(NULL, db)) { Emsg1(M_FATAL, 0, "%s", db_strerror(db)); } - eliminate_duplicate_filenames(); + if (batch) { + eliminate_duplicate_filenames(); + eliminate_duplicate_paths(); + eliminate_orphaned_jobmedia_records(); + eliminate_orphaned_file_records(); + eliminate_orphaned_path_records(); + eliminate_orphaned_filename_records(); + eliminate_orphaned_fileset_records(); + } else { + do_interactive_mode(); + } - eliminate_duplicate_paths(); + db_close_database(NULL, db); + close_msg(NULL); + term_msg(); + return 0; +} - eliminate_orphaned_jobmedia_records(); +static void do_interactive_mode() +{ + int quit = FALSE; + char *cmd; + + printf("Hello, this is the database check/correct program.\n\ +Modify database is %s. Verbose is %s.\n\ +Please select the fuction you want to perform.\n", + fix?"On":"Off", verbose?"On":"Off"); + + while (!quit) { + if (fix) { + printf(_("\n\ + 1) Toggle modify database flag\n\ + 2) Toggle verbose flag\n\ + 3) Eliminate duplicate Filename records\n\ + 4) Eliminate duplicate Path records\n\ + 5) Eliminate orphaned Jobmedia records\n\ + 6) Eliminate orphaned File records\n\ + 7) Eliminate orphaned Path records\n\ + 8) Eliminate orphaned Filename records\n\ + 9) Eliminate orphaned FileSet records\n\ + 10) All (3-9)\n\ + 11) Quit\n")); + } else { + printf(_("\n\ + 1) Toggle modify database flag\n\ + 2) Toggle verbose flag\n\ + 3) Check for duplicate Filename records\n\ + 4) Check for duplicate Path records\n\ + 5) Check for orphaned Jobmedia records\n\ + 6) Check for orphaned File records\n\ + 7) Check for orphaned Path records\n\ + 8) Check for orphaned Filename records\n\ + 9) Check for orphaned FileSet records\n\ + 10) All (3-9)\n\ + 11) Quit\n")); + } + + cmd = get_cmd(_("Select function number: ")); + if (cmd) { + int item = atoi(cmd); + switch (item) { + case 1: + fix = !fix; + printf(_("Database will %sbe modified.\n"), fix?"":_("NOT ")); + break; + case 2: + verbose = verbose?0:1; + printf(_("Verbose is %s\n"), verbose?_("On"):_("Off")); + break; + case 3: + eliminate_duplicate_filenames(); + break; + case 4: + eliminate_duplicate_paths(); + break; + case 5: + eliminate_orphaned_jobmedia_records(); + break; + case 6: + eliminate_orphaned_file_records(); + break; + case 7: + eliminate_orphaned_path_records(); + break; + case 8: + eliminate_orphaned_filename_records(); + break; + case 9: + eliminate_orphaned_fileset_records(); + break; + case 10: + eliminate_duplicate_filenames(); + eliminate_duplicate_paths(); + eliminate_orphaned_jobmedia_records(); + eliminate_orphaned_file_records(); + eliminate_orphaned_path_records(); + eliminate_orphaned_filename_records(); + eliminate_orphaned_fileset_records(); + break; + case 11: + quit = 1; + break; + } + } + } +} + +static int print_name_handler(void *ctx, int num_fields, char **row) +{ + if (row[0]) { + printf("%s\n", row[0]); + } + return 0; +} - eliminate_orphaned_file_records(); +static int print_jobmedia_handler(void *ctx, int num_fields, char **row) +{ + printf(_("Orphaned JobMediaId=%s JobId=%s Volume=\"%s\"\n"), + NPRT(row[0]), NPRT(row[1]), NPRT(row[2])); + return 0; +} - db_close_database(db); +static int print_file_handler(void *ctx, int num_fields, char **row) +{ + printf(_("Orphaned FileId=%s JobId=%s Volume=\"%s\"\n"), + NPRT(row[0]), NPRT(row[1]), NPRT(row[2])); + return 0; +} - close_msg(NULL); - term_msg(); +static int print_fileset_handler(void *ctx, int num_fields, char **row) +{ + printf(_("Orphaned FileSetId=%s FileSet=\"%s\" MD5=%s\n"), + NPRT(row[0]), NPRT(row[1]), NPRT(row[2])); return 0; } + + + + /* * Called here with each id to be added to the list @@ -223,6 +353,9 @@ static int delete_id_list(char *query, ID_LIST *id_list) for (i=0; i < id_list->num_ids; i++) { sprintf(buf, query, id_list->Id[i]); + if (verbose) { + printf("Deleting: %s\n", buf); + } db_sql_query(db, buf, NULL, NULL); } return 1; @@ -268,7 +401,6 @@ static int make_name_list(char *query, NAME_LIST *name_list) return 1; } - /* * Print names in the list */ @@ -298,25 +430,30 @@ static void free_name_list(NAME_LIST *name_list) static void eliminate_duplicate_filenames() { char *query; + char esc_name[5000]; printf("Checking for duplicate Filename entries.\n"); /* Make list of duplicated names */ - query = "SELECT Name FROM Filename " - "GROUP BY Name HAVING COUNT(FilenameId) > 1"; + query = "SELECT Name,count(Name) as Count FROM Filename GROUP BY Name " + "HAVING Count > 1"; + if (!make_name_list(query, &name_list)) { exit(1); } printf("Found %d duplicate Filename records.\n", name_list.num_ids); - if (verbose) { + if (verbose && yes_no("Print the list? (yes/no): ")) { print_name_list(&name_list); } if (fix) { /* Loop through list of duplicate names */ for (int i=0; i 1"; + + query = "SELECT Path,count(Path) as Count FROM Path " + "GROUP BY Path HAVING Count > 1"; + if (!make_name_list(query, &name_list)) { exit(1); } printf("Found %d duplicate Path records.\n", name_list.num_ids); - if (verbose) { + if (name_list.num_ids && verbose && yes_no("Print them? (yes/no): ")) { 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); @@ -395,16 +550,133 @@ 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"; + printf("Checking for orphaned File entries. This may take some time!\n"); + query = "SELECT File.FileId,Job.JobId FROM File " + "LEFT OUTER JOIN Job ON (File.JobId=Job.JobId) " + "WHERE Job.JobId IS NULL"; if (!make_id_list(query, &id_list)) { exit(1); } printf("Found %d orphaned File records.\n", id_list.num_ids); - + if (name_list.num_ids && verbose && yes_no("Print them? (yes/no): ")) { + int i; + for (i=0; i < id_list.num_ids; i++) { + sprintf(buf, +"SELECT File.FileId,File.JobId,Filename.Name FROM File,Filename " +"WHERE File.FileId=%u AND File.FilenameId=Filename.FilenameId", id_list.Id[i]); + if (!db_sql_query(db, buf, print_file_handler, NULL)) { + printf("%s\n", db_strerror(db)); + } + } + } + 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); + delete_id_list("DELETE FROM File WHERE FileId=%u", &id_list); + } +} + +static void eliminate_orphaned_path_records() +{ + char *query; + + printf("Checking for orphaned Path entries. This may take some time!\n"); + query = "SELECT Path.PathId,File.PathId FROM Path " + "LEFT OUTER JOIN File ON (Path.PathId=File.PathId) " + "HAVING File.PathId IS NULL"; + if (!make_id_list(query, &id_list)) { + exit(1); + } + printf("Found %d orphaned Path records.\n", id_list.num_ids); + if (id_list.num_ids && verbose && yes_no("Print them? (yes/no): ")) { + int i; + for (i=0; i < id_list.num_ids; i++) { + sprintf(buf, "SELECT Path FROM Path WHERE PathId=%u", id_list.Id[i]); + db_sql_query(db, buf, print_name_handler, NULL); + } + } + + if (fix && id_list.num_ids > 0) { + printf("Deleting %d orphaned Path records.\n", id_list.num_ids); + delete_id_list("DELETE FROM Path WHERE PathId=%u", &id_list); + } +} + +static void eliminate_orphaned_filename_records() +{ + char *query; + + printf("Checking for orphaned Filename entries. This may take some time!\n"); + query = "SELECT Filename.FilenameId,File.FilenameId FROM Filename " + "LEFT OUTER JOIN File ON (Filename.FilenameId=File.FilenameId) " + "WHERE File.FilenameId IS NULL"; + + if (!make_id_list(query, &id_list)) { + exit(1); + } + printf("Found %d orphaned Filename records.\n", id_list.num_ids); + if (id_list.num_ids && verbose && yes_no("Print them? (yes/no): ")) { + int i; + for (i=0; i < id_list.num_ids; i++) { + sprintf(buf, "SELECT Name FROM Filename WHERE FilenameId=%u", id_list.Id[i]); + db_sql_query(db, buf, print_name_handler, NULL); + } } + + if (fix && id_list.num_ids > 0) { + printf("Deleting %d orphaned Filename records.\n", id_list.num_ids); + delete_id_list("DELETE FROM Filename WHERE FilenameId=%u", &id_list); + } +} + +static void eliminate_orphaned_fileset_records() +{ + char *query; + + printf("Checking for orphaned FileSet entries. This takes some time!\n"); + query = "SELECT FileSet.FileSetId,Job.FileSetId FROM FileSet " + "LEFT OUTER JOIN Job ON (FileSet.FileSetId=Job.FileSetId) " + "WHERE Job.FileSetId IS NULL"; + if (!make_id_list(query, &id_list)) { + exit(1); + } + printf("Found %d orphaned FileSet records.\n", id_list.num_ids); + if (id_list.num_ids && verbose && yes_no("Print them? (yes/no): ")) { + int i; + for (i=0; i < id_list.num_ids; i++) { + sprintf(buf, "SELECT FileSetId,FileSet,MD5 FROM FileSet " + "WHERE FileSetId=%u", id_list.Id[i]); + if (!db_sql_query(db, buf, print_fileset_handler, NULL)) { + printf("%s\n", db_strerror(db)); + } + } + } + + if (fix && id_list.num_ids > 0) { + printf("Deleting %d orphaned FileSet records.\n", id_list.num_ids); + delete_id_list("DELETE FROM FileSet WHERE FileSetId=%u", &id_list); + } +} + + +/* + * Gen next input command from the terminal + */ +static char *get_cmd(char *prompt) +{ + static char cmd[1000]; + + printf("%s", prompt); + if (fgets(cmd, sizeof(cmd), stdin) == NULL) + return NULL; + printf("\n"); + strip_trailing_junk(cmd); + return cmd; +} + +static int yes_no(char *prompt) +{ + char *cmd; + cmd = get_cmd(prompt); + return strcasecmp(cmd, "yes") == 0; }