]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Enhance JSON output for .jlist command with error, errmsg and type
authorEric Bollengier <eric@baculasystems.com>
Thu, 7 Oct 2021 16:25:17 +0000 (18:25 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 24 Mar 2022 08:03:28 +0000 (09:03 +0100)
bacula/src/cats/bdb.h
bacula/src/cats/cats.h
bacula/src/cats/protos.h
bacula/src/cats/sql.c
bacula/src/cats/sql_list.c
bacula/src/dird/ua_query.c
bacula/src/dird/ua_restore.c
bacula/src/dird/ua_update.c

index 59fe7edd1eda67251036565e2c3015c1431c04bd..52e277cb1737ca47b5799d742497225576818e65 100644 (file)
@@ -262,7 +262,7 @@ public:
    void bdb_list_jobmedia_records(JCR *jcr, JobId_t JobId, char *volume, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_filemedia_records(JCR *jcr, JobId_t JobId, uint32_t FileIndex, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_joblog_records(JCR *jcr, JobId_t JobId, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
-   int  bdb_list_sql_query(JCR *jcr, const char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type);
+   int  bdb_list_sql_query(JCR *jcr, const char *title, const char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type);
    void bdb_list_client_records(JCR *jcr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_copies_records(JCR *jcr, uint32_t limit, char *jobids, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_events_records(JCR *jcr, EVENTS_DBR *rec, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
index 767f8d6a52d39643518790e5d04b22346ef823e1..c1197188f59e7da1025011a257888d76a5e0d534 100644 (file)
@@ -723,8 +723,10 @@ public:
 
 
 /* Functions exported by sql.c for use within the cats directory. */
+void json_list_begin(void *vctx, const char *title);
+void json_list_end(void *vctx, int errcode, const char *errmsg);
 int list_result(void *vctx, int cols, char **row);
-int list_result(JCR *jcr, BDB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type);
+int list_result(JCR *jcr, BDB *mdb, const char *title, DB_LIST_HANDLER *send, void *ctx, e_list_type type);
 int get_sql_record_max(JCR *jcr, BDB *mdb);
 void list_dashes(BDB *mdb, DB_LIST_HANDLER *send, void *ctx);
 
index f5889e1b6ea58dd460b5695b2551b5f971417c34..53e6682518a3760602ed643a63dfeb793ba9baf4 100644 (file)
@@ -81,6 +81,7 @@ BDB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name,
         if (mdb)  mdb->bdb_thread_cleanup()
 
 /* sql.c */
+int db_mint64_handler(void *ctx, int num_fields, char **row);
 int db_int64_handler(void *ctx, int num_fields, char **row);
 int db_strtime_handler(void *ctx, int num_fields, char **row);
 int db_list_handler(void *ctx, int num_fields, char **row);
@@ -278,8 +279,8 @@ void bdb_free_restoreobject_record(JCR *jcr, ROBJECT_DBR *rr);
            mdb->bdb_list_filemedia_records(jcr, JobId, FI, sendit, ctx, type)
 #define db_list_joblog_records(jcr, mdb, JobId, sendit, ctx, type)      \
            mdb->bdb_list_joblog_records(jcr, JobId, sendit, ctx, type)
-#define db_list_sql_query(jcr, mdb, query, sendit, ctx, verbose, type) \
-           mdb->bdb_list_sql_query(jcr, query, sendit, ctx, verbose, type)
+#define db_list_sql_query(jcr, mdb, title, query, sendit, ctx, verbose, type) \
+           mdb->bdb_list_sql_query(jcr, title, query, sendit, ctx, verbose, type)
 #define db_list_client_records(jcr, mdb, sendit, ctx, type) \
            mdb->bdb_list_client_records(jcr, sendit, ctx, type)
 #define db_list_copies_records(jcr, mdb, limit, jobids, sendit, ctx, type) \
index 1de5dc1847d1805a5089056599688eecfdb709fb..85bda0ae8c64e03a343f9b892f14dd8ff6c78987 100644 (file)
@@ -122,7 +122,24 @@ int db_int64_handler(void *ctx, int num_fields, char **row)
    } 
    return 0; 
 } 
+
+/* 
+ * Called here to retrieve a 32/64 bit integer from the database. 
+ *   The returned integer will be extended to 64 bit. It can
+ * return multiple values, but the array has to match the number
+ * of fields to be returned.
+ */ 
+int db_mint64_handler(void *ctx, int num_fields, char **row)
+{
+   int64_t *tab = (int64_t *)ctx;
+   for (int i = 0; i < num_fields; i++) {
+      if (row[i]) {
+         tab[i] = str_to_int64(row[i]);
+      }
+   }
+   return 0;
+}
+
 /* 
  * Called here to retrieve a btime from the database. 
  *   The returned integer will be extended to 64 bit. 
@@ -740,7 +757,7 @@ static void last_line_handler(void *vctx, const char *str)
    LIST_CTX *ctx = (LIST_CTX *)vctx; 
    bstrncat(ctx->line, str, sizeof(ctx->line)); 
 } 
+
 int list_result(void *vctx, int nb_col, char **row) 
 { 
    SQL_FIELD *field; 
@@ -844,7 +861,6 @@ int list_result(void *vctx, int nb_col, char **row)
    return 0; 
  
 vertical_list: 
    Dmsg1(800, "list_result starts vertical list at %d fields\n", mdb->sql_num_fields()); 
    mdb->sql_field_seek(0); 
    for (i = 0; i < mdb->sql_num_fields(); i++) { 
@@ -908,27 +924,46 @@ json_list:
       send(ctx, tmp.c_str());
       first = false;
    }
-   send(ctx, "}\n");
+   send(ctx, "}");
    return 0;
 } 
+
+/* Use this function to start a new JSON list */
+void json_list_begin(DB_LIST_HANDLER *send, void *ctx, const char *title)
+{
+   send(ctx, "{\"type\":\"");
+   send(ctx, title);
+   send(ctx, "\", \"data\":");
+}
+
+/* Use this function to end a JSON list */
+void json_list_end(DB_LIST_HANDLER *send, void *ctx, int errcode, const char *errmsg)
+{
+   send(ctx, ",\"error\":0, \"errmsg\":\"\"}\n");
+}
+
 /* 
  * If full_list is set, we list vertically, otherwise, we 
  *  list on one line horizontally. 
  * Return number of rows 
  */ 
 int 
-list_result(JCR *jcr, BDB *mdb, DB_LIST_HANDLER *send, void *ctx, e_list_type type) 
+list_result(JCR *jcr, BDB *mdb, const char *title, DB_LIST_HANDLER *send, void *ctx, e_list_type type) 
 { 
    SQL_FIELD *field; 
    SQL_ROW row; 
    int i, col_len, max_len = 0; 
    char buf[2000], ewc[30]; 
+
+   if (type == JSON_LIST) {
+      json_list_begin(send, ctx, title);
+   }
+
    Dmsg0(800, "list_result starts\n"); 
    if (mdb->sql_num_rows() == 0) {
       if (type == JSON_LIST) {
-         send(ctx, "[]\n");
+         send(ctx, "[]");
+         json_list_end(send, ctx, 0, "");
       } else {
          send(ctx, _("No results to list.\n"));
       }
@@ -1090,7 +1125,8 @@ json_list:
       }
       send(ctx, "}");
    }
-   send(ctx, "]\n");
+   send(ctx, "]");
+   json_list_end(send, ctx, 0, "");
    return mdb->sql_num_rows();
 } 
  
index e70f485c182cc71f1108447e4f4a6ec529264b8c..06b8f8d8f5473da078bc80114502de37736ca246 100644 (file)
@@ -39,7 +39,7 @@
 /*
  * Submit general SQL query
  */
-int BDB::bdb_list_sql_query(JCR *jcr, const char *query, DB_LIST_HANDLER *sendit,
+int BDB::bdb_list_sql_query(JCR *jcr, const char *title, const char *query, DB_LIST_HANDLER *sendit,
                       void *ctx, int verbose, e_list_type type)
 {
    bdb_lock();
@@ -52,7 +52,7 @@ int BDB::bdb_list_sql_query(JCR *jcr, const char *query, DB_LIST_HANDLER *sendit
       return 0;
    }
 
-   list_result(jcr,this, sendit, ctx, type);
+   list_result(jcr,this, title, sendit, ctx, type);
    sql_free_result();
    bdb_unlock();
    return 1;
@@ -100,7 +100,7 @@ void BDB::bdb_list_pool_records(JCR *jcr, POOL_DBR *pdbr,
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "pool", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -122,7 +122,7 @@ void BDB::bdb_list_client_records(JCR *jcr, DB_LIST_HANDLER *sendit, void *ctx,
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "client", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -144,7 +144,7 @@ void BDB::bdb_list_plugin_object_types(JCR *jcr, DB_LIST_HANDLER *sendit, void *
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "objecttype", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -204,7 +204,7 @@ void BDB::bdb_list_plugin_objects(JCR *jcr, OBJECT_DBR *obj_r, DB_LIST_HANDLER *
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "object", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -244,7 +244,7 @@ void BDB::bdb_list_plugin_objects_ids(JCR *jcr, char* id_list, DB_LIST_HANDLER *
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "object", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -296,7 +296,7 @@ void BDB::bdb_list_restore_objects(JCR *jcr, ROBJECT_DBR *rr, DB_LIST_HANDLER *s
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "restoreobject", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -385,7 +385,7 @@ void BDB::bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr,
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "media", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -442,7 +442,7 @@ void BDB::bdb_list_jobmedia_records(JCR *jcr, uint32_t JobId, char *volume,
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "jobmedia", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -479,7 +479,7 @@ void BDB::bdb_list_filemedia_records(JCR *jcr, uint32_t JobId, uint32_t FileInde
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "filemedia", sendit, ctx, type);
 
    sql_free_result();
    bdb_unlock();
@@ -525,7 +525,7 @@ void BDB::bdb_list_copies_records(JCR *jcr, uint32_t limit, char *JobIds,
          sendit(ctx, _("The catalog contains copies as follows:\n"));
       }
 
-      list_result(jcr, this, sendit, ctx, type);
+      list_result(jcr, this, "copy", sendit, ctx, type);
    }
 
    sql_free_result();
@@ -627,7 +627,7 @@ void BDB::bdb_list_events_records(JCR *jcr, EVENTS_DBR *rec,
    if (!QueryDB(jcr, cmd)) {
       goto bail_out;
    }
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "event", sendit, ctx, type);
 
 bail_out:
    bdb_unlock();
@@ -670,7 +670,7 @@ void BDB::bdb_list_joblog_records(JCR *jcr, uint32_t JobId,
       goto bail_out;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "joblog", sendit, ctx, type);
 
    sql_free_result();
 
@@ -818,7 +818,7 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
       }
    }
    sql_data_seek(0);
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "job", sendit, ctx, type);
    sql_free_result();
    bdb_unlock();
    return list;
@@ -827,6 +827,7 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
 /*
  * List Job totals
  *
+ * TODO: Adapt for JSON
  */
 void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx)
 {
@@ -844,7 +845,7 @@ void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, HORZ_LIST);
+   list_result(jcr, this, "jobtotal", sendit, ctx, HORZ_LIST);
 
    sql_free_result();
 
@@ -858,7 +859,7 @@ void BDB::bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo
       return;
    }
 
-   list_result(jcr, this, sendit, ctx, HORZ_LIST);
+   list_result(jcr, this, "jobtotal", sendit, ctx, HORZ_LIST);
 
    sql_free_result();
    bdb_unlock();
@@ -1055,7 +1056,7 @@ void BDB::bdb_list_snapshot_records(JCR *jcr, SNAPSHOT_DBR *sdbr,
       goto bail_out;
    }
 
-   list_result(jcr, this, sendit, ctx, type);
+   list_result(jcr, this, "snapshot", sendit, ctx, type);
 
 bail_out:
    sql_free_result();
@@ -1129,10 +1130,9 @@ void BDB::bdb_list_tag_records(JCR *jcr, TAG_DBR *tag, DB_LIST_HANDLER *result_h
          }
       }
       Dmsg1(DT_SQL|50, "q=%s\n", tmp.c_str());
-      bdb_list_sql_query(jcr, tmp.c_str(), result_handler, ctx, 0, type);
+      bdb_list_sql_query(jcr, "tag", tmp.c_str(), result_handler, ctx, 0, type);
    }
    bdb_unlock();
 }
 
-
 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */
index 522cb10f1380a0078a4fd287240aab31a9e82a23..c46d904bc9b51f67cca8203c0034967788fb0eb0 100644 (file)
@@ -141,8 +141,8 @@ int query_cmd(UAContext *ua, const char *cmd)
          query = substitute_prompts(ua, query, prompt, nprompt);
          Dmsg1(100, "Query2=%s\n", query);
          if (query[0] == '!') {
-            db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST);
-         } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) {
+            db_list_sql_query(ua->jcr, ua->db, "query", query+1, prtit, ua, 0, VERT_LIST);
+         } else if (!db_list_sql_query(ua->jcr, ua->db, "query", query, prtit, ua, 1, HORZ_LIST)) {
             ua->send_msg("%s\n", query);
          }
          query[0] = 0;
@@ -153,8 +153,8 @@ int query_cmd(UAContext *ua, const char *cmd)
       query = substitute_prompts(ua, query, prompt, nprompt);
       Dmsg1(100, "Query2=%s\n", query);
          if (query[0] == '!') {
-            db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST);
-         } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) {
+            db_list_sql_query(ua->jcr, ua->db, "query", query+1, prtit, ua, 0, VERT_LIST);
+         } else if (!db_list_sql_query(ua->jcr, ua->db, "query", query, prtit, ua, 1, HORZ_LIST)) {
             ua->error_msg("%s\n", query);
          }
    }
@@ -289,7 +289,7 @@ int sqlquery_cmd(UAContext *ua, const char *cmd)
       if (ua->cmd[len-1] == ';') {
          ua->cmd[len-1] = 0;          /* zap ; */
          /* Submit query */
-         db_list_sql_query(ua->jcr, ua->db, query.c_str(), prtit, ua, 1, HORZ_LIST);
+         db_list_sql_query(ua->jcr, ua->db, "query", query.c_str(), prtit, ua, 1, HORZ_LIST);
          *query.c_str() = 0;         /* start new query */
          msg = _("Enter SQL query: ");
       } else {
index bbf8ccac182590d3de25d6efd2142bc89e59ef04..9caab2ee028029e8f26d74fb1eb16e8f009538e0 100644 (file)
@@ -455,7 +455,7 @@ static void get_and_display_basejobs(UAContext *ua, RESTORE_CTX *rx)
       POOL_MEM q;
       Mmsg(q, uar_print_jobs, jobids.list);
       ua->send_msg(_("The restore will use the following job(s) as Base\n"));
-      db_list_sql_query(ua->jcr, ua->db, q.c_str(), prtit, ua, 1, HORZ_LIST);
+      db_list_sql_query(ua->jcr, ua->db, "basejobs", q.c_str(), prtit, ua, 1, HORZ_LIST);
    }
    pm_strcpy(rx->BaseJobIds, jobids.list);
 }
@@ -842,7 +842,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          }
          gui_save = ua->jcr->gui;
          ua->jcr->gui = true;
-         db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, HORZ_LIST);
+         db_list_sql_query(ua->jcr, ua->db, "job", uar_list_jobs, prtit, ua, 1, HORZ_LIST);
          ua->jcr->gui = gui_save;
          done = false;
          break;
@@ -860,7 +860,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          free(fname);
          gui_save = ua->jcr->gui;
          ua->jcr->gui = true;
-         db_list_sql_query(ua->jcr, ua->db, rx->query, prtit, ua, 1, HORZ_LIST);
+         db_list_sql_query(ua->jcr, ua->db, "job", rx->query, prtit, ua, 1, HORZ_LIST);
          ua->jcr->gui = gui_save;
          done = false;
          break;
@@ -880,7 +880,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          }
          gui_save = ua->jcr->gui;
          ua->jcr->gui = true;
-         db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, HORZ_LIST);
+         db_list_sql_query(ua->jcr, ua->db, "job", ua->cmd, prtit, ua, 1, HORZ_LIST);
          ua->jcr->gui = gui_save;
          done = false;
          break;
@@ -1104,7 +1104,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
                         "WHERE Object.ObjectName='%s' AND Object.ObjectCategory='%s' AND Object.ObjectType='%s'",
                  esc.c_str(), esc_cat.c_str(), esc_type.c_str());
 
-            if (!db_list_sql_query(ua->jcr, ua->db, query.c_str(), prtit, ua, 0, HORZ_LIST)) {
+            if (!db_list_sql_query(ua->jcr, ua->db, "object", query.c_str(), prtit, ua, 0, HORZ_LIST)) {
                ua->error_msg(_("SQL Query failed: %s\n"), db_strerror(ua->db));
                return 0;
             }
@@ -1858,7 +1858,7 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    if (rx->JobIds[0] != 0) {
       /* Display a list of Jobs selected for this restore */
-      db_list_sql_query(ua->jcr, ua->db, uar_list_temp, prtit, ua, 1,HORZ_LIST);
+      db_list_sql_query(ua->jcr, ua->db, "job", uar_list_temp, prtit, ua, 1,HORZ_LIST);
       ok = true;
    } else {
       ua->warning_msg(_("No jobs found.\n"));
index 0e338977d9929c5e388a626662a4cb5e9fb565a1..89194b052dabf8f1b35e277b90bfea34295eebff 100644 (file)
@@ -917,7 +917,7 @@ static bool update_pool(UAContext *ua)
    }
    query = get_pool_memory(PM_MESSAGE);
    Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
-   db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
+   db_list_sql_query(ua->jcr, ua->db, "pool", query, prtit, ua, 1, HORZ_LIST);
    free_pool_memory(query);
    ua->info_msg(_("Pool DB record updated from resource.\n"));
    return true;