3 * Program to check a Bacula database for consistency and to
6 * Kern E. Sibbald, August 2002
12 Copyright (C) 2002-2006 Kern Sibbald
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 version 2 as amended with additional clauses defined in the
17 file LICENSE in the main source directory.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 the file LICENSE for additional details.
27 #include "cats/cats.h"
28 #include "lib/runscript.h"
29 #include "dird/dird_conf.h"
32 int generate_daemon_event(JCR *jcr, const char *event)
35 typedef struct s_id_ctx {
36 uint32_t *Id; /* ids to be modified */
37 int num_ids; /* ids stored */
38 int max_ids; /* size of array */
39 int num_del; /* number deleted */
40 int tot_ids; /* total to process */
43 typedef struct s_name_ctx {
44 char **name; /* list of names */
45 int num_ids; /* ids stored */
46 int max_ids; /* size of array */
47 int num_del; /* number deleted */
48 int tot_ids; /* total to process */
53 /* Global variables */
54 static bool fix = false;
55 static bool batch = false;
57 static ID_LIST id_list;
58 static NAME_LIST name_list;
59 static char buf[2000];
61 #define MAX_ID_LIST_LEN 10000000
63 /* Forward referenced functions */
64 static int make_id_list(const char *query, ID_LIST *id_list);
65 static int delete_id_list(const char *query, ID_LIST *id_list);
66 static int make_name_list(const char *query, NAME_LIST *name_list);
67 static void print_name_list(NAME_LIST *name_list);
68 static void free_name_list(NAME_LIST *name_list);
69 static char *get_cmd(const char *prompt);
70 static void eliminate_duplicate_filenames();
71 static void eliminate_duplicate_paths();
72 static void eliminate_orphaned_jobmedia_records();
73 static void eliminate_orphaned_file_records();
74 static void eliminate_orphaned_path_records();
75 static void eliminate_orphaned_filename_records();
76 static void eliminate_orphaned_fileset_records();
77 static void eliminate_orphaned_client_records();
78 static void eliminate_orphaned_job_records();
79 static void eliminate_admin_records();
80 static void eliminate_restore_records();
81 static void repair_bad_paths();
82 static void repair_bad_filenames();
83 static void do_interactive_mode();
84 static int yes_no(const char *prompt);
90 "Usage: dbcheck [-c config] [-C catalog name] [-d debug_level] <working-directory> <bacula-database> <user> <password> [<dbhost>]\n"
92 " -C catalog name in the director conf file\n"
93 " -c director conf filename\n"
94 " -dnn set debug level to nn\n"
95 " -f fix inconsistencies\n"
97 " -? print this message\n\n");
101 int main (int argc, char *argv[])
104 const char *user, *password, *db_name, *dbhost;
105 char *configfile = NULL;
106 char *catalogname = NULL;
108 setlocale(LC_ALL, "");
109 bindtextdomain("bacula", LOCALEDIR);
110 textdomain("bacula");
112 my_name_is(argc, argv, "dbcheck");
113 init_msg(NULL, NULL); /* setup message handler */
115 memset(&id_list, 0, sizeof(id_list));
116 memset(&name_list, 0, sizeof(name_list));
119 while ((ch = getopt(argc, argv, "bc:C:d:fv?")) != -1) {
121 case 'b': /* batch */
125 case 'C': /* CatalogName */
126 catalogname = optarg;
129 case 'c': /* configfile */
133 case 'd': /* debug level */
134 debug_level = atoi(optarg);
135 if (debug_level <= 0)
139 case 'f': /* fix inconsistencies */
161 Pmsg0(0, _("Warning skipping the additional parameters for working directory/dbname/user/password/host.\n"));
163 parse_config(configfile);
165 foreach_res(catalog, R_CATALOG) {
166 if (catalogname && !strcmp(catalog->hdr.name, catalogname)) {
169 } else if (!catalogname) { // stop on first if no catalogname is given
177 Pmsg2(0, _("Error can not find the Catalog name[%s] in the given config file [%s]\n"), catalogname, configfile);
179 Pmsg1(0, _("Error there is no Catalog section in the given config file [%s]\n"), configfile);
185 director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
188 Pmsg0(0, _("Error no Director resource defined.\n"));
191 set_working_directory(director->working_directory);
192 db_name = catalog->db_name;
193 user = catalog->db_user;
194 password = catalog->db_password;
195 dbhost = catalog->db_address;
196 if (dbhost && dbhost[0] == 0) {
202 Pmsg0(0, _("Wrong number of arguments.\n"));
207 Pmsg0(0, _("Working directory not supplied.\n"));
211 /* This is needed by SQLite to find the db */
212 working_directory = argv[0];
221 } else if (argc == 3) {
224 } else if (argc == 4) {
228 } else if (argc == 5) {
237 db = db_init_database(NULL, db_name, user, password, dbhost, 0, NULL, 0);
238 if (!db_open_database(NULL, db)) {
239 Emsg1(M_FATAL, 0, "%s", db_strerror(db));
245 repair_bad_filenames();
246 eliminate_duplicate_filenames();
247 eliminate_duplicate_paths();
248 eliminate_orphaned_jobmedia_records();
249 eliminate_orphaned_file_records();
250 eliminate_orphaned_path_records();
251 eliminate_orphaned_filename_records();
252 eliminate_orphaned_fileset_records();
253 eliminate_orphaned_client_records();
254 eliminate_orphaned_job_records();
255 eliminate_admin_records();
256 eliminate_restore_records();
258 do_interactive_mode();
261 db_close_database(NULL, db);
267 static void do_interactive_mode()
272 printf(_("Hello, this is the database check/correct program.\n"));
274 printf(_("Modify database is on."));
276 printf(_("Modify database is off."));
278 printf(_(" Verbose is on.\n"));
280 printf(_(" Verbose is off.\n"));
282 printf(_("Please select the fuction you want to perform.\n"));
287 " 1) Toggle modify database flag\n"
288 " 2) Toggle verbose flag\n"
289 " 3) Repair bad Filename records\n"
290 " 4) Repair bad Path records\n"
291 " 5) Eliminate duplicate Filename records\n"
292 " 6) Eliminate duplicate Path records\n"
293 " 7) Eliminate orphaned Jobmedia records\n"
294 " 8) Eliminate orphaned File records\n"
295 " 9) Eliminate orphaned Path records\n"
296 " 10) Eliminate orphaned Filename records\n"
297 " 11) Eliminate orphaned FileSet records\n"
298 " 12) Eliminate orphaned Client records\n"
299 " 13) Eliminate orphaned Job records\n"
300 " 14) Eliminate all Admin records\n"
301 " 15) Eliminate all Restore records\n"
306 " 1) Toggle modify database flag\n"
307 " 2) Toggle verbose flag\n"
308 " 3) Check for bad Filename records\n"
309 " 4) Check for bad Path records\n"
310 " 5) Check for duplicate Filename records\n"
311 " 6) Check for duplicate Path records\n"
312 " 7) Check for orphaned Jobmedia records\n"
313 " 8) Check for orphaned File records\n"
314 " 9) Check for orphaned Path records\n"
315 " 10) Check for orphaned Filename records\n"
316 " 11) Check for orphaned FileSet records\n"
317 " 12) Check for orphaned Client records\n"
318 " 13) Check for orphaned Job records\n"
319 " 14) Check for all Admin records\n"
320 " 15) Check for all Restore records\n"
325 cmd = get_cmd(_("Select function number: "));
327 int item = atoi(cmd);
332 printf(_("Database will be modified.\n"));
334 printf(_("Database will NOT be modified.\n"));
337 verbose = verbose?0:1;
339 printf(_(" Verbose is on.\n"));
341 printf(_(" Verbose is off.\n"));
344 repair_bad_filenames();
350 eliminate_duplicate_filenames();
353 eliminate_duplicate_paths();
356 eliminate_orphaned_jobmedia_records();
359 eliminate_orphaned_file_records();
362 eliminate_orphaned_path_records();
365 eliminate_orphaned_filename_records();
368 eliminate_orphaned_fileset_records();
371 eliminate_orphaned_client_records();
374 eliminate_orphaned_job_records();
377 eliminate_admin_records();
380 eliminate_restore_records();
383 repair_bad_filenames();
385 eliminate_duplicate_filenames();
386 eliminate_duplicate_paths();
387 eliminate_orphaned_jobmedia_records();
388 eliminate_orphaned_file_records();
389 eliminate_orphaned_path_records();
390 eliminate_orphaned_filename_records();
391 eliminate_orphaned_fileset_records();
392 eliminate_orphaned_client_records();
393 eliminate_orphaned_job_records();
394 eliminate_admin_records();
395 eliminate_restore_records();
405 static int print_name_handler(void *ctx, int num_fields, char **row)
408 printf("%s\n", row[0]);
413 static int get_name_handler(void *ctx, int num_fields, char **row)
415 POOLMEM *buf = (POOLMEM *)ctx;
417 pm_strcpy(&buf, row[0]);
422 static int print_job_handler(void *ctx, int num_fields, char **row)
424 printf(_("JobId=%s Name=\"%s\" StartTime=%s\n"),
425 NPRT(row[0]), NPRT(row[1]), NPRT(row[2]));
430 static int print_jobmedia_handler(void *ctx, int num_fields, char **row)
432 printf(_("Orphaned JobMediaId=%s JobId=%s Volume=\"%s\"\n"),
433 NPRT(row[0]), NPRT(row[1]), NPRT(row[2]));
437 static int print_file_handler(void *ctx, int num_fields, char **row)
439 printf(_("Orphaned FileId=%s JobId=%s Volume=\"%s\"\n"),
440 NPRT(row[0]), NPRT(row[1]), NPRT(row[2]));
444 static int print_fileset_handler(void *ctx, int num_fields, char **row)
446 printf(_("Orphaned FileSetId=%s FileSet=\"%s\" MD5=%s\n"),
447 NPRT(row[0]), NPRT(row[1]), NPRT(row[2]));
451 static int print_client_handler(void *ctx, int num_fields, char **row)
453 printf(_("Orphaned ClientId=%s Name=\"%s\"\n"),
454 NPRT(row[0]), NPRT(row[1]));
460 * Called here with each id to be added to the list
462 static int id_list_handler(void *ctx, int num_fields, char **row)
464 ID_LIST *lst = (ID_LIST *)ctx;
466 if (lst->num_ids == MAX_ID_LIST_LEN) {
469 if (lst->num_ids == lst->max_ids) {
470 if (lst->max_ids == 0) {
472 lst->Id = (uint32_t *)bmalloc(sizeof(uint32_t) * lst->max_ids);
474 lst->max_ids = (lst->max_ids * 3) / 2;
475 lst->Id = (uint32_t *)brealloc(lst->Id, sizeof(uint32_t) * lst->max_ids);
478 lst->Id[lst->num_ids++] = (uint32_t)strtod(row[0], NULL);
483 * Construct record id list
485 static int make_id_list(const char *query, ID_LIST *id_list)
487 id_list->num_ids = 0;
488 id_list->num_del = 0;
489 id_list->tot_ids = 0;
491 if (!db_sql_query(db, query, id_list_handler, (void *)id_list)) {
492 printf("%s", db_strerror(db));
499 * Delete all entries in the list
501 static int delete_id_list(const char *query, ID_LIST *id_list)
503 for (int i=0; i < id_list->num_ids; i++) {
504 bsnprintf(buf, sizeof(buf), query, id_list->Id[i]);
506 printf(_("Deleting: %s\n"), buf);
508 db_sql_query(db, buf, NULL, NULL);
514 * Called here with each name to be added to the list
516 static int name_list_handler(void *ctx, int num_fields, char **row)
518 NAME_LIST *name = (NAME_LIST *)ctx;
520 if (name->num_ids == MAX_ID_LIST_LEN) {
523 if (name->num_ids == name->max_ids) {
524 if (name->max_ids == 0) {
525 name->max_ids = 1000;
526 name->name = (char **)bmalloc(sizeof(char *) * name->max_ids);
528 name->max_ids = (name->max_ids * 3) / 2;
529 name->name = (char **)brealloc(name->name, sizeof(char *) * name->max_ids);
532 name->name[name->num_ids++] = bstrdup(row[0]);
538 * Construct name list
540 static int make_name_list(const char *query, NAME_LIST *name_list)
542 name_list->num_ids = 0;
543 name_list->num_del = 0;
544 name_list->tot_ids = 0;
546 if (!db_sql_query(db, query, name_list_handler, (void *)name_list)) {
547 printf("%s", db_strerror(db));
554 * Print names in the list
556 static void print_name_list(NAME_LIST *name_list)
558 for (int i=0; i < name_list->num_ids; i++) {
559 printf("%s\n", name_list->name[i]);
565 * Free names in the list
567 static void free_name_list(NAME_LIST *name_list)
569 for (int i=0; i < name_list->num_ids; i++) {
570 free(name_list->name[i]);
572 name_list->num_ids = 0;
575 static void eliminate_duplicate_filenames()
580 printf(_("Checking for duplicate Filename entries.\n"));
582 /* Make list of duplicated names */
583 query = "SELECT Name, count(Name) as Count FROM Filename GROUP BY Name "
584 "HAVING count(Name) > 1";
586 if (!make_name_list(query, &name_list)) {
589 printf(_("Found %d duplicate Filename records.\n"), name_list.num_ids);
590 if (name_list.num_ids && verbose && yes_no(_("Print the list? (yes/no): "))) {
591 print_name_list(&name_list);
594 /* Loop through list of duplicate names */
595 for (int i=0; i<name_list.num_ids; i++) {
596 /* Get all the Ids of each name */
597 db_escape_string(esc_name, name_list.name[i], strlen(name_list.name[i]));
598 bsnprintf(buf, sizeof(buf), "SELECT FilenameId FROM Filename WHERE Name='%s'", esc_name);
602 if (!make_id_list(buf, &id_list)) {
606 printf(_("Found %d for: %s\n"), id_list.num_ids, name_list.name[i]);
608 /* Force all records to use the first id then delete the other ids */
609 for (int j=1; j<id_list.num_ids; j++) {
610 bsnprintf(buf, sizeof(buf), "UPDATE File SET FilenameId=%u WHERE FilenameId=%u",
611 id_list.Id[0], id_list.Id[j]);
615 db_sql_query(db, buf, NULL, NULL);
616 bsnprintf(buf, sizeof(buf), "DELETE FROM Filename WHERE FilenameId=%u",
621 db_sql_query(db, buf, NULL, NULL);
625 free_name_list(&name_list);
628 static void eliminate_duplicate_paths()
633 printf(_("Checking for duplicate Path entries.\n"));
635 /* Make list of duplicated names */
637 query = "SELECT Path, count(Path) as Count FROM Path "
638 "GROUP BY Path HAVING count(Path) > 1";
640 if (!make_name_list(query, &name_list)) {
643 printf(_("Found %d duplicate Path records.\n"), name_list.num_ids);
644 if (name_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
645 print_name_list(&name_list);
648 /* Loop through list of duplicate names */
649 for (int i=0; i<name_list.num_ids; i++) {
650 /* Get all the Ids of each name */
651 db_escape_string(esc_name, name_list.name[i], strlen(name_list.name[i]));
652 bsnprintf(buf, sizeof(buf), "SELECT PathId FROM Path WHERE Path='%s'", esc_name);
656 if (!make_id_list(buf, &id_list)) {
660 printf(_("Found %d for: %s\n"), id_list.num_ids, name_list.name[i]);
662 /* Force all records to use the first id then delete the other ids */
663 for (int j=1; j<id_list.num_ids; j++) {
664 bsnprintf(buf, sizeof(buf), "UPDATE File SET PathId=%u WHERE PathId=%u",
665 id_list.Id[0], id_list.Id[j]);
669 db_sql_query(db, buf, NULL, NULL);
670 bsnprintf(buf, sizeof(buf), "DELETE FROM Path WHERE PathId=%u",
675 db_sql_query(db, buf, NULL, NULL);
679 free_name_list(&name_list);
682 static void eliminate_orphaned_jobmedia_records()
686 printf(_("Checking for orphaned JobMedia entries.\n"));
687 query = "SELECT JobMedia.JobMediaId,Job.JobId FROM JobMedia "
688 "LEFT OUTER JOIN Job ON (JobMedia.JobId=Job.JobId) "
689 "WHERE Job.JobId IS NULL";
690 if (!make_id_list(query, &id_list)) {
693 printf(_("Found %d orphaned JobMedia records.\n"), id_list.num_ids);
694 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
695 for (int i=0; i < id_list.num_ids; i++) {
696 bsnprintf(buf, sizeof(buf),
697 "SELECT JobMedia.JobMediaId,JobMedia.JobId,Media.VolumeName FROM JobMedia,Media "
698 "WHERE JobMedia.JobMediaId=%u AND Media.MediaId=JobMedia.MediaId", id_list.Id[i]);
699 if (!db_sql_query(db, buf, print_jobmedia_handler, NULL)) {
700 printf("%s\n", db_strerror(db));
705 if (fix && id_list.num_ids > 0) {
706 printf(_("Deleting %d orphaned JobMedia records.\n"), id_list.num_ids);
707 delete_id_list("DELETE FROM JobMedia WHERE JobMediaId=%u", &id_list);
711 static void eliminate_orphaned_file_records()
715 printf(_("Checking for orphaned File entries. This may take some time!\n"));
716 query = "SELECT File.FileId,Job.JobId FROM File "
717 "LEFT OUTER JOIN Job ON (File.JobId=Job.JobId) "
718 "WHERE Job.JobId IS NULL";
720 printf("%s\n", query);
722 if (!make_id_list(query, &id_list)) {
725 printf(_("Found %d orphaned File records.\n"), id_list.num_ids);
726 if (name_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
727 for (int i=0; i < id_list.num_ids; i++) {
728 bsnprintf(buf, sizeof(buf),
729 "SELECT File.FileId,File.JobId,Filename.Name FROM File,Filename "
730 "WHERE File.FileId=%u AND File.FilenameId=Filename.FilenameId", id_list.Id[i]);
731 if (!db_sql_query(db, buf, print_file_handler, NULL)) {
732 printf("%s\n", db_strerror(db));
737 if (fix && id_list.num_ids > 0) {
738 printf(_("Deleting %d orphaned File records.\n"), id_list.num_ids);
739 delete_id_list("DELETE FROM File WHERE FileId=%u", &id_list);
743 static void eliminate_orphaned_path_records()
747 printf(_("Checking for orphaned Path entries. This may take some time!\n"));
748 query = "SELECT DISTINCT Path.PathId,File.PathId FROM Path "
749 "LEFT OUTER JOIN File ON (Path.PathId=File.PathId) "
750 "WHERE File.PathId IS NULL";
752 printf("%s\n", query);
754 if (!make_id_list(query, &id_list)) {
757 printf(_("Found %d orphaned Path records.\n"), id_list.num_ids);
758 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
759 for (int i=0; i < id_list.num_ids; i++) {
760 bsnprintf(buf, sizeof(buf), "SELECT Path FROM Path WHERE PathId=%u", id_list.Id[i]);
761 db_sql_query(db, buf, print_name_handler, NULL);
765 if (fix && id_list.num_ids > 0) {
766 printf(_("Deleting %d orphaned Path records.\n"), id_list.num_ids);
767 delete_id_list("DELETE FROM Path WHERE PathId=%u", &id_list);
771 static void eliminate_orphaned_filename_records()
775 printf(_("Checking for orphaned Filename entries. This may take some time!\n"));
776 query = "SELECT Filename.FilenameId,File.FilenameId FROM Filename "
777 "LEFT OUTER JOIN File ON (Filename.FilenameId=File.FilenameId) "
778 "WHERE File.FilenameId IS NULL";
780 printf("%s\n", query);
782 if (!make_id_list(query, &id_list)) {
785 printf(_("Found %d orphaned Filename records.\n"), id_list.num_ids);
786 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
787 for (int i=0; i < id_list.num_ids; i++) {
788 bsnprintf(buf, sizeof(buf), "SELECT Name FROM Filename WHERE FilenameId=%u", id_list.Id[i]);
789 db_sql_query(db, buf, print_name_handler, NULL);
793 if (fix && id_list.num_ids > 0) {
794 printf(_("Deleting %d orphaned Filename records.\n"), id_list.num_ids);
795 delete_id_list("DELETE FROM Filename WHERE FilenameId=%u", &id_list);
799 static void eliminate_orphaned_fileset_records()
803 printf(_("Checking for orphaned FileSet entries. This takes some time!\n"));
804 query = "SELECT FileSet.FileSetId,Job.FileSetId FROM FileSet "
805 "LEFT OUTER JOIN Job ON (FileSet.FileSetId=Job.FileSetId) "
806 "WHERE Job.FileSetId IS NULL";
808 printf("%s\n", query);
810 if (!make_id_list(query, &id_list)) {
813 printf(_("Found %d orphaned FileSet records.\n"), id_list.num_ids);
814 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
815 for (int i=0; i < id_list.num_ids; i++) {
816 bsnprintf(buf, sizeof(buf), "SELECT FileSetId,FileSet,MD5 FROM FileSet "
817 "WHERE FileSetId=%u", id_list.Id[i]);
818 if (!db_sql_query(db, buf, print_fileset_handler, NULL)) {
819 printf("%s\n", db_strerror(db));
824 if (fix && id_list.num_ids > 0) {
825 printf(_("Deleting %d orphaned FileSet records.\n"), id_list.num_ids);
826 delete_id_list("DELETE FROM FileSet WHERE FileSetId=%u", &id_list);
830 static void eliminate_orphaned_client_records()
834 printf(_("Checking for orphaned Client entries.\n"));
836 * Wiffle through Client for every Client
837 * joining with the Job table including every Client even if
838 * there is not a match in Job (left outer join), then
839 * filter out only those where no Job points to a Client
840 * i.e. Job.Client is NULL
842 query = "SELECT Client.ClientId,Client.Name FROM Client "
843 "LEFT OUTER JOIN Job ON (Client.ClientId=Job.ClientId) "
844 "WHERE Job.ClientId IS NULL";
846 printf("%s\n", query);
848 if (!make_id_list(query, &id_list)) {
851 printf(_("Found %d orphaned Client records.\n"), id_list.num_ids);
852 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
853 for (int i=0; i < id_list.num_ids; i++) {
854 bsnprintf(buf, sizeof(buf), "SELECT ClientId,Name FROM Client "
855 "WHERE ClientId=%u", id_list.Id[i]);
856 if (!db_sql_query(db, buf, print_client_handler, NULL)) {
857 printf("%s\n", db_strerror(db));
862 if (fix && id_list.num_ids > 0) {
863 printf(_("Deleting %d orphaned Client records.\n"), id_list.num_ids);
864 delete_id_list("DELETE FROM Client WHERE ClientId=%u", &id_list);
868 static void eliminate_orphaned_job_records()
872 printf(_("Checking for orphaned Job entries.\n"));
874 * Wiffle through Job for every Job
875 * joining with the Client table including every Job even if
876 * there is not a match in Client (left outer join), then
877 * filter out only those where no Client exists
878 * i.e. Client.Name is NULL
880 query = "SELECT Job.JobId,Job.Name FROM Job "
881 "LEFT OUTER JOIN Client ON (Job.ClientId=Client.ClientId) "
882 "WHERE Client.Name IS NULL";
884 printf("%s\n", query);
886 if (!make_id_list(query, &id_list)) {
889 printf(_("Found %d orphaned Job records.\n"), id_list.num_ids);
890 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
891 for (int i=0; i < id_list.num_ids; i++) {
892 bsnprintf(buf, sizeof(buf), "SELECT JobId,Name,StartTime FROM Job "
893 "WHERE JobId=%u", id_list.Id[i]);
894 if (!db_sql_query(db, buf, print_job_handler, NULL)) {
895 printf("%s\n", db_strerror(db));
900 if (fix && id_list.num_ids > 0) {
901 printf(_("Deleting %d orphaned Job records.\n"), id_list.num_ids);
902 delete_id_list("DELETE FROM Job WHERE JobId=%u", &id_list);
907 static void eliminate_admin_records()
911 printf(_("Checking for Admin Job entries.\n"));
912 query = "SELECT Job.JobId FROM Job "
913 "WHERE Job.Type='D'";
915 printf("%s\n", query);
917 if (!make_id_list(query, &id_list)) {
920 printf(_("Found %d Admin Job records.\n"), id_list.num_ids);
921 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
922 for (int i=0; i < id_list.num_ids; i++) {
923 bsnprintf(buf, sizeof(buf), "SELECT JobId,Name,StartTime FROM Job "
924 "WHERE JobId=%u", id_list.Id[i]);
925 if (!db_sql_query(db, buf, print_job_handler, NULL)) {
926 printf("%s\n", db_strerror(db));
931 if (fix && id_list.num_ids > 0) {
932 printf(_("Deleting %d Admin Job records.\n"), id_list.num_ids);
933 delete_id_list("DELETE FROM Job WHERE JobId=%u", &id_list);
937 static void eliminate_restore_records()
941 printf(_("Checking for Restore Job entries.\n"));
942 query = "SELECT Job.JobId FROM Job "
943 "WHERE Job.Type='R'";
945 printf("%s\n", query);
947 if (!make_id_list(query, &id_list)) {
950 printf(_("Found %d Restore Job records.\n"), id_list.num_ids);
951 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
952 for (int i=0; i < id_list.num_ids; i++) {
953 bsnprintf(buf, sizeof(buf), "SELECT JobId,Name,StartTime FROM Job "
954 "WHERE JobId=%u", id_list.Id[i]);
955 if (!db_sql_query(db, buf, print_job_handler, NULL)) {
956 printf("%s\n", db_strerror(db));
961 if (fix && id_list.num_ids > 0) {
962 printf(_("Deleting %d Restore Job records.\n"), id_list.num_ids);
963 delete_id_list("DELETE FROM Job WHERE JobId=%u", &id_list);
970 static void repair_bad_filenames()
975 printf(_("Checking for Filenames with a trailing slash\n"));
976 query = "SELECT FilenameId,Name from Filename "
977 "WHERE Name LIKE '%/'";
979 printf("%s\n", query);
981 if (!make_id_list(query, &id_list)) {
984 printf(_("Found %d bad Filename records.\n"), id_list.num_ids);
985 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
986 for (i=0; i < id_list.num_ids; i++) {
987 bsnprintf(buf, sizeof(buf),
988 "SELECT Name FROM Filename WHERE FilenameId=%u", id_list.Id[i]);
989 if (!db_sql_query(db, buf, print_name_handler, NULL)) {
990 printf("%s\n", db_strerror(db));
995 if (fix && id_list.num_ids > 0) {
996 POOLMEM *name = get_pool_memory(PM_FNAME);
998 printf(_("Reparing %d bad Filename records.\n"), id_list.num_ids);
999 for (i=0; i < id_list.num_ids; i++) {
1001 bsnprintf(buf, sizeof(buf),
1002 "SELECT Name FROM Filename WHERE FilenameId=%u", id_list.Id[i]);
1003 if (!db_sql_query(db, buf, get_name_handler, name)) {
1004 printf("%s\n", db_strerror(db));
1006 /* Strip trailing slash(es) */
1007 for (len=strlen(name); len > 0 && name[len-1]=='/'; len--)
1015 db_escape_string(esc_name, name, len);
1017 bsnprintf(buf, sizeof(buf),
1018 "UPDATE Filename SET Name='%s' WHERE FilenameId=%u",
1019 esc_name, id_list.Id[i]);
1021 printf("%s\n", buf);
1023 db_sql_query(db, buf, NULL, NULL);
1028 static void repair_bad_paths()
1033 printf(_("Checking for Paths without a trailing slash\n"));
1034 query = "SELECT PathId,Path from Path "
1035 "WHERE Path NOT LIKE '%/'";
1037 printf("%s\n", query);
1039 if (!make_id_list(query, &id_list)) {
1042 printf(_("Found %d bad Path records.\n"), id_list.num_ids);
1043 if (id_list.num_ids && verbose && yes_no(_("Print them? (yes/no): "))) {
1044 for (i=0; i < id_list.num_ids; i++) {
1045 bsnprintf(buf, sizeof(buf),
1046 "SELECT Path FROM Path WHERE PathId=%u", id_list.Id[i]);
1047 if (!db_sql_query(db, buf, print_name_handler, NULL)) {
1048 printf("%s\n", db_strerror(db));
1053 if (fix && id_list.num_ids > 0) {
1054 POOLMEM *name = get_pool_memory(PM_FNAME);
1055 char esc_name[5000];
1056 printf(_("Reparing %d bad Filename records.\n"), id_list.num_ids);
1057 for (i=0; i < id_list.num_ids; i++) {
1059 bsnprintf(buf, sizeof(buf),
1060 "SELECT Path FROM Path WHERE PathId=%u", id_list.Id[i]);
1061 if (!db_sql_query(db, buf, get_name_handler, name)) {
1062 printf("%s\n", db_strerror(db));
1064 /* Strip trailing blanks */
1065 for (len=strlen(name); len > 0 && name[len-1]==' '; len--) {
1068 /* Add trailing slash */
1069 len = pm_strcat(&name, "/");
1070 db_escape_string(esc_name, name, len);
1071 bsnprintf(buf, sizeof(buf), "UPDATE Path SET Path='%s' WHERE PathId=%u",
1072 esc_name, id_list.Id[i]);
1074 printf("%s\n", buf);
1076 db_sql_query(db, buf, NULL, NULL);
1083 * Gen next input command from the terminal
1085 static char *get_cmd(const char *prompt)
1087 static char cmd[1000];
1089 printf("%s", prompt);
1090 if (fgets(cmd, sizeof(cmd), stdin) == NULL)
1093 strip_trailing_junk(cmd);
1097 static int yes_no(const char *prompt)
1100 cmd = get_cmd(prompt);
1101 return (strcasecmp(cmd, "yes") == 0) || (strcasecmp(cmd, _("yes")) == 0);
1104 bool python_set_prog(JCR*, char const*) { return false; }