]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/tools/dbcheck.c
Add jcr to DB arguments
[bacula/bacula] / bacula / src / tools / dbcheck.c
index eafcc748bce78ce7783ab218196d2ed620257cd3..819b39e543d896a0fc52645900df2000bcf11b10 100644 (file)
@@ -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] <working-directory> <bacula-databse> <user> <password>\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<name_list.num_ids; i++) {
         /* Get all the Ids of each name */
-         sprintf(buf, "SELECT FilenameId FROM Filename WHERE Name='%s'",
-           name_list.name[i]);
+        db_escape_string(esc_name, name_list.name[i], strlen(name_list.name[i]));
+         sprintf(buf, "SELECT FilenameId FROM Filename WHERE Name='%s'", esc_name);
+        if (verbose) {
+            printf("Doing: %s\n", name_list.name[i]);
+        }
         if (!make_id_list(buf, &id_list)) {
            exit(1);
         }
@@ -337,25 +474,31 @@ static void eliminate_duplicate_filenames()
 static void eliminate_duplicate_paths()
 {
    char *query;
+   char esc_name[5000];
 
-   printf("Checking for duplicate Path entries.\n");
+   printf(_("Checking for duplicate Path entries.\n"));
    
    /* Make list of duplicated names */
-   query = "SELECT Path FROM Path "
-           "GROUP BY Path HAVING COUNT(PathId) > 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<name_list.num_ids; i++) {
         /* Get all the Ids of each name */
-         sprintf(buf, "SELECT PathId FROM Path WHERE Path='%s'",
-           name_list.name[i]);
+        db_escape_string(esc_name, name_list.name[i], strlen(name_list.name[i]));
+         sprintf(buf, "SELECT PathId FROM Path WHERE Path='%s'", esc_name);
+        if (verbose) {
+            printf("Doing: %s\n", name_list.name[i]);
+        }
         if (!make_id_list(buf, &id_list)) {
            exit(1);
         }
@@ -378,12 +521,24 @@ static void eliminate_orphaned_jobmedia_records()
    char *query;
 
    printf("Checking for orphaned JobMedia entries.\n");
-   query = "SELECT JobMedia.JobId,Job FROM JobMedia LEFT OUTER JOIN Job ON"
-           " (Job.JobId=JobMediaId) GROUP BY MediaId HAVING Job IS NULL";
+   query = "SELECT JobMedia.JobMediaId,Job.JobId FROM JobMedia "
+           "LEFT OUTER JOIN Job ON (JobMedia.JobId=Job.JobId) "
+           "WHERE Job.JobId IS NULL";
    if (!make_id_list(query, &id_list)) {
       exit(1);
    }
    printf("Found %d orphaned JobMedia 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 JobMedia.JobMediaId,JobMedia.JobId,Media.VolumeName FROM JobMedia,Media "
+"WHERE JobMedia.JobMediaId=%u AND Media.MediaId=JobMedia.MediaId", id_list.Id[i]);
+        if (!db_sql_query(db, buf, print_jobmedia_handler, NULL)) {
+            printf("%s\n", db_strerror(db));
+        }
+      }
+   }
    
    if (fix && id_list.num_ids > 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;
 }