1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2016 Planets Communications B.V.
6    Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Kern Sibbald, March 2000
25  */
26 /**
27  * @file
28  * BAREOS Catalog Database List records interface routines
29  */
30 
31 #include "include/bareos.h"
32 
33 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
34 
35 #  include "cats.h"
36 #  include "lib/edit.h"
37 
38 /* -----------------------------------------------------------------------
39  *
40  *   Generic Routines (or almost generic)
41  *
42  * -----------------------------------------------------------------------
43  */
44 
45 /**
46  * Submit general SQL query
47  */
ListSqlQuery(JobControlRecord * jcr,const char * query,OutputFormatter * sendit,e_list_type type,bool verbose)48 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
49                             const char* query,
50                             OutputFormatter* sendit,
51                             e_list_type type,
52                             bool verbose)
53 {
54   return ListSqlQuery(jcr, query, sendit, type, "query", verbose);
55 }
56 
ListSqlQuery(JobControlRecord * jcr,SQL_QUERY query,OutputFormatter * sendit,e_list_type type,bool verbose)57 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
58                             SQL_QUERY query,
59                             OutputFormatter* sendit,
60                             e_list_type type,
61                             bool verbose)
62 {
63   return ListSqlQuery(jcr, query, sendit, type, "query", verbose);
64 }
65 
ListSqlQuery(JobControlRecord * jcr,const char * query,OutputFormatter * sendit,e_list_type type,const char * description,bool verbose)66 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
67                             const char* query,
68                             OutputFormatter* sendit,
69                             e_list_type type,
70                             const char* description,
71                             bool verbose)
72 {
73   bool retval = false;
74 
75   DbLock(this);
76 
77   if (!SqlQuery(query, QF_STORE_RESULT)) {
78     Mmsg(errmsg, _("Query failed: %s\n"), sql_strerror());
79     if (verbose) { sendit->Decoration(errmsg); }
80     goto bail_out;
81   }
82 
83   sendit->ArrayStart(description);
84   ListResult(jcr, sendit, type);
85   sendit->ArrayEnd(description);
86   SqlFreeResult();
87   retval = true;
88 
89 bail_out:
90   DbUnlock(this);
91   return retval;
92 }
93 
ListSqlQuery(JobControlRecord * jcr,SQL_QUERY query,OutputFormatter * sendit,e_list_type type,const char * description,bool verbose)94 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
95                             SQL_QUERY query,
96                             OutputFormatter* sendit,
97                             e_list_type type,
98                             const char* description,
99                             bool verbose)
100 {
101   return ListSqlQuery(jcr, get_predefined_query(query), sendit, type,
102                       description, verbose);
103 }
104 
ListPoolRecords(JobControlRecord * jcr,PoolDbRecord * pdbr,OutputFormatter * sendit,e_list_type type)105 void BareosDb::ListPoolRecords(JobControlRecord* jcr,
106                                PoolDbRecord* pdbr,
107                                OutputFormatter* sendit,
108                                e_list_type type)
109 {
110   char esc[MAX_ESCAPE_NAME_LENGTH];
111 
112   DbLock(this);
113   EscapeString(jcr, esc, pdbr->Name, strlen(pdbr->Name));
114 
115   if (type == VERT_LIST) {
116     if (pdbr->Name[0] != 0) {
117       Mmsg(cmd,
118            "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
119            "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
120            "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
121            "RecyclePoolId,LabelType "
122            "FROM Pool WHERE Name='%s'",
123            esc);
124     } else {
125       Mmsg(cmd,
126            "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
127            "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
128            "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
129            "RecyclePoolId,LabelType "
130            "FROM Pool ORDER BY PoolId");
131     }
132   } else {
133     if (pdbr->Name[0] != 0) {
134       Mmsg(cmd,
135            "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
136            "FROM Pool WHERE Name='%s'",
137            esc);
138     } else {
139       Mmsg(cmd,
140            "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
141            "FROM Pool ORDER BY PoolId");
142     }
143   }
144 
145   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
146 
147   sendit->ArrayStart("pools");
148   ListResult(jcr, sendit, type);
149   sendit->ArrayEnd("pools");
150 
151   SqlFreeResult();
152 
153 bail_out:
154   DbUnlock(this);
155 }
156 
ListClientRecords(JobControlRecord * jcr,char * clientname,OutputFormatter * sendit,e_list_type type)157 void BareosDb::ListClientRecords(JobControlRecord* jcr,
158                                  char* clientname,
159                                  OutputFormatter* sendit,
160                                  e_list_type type)
161 {
162   DbLock(this);
163   PoolMem clientfilter(PM_MESSAGE);
164 
165   if (clientname) { clientfilter.bsprintf("WHERE Name = '%s'", clientname); }
166   if (type == VERT_LIST) {
167     Mmsg(cmd,
168          "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,"
169          "JobRetention "
170          "FROM Client %s ORDER BY ClientId ",
171          clientfilter.c_str());
172   } else {
173     Mmsg(cmd,
174          "SELECT ClientId,Name,FileRetention,JobRetention "
175          "FROM Client %s ORDER BY ClientId",
176          clientfilter.c_str());
177   }
178 
179   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
180 
181   sendit->ArrayStart("clients");
182   ListResult(jcr, sendit, type);
183   sendit->ArrayEnd("clients");
184 
185   SqlFreeResult();
186 
187 bail_out:
188   DbUnlock(this);
189 }
190 
ListStorageRecords(JobControlRecord * jcr,OutputFormatter * sendit,e_list_type type)191 void BareosDb::ListStorageRecords(JobControlRecord* jcr,
192                                   OutputFormatter* sendit,
193                                   e_list_type type)
194 {
195   DbLock(this);
196 
197   Mmsg(cmd, "SELECT StorageId,Name,AutoChanger FROM Storage");
198 
199   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
200 
201   sendit->ArrayStart("storages");
202   ListResult(jcr, sendit, type);
203   sendit->ArrayEnd("storages");
204 
205   SqlFreeResult();
206 
207 bail_out:
208   DbUnlock(this);
209 }
210 
211 /**
212  * If VolumeName is non-zero, list the record for that Volume
213  *   otherwise, list the Volumes in the Pool specified by PoolId
214  */
ListMediaRecords(JobControlRecord * jcr,MediaDbRecord * mdbr,const char * range,bool count,OutputFormatter * sendit,e_list_type type)215 void BareosDb::ListMediaRecords(JobControlRecord* jcr,
216                                 MediaDbRecord* mdbr,
217                                 const char* range,
218                                 bool count,
219                                 OutputFormatter* sendit,
220                                 e_list_type type)
221 {
222   char ed1[50];
223   char esc[MAX_ESCAPE_NAME_LENGTH];
224   PoolMem select(PM_MESSAGE);
225   PoolMem query(PM_MESSAGE);
226 
227   EscapeString(jcr, esc, mdbr->VolumeName, strlen(mdbr->VolumeName));
228 
229   /*
230    * There is one case where ListMediaRecords() is called from SelectMediaDbr()
231    * with the range argument set to NULL. To avoid problems, we set the range to
232    * an empty string if range is set to NULL. Otherwise it would result in
233    * malformed SQL queries.
234    */
235   if (range == NULL) { range = ""; }
236 
237   if (count) {
238     /* NOTE: ACLs are ignored. */
239     if (mdbr->VolumeName[0] != 0) {
240       FillQuery(query, SQL_QUERY::list_volumes_by_name_count_1, esc);
241     } else if (mdbr->PoolId > 0) {
242       FillQuery(query, SQL_QUERY::list_volumes_by_poolid_count_1,
243                 edit_int64(mdbr->PoolId, ed1));
244     } else {
245       FillQuery(query, SQL_QUERY::list_volumes_count_0);
246     }
247   } else {
248     if (type == VERT_LIST) {
249       FillQuery(select, SQL_QUERY::list_volumes_select_long_0);
250     } else {
251       FillQuery(select, SQL_QUERY::list_volumes_select_0);
252     }
253 
254     if (mdbr->VolumeName[0] != 0) {
255       query.bsprintf("%s WHERE VolumeName='%s'", select.c_str(), esc);
256     } else if (mdbr->PoolId > 0) {
257       query.bsprintf("%s WHERE PoolId=%s ORDER BY MediaId %s", select.c_str(),
258                      edit_int64(mdbr->PoolId, ed1), range);
259     } else {
260       query.bsprintf("%s ORDER BY MediaId %s", select.c_str(), range);
261     }
262   }
263 
264   DbLock(this);
265 
266   if (!QUERY_DB(jcr, query.c_str())) { goto bail_out; }
267 
268   ListResult(jcr, sendit, type);
269 
270   SqlFreeResult();
271 
272 bail_out:
273   DbUnlock(this);
274 }
275 
276 
ListJobmediaRecords(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)277 void BareosDb::ListJobmediaRecords(JobControlRecord* jcr,
278                                    uint32_t JobId,
279                                    OutputFormatter* sendit,
280                                    e_list_type type)
281 {
282   char ed1[50];
283 
284   DbLock(this);
285   if (type == VERT_LIST) {
286     if (JobId > 0) { /* do by JobId */
287       Mmsg(cmd,
288            "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
289            "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
290            "JobMedia.EndBlock "
291            "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
292            "AND JobMedia.JobId=%s",
293            edit_int64(JobId, ed1));
294     } else {
295       Mmsg(cmd,
296            "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
297            "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
298            "JobMedia.EndBlock "
299            "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
300     }
301 
302   } else {
303     if (JobId > 0) { /* do by JobId */
304       Mmsg(cmd,
305            "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
306            "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
307            "AND JobMedia.JobId=%s",
308            edit_int64(JobId, ed1));
309     } else {
310       Mmsg(cmd,
311            "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
312            "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
313     }
314   }
315   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
316 
317   sendit->ArrayStart("jobmedia");
318   ListResult(jcr, sendit, type);
319   sendit->ArrayEnd("jobmedia");
320 
321   SqlFreeResult();
322 
323 bail_out:
324   DbUnlock(this);
325 }
326 
327 
ListVolumesOfJobid(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)328 void BareosDb::ListVolumesOfJobid(JobControlRecord* jcr,
329                                   uint32_t JobId,
330                                   OutputFormatter* sendit,
331                                   e_list_type type)
332 {
333   char ed1[50];
334 
335   if (JobId <= 0) { return; }
336 
337   DbLock(this);
338   if (type == VERT_LIST) {
339     Mmsg(cmd,
340          "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName "
341          "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
342          "AND JobMedia.JobId=%s",
343          edit_int64(JobId, ed1));
344   } else {
345     Mmsg(cmd,
346          "SELECT DISTINCT Media.VolumeName "
347          "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
348          "AND JobMedia.JobId=%s",
349          edit_int64(JobId, ed1));
350   }
351   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
352 
353   sendit->ArrayStart("volumes");
354   ListResult(jcr, sendit, type);
355   sendit->ArrayEnd("volumes");
356 
357   SqlFreeResult();
358 
359 bail_out:
360   DbUnlock(this);
361 }
362 
363 
ListCopiesRecords(JobControlRecord * jcr,const char * range,const char * JobIds,OutputFormatter * send,e_list_type type)364 void BareosDb::ListCopiesRecords(JobControlRecord* jcr,
365                                  const char* range,
366                                  const char* JobIds,
367                                  OutputFormatter* send,
368                                  e_list_type type)
369 {
370   PoolMem str_jobids(PM_MESSAGE);
371 
372   if (JobIds && JobIds[0]) {
373     Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ",
374          JobIds, JobIds);
375   }
376 
377   DbLock(this);
378   Mmsg(cmd,
379        "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
380        "Job.JobId AS CopyJobId, Media.MediaType "
381        "FROM Job "
382        "JOIN JobMedia USING (JobId) "
383        "JOIN Media USING (MediaId) "
384        "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s",
385        (char)JT_JOB_COPY, str_jobids.c_str(), range);
386 
387   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
388 
389   if (SqlNumRows()) {
390     if (JobIds && JobIds[0]) {
391       send->Decoration(_("These JobIds have copies as follows:\n"));
392     } else {
393       send->Decoration(_("The catalog contains copies as follows:\n"));
394     }
395 
396     send->ArrayStart("copies");
397     ListResult(jcr, send, type);
398     send->ArrayEnd("copies");
399   }
400 
401   SqlFreeResult();
402 
403 bail_out:
404   DbUnlock(this);
405 }
406 
ListLogRecords(JobControlRecord * jcr,const char * clientname,const char * range,bool reverse,OutputFormatter * sendit,e_list_type type)407 void BareosDb::ListLogRecords(JobControlRecord* jcr,
408                               const char* clientname,
409                               const char* range,
410                               bool reverse,
411                               OutputFormatter* sendit,
412                               e_list_type type)
413 {
414   PoolMem client_filter(PM_MESSAGE);
415 
416   if (clientname) {
417     Mmsg(client_filter, "AND Client.Name = '%s' ", clientname);
418   }
419 
420   if (reverse) {
421     Mmsg(cmd,
422          "SELECT LogId, Job.Name AS JobName, Client.Name AS ClientName, Time, "
423          "LogText "
424          "FROM Log "
425          "JOIN Job USING (JobId) "
426          "LEFT JOIN Client USING (ClientId) "
427          "WHERE Job.Type != 'C' "
428          "%s"
429          "ORDER BY Log.LogId DESC %s",
430          client_filter.c_str(), range);
431   } else {
432     Mmsg(cmd,
433          "SELECT LogId, JobName, ClientName, Time, LogText FROM ("
434          "SELECT LogId, Job.Name AS JobName, Client.Name As ClientName, Time, "
435          "LogText "
436          "FROM Log "
437          "JOIN Job USING (JobId) "
438          "LEFT JOIN Client USING (ClientId) "
439          "WHERE Job.Type != 'C' "
440          "%s"
441          "ORDER BY Log.LogId DESC %s"
442          ") AS sub ORDER BY LogId ASC",
443          client_filter.c_str(), range);
444   }
445 
446   if (type != VERT_LIST) {
447     /*
448      * When something else then a vertical list is requested set the list type
449      * to RAW_LIST e.g. non formated raw data as that makes the only sense for
450      * the logtext output. The logtext already has things like \n etc in it
451      * so we should just dump the raw content out for the best visible output.
452      */
453     type = RAW_LIST;
454   }
455 
456   DbLock(this);
457 
458   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
459 
460   sendit->ArrayStart("log");
461   ListResult(jcr, sendit, type);
462   sendit->ArrayEnd("log");
463 
464   SqlFreeResult();
465 
466 bail_out:
467   DbUnlock(this);
468 }
469 
ListJoblogRecords(JobControlRecord * jcr,uint32_t JobId,const char * range,bool count,OutputFormatter * sendit,e_list_type type)470 void BareosDb::ListJoblogRecords(JobControlRecord* jcr,
471                                  uint32_t JobId,
472                                  const char* range,
473                                  bool count,
474                                  OutputFormatter* sendit,
475                                  e_list_type type)
476 {
477   char ed1[50];
478 
479   if (JobId <= 0) { return; }
480 
481   DbLock(this);
482   if (count) {
483     FillQuery(SQL_QUERY::list_joblog_count_1, edit_int64(JobId, ed1));
484   } else {
485     FillQuery(SQL_QUERY::list_joblog_2, edit_int64(JobId, ed1), range);
486     if (type != VERT_LIST) {
487       /*
488        * When something else then a vertical list is requested set the list type
489        * to RAW_LIST e.g. non formated raw data as that makes the only sense for
490        * the logtext output. The logtext already has things like \n etc in it
491        * so we should just dump the raw content out for the best visible output.
492        */
493       type = RAW_LIST;
494     }
495   }
496 
497   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
498 
499   sendit->ArrayStart("joblog");
500   ListResult(jcr, sendit, type);
501   sendit->ArrayEnd("joblog");
502 
503   SqlFreeResult();
504 
505 bail_out:
506   DbUnlock(this);
507 }
508 
509 /**
510  * list job statistics records for certain jobid
511  *
512  */
ListJobstatisticsRecords(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)513 void BareosDb::ListJobstatisticsRecords(JobControlRecord* jcr,
514                                         uint32_t JobId,
515                                         OutputFormatter* sendit,
516                                         e_list_type type)
517 {
518   char ed1[50];
519 
520   if (JobId <= 0) { return; }
521   DbLock(this);
522   Mmsg(cmd,
523        "SELECT DeviceId, SampleTime, JobId, JobFiles, JobBytes "
524        "FROM JobStats "
525        "WHERE JobStats.JobId=%s "
526        "ORDER BY JobStats.SampleTime ",
527        edit_int64(JobId, ed1));
528   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
529 
530   sendit->ArrayStart("jobstats");
531   ListResult(jcr, sendit, type);
532   sendit->ArrayEnd("jobstats");
533 
534   SqlFreeResult();
535 
536 bail_out:
537   DbUnlock(this);
538 }
539 
540 /**
541  * List Job record(s) that match JobDbRecord
542  */
ListJobRecords(JobControlRecord * jcr,JobDbRecord * jr,const char * range,const char * clientname,int jobstatus,int joblevel,const char * volumename,const char * poolname,utime_t since_time,bool last,bool count,OutputFormatter * sendit,e_list_type type)543 void BareosDb::ListJobRecords(JobControlRecord* jcr,
544                               JobDbRecord* jr,
545                               const char* range,
546                               const char* clientname,
547                               int jobstatus,
548                               int joblevel,
549                               const char* volumename,
550                               const char* poolname,
551                               utime_t since_time,
552                               bool last,
553                               bool count,
554                               OutputFormatter* sendit,
555                               e_list_type type)
556 {
557   char ed1[50];
558   char dt[MAX_TIME_LENGTH];
559   char esc[MAX_ESCAPE_NAME_LENGTH];
560   PoolMem temp(PM_MESSAGE), selection(PM_MESSAGE), criteria(PM_MESSAGE);
561 
562   if (jr->JobId > 0) {
563     temp.bsprintf("AND Job.JobId=%s", edit_int64(jr->JobId, ed1));
564     PmStrcat(selection, temp.c_str());
565   }
566 
567   if (jr->Name[0] != 0) {
568     EscapeString(jcr, esc, jr->Name, strlen(jr->Name));
569     temp.bsprintf("AND Job.Name = '%s' ", esc);
570     PmStrcat(selection, temp.c_str());
571   }
572 
573   if (clientname) {
574     temp.bsprintf("AND Client.Name = '%s' ", clientname);
575     PmStrcat(selection, temp.c_str());
576   }
577 
578   if (jobstatus) {
579     temp.bsprintf("AND Job.JobStatus = '%c' ", jobstatus);
580     PmStrcat(selection, temp.c_str());
581   }
582 
583   if (joblevel) {
584     temp.bsprintf("AND Job.Level = '%c' ", joblevel);
585     PmStrcat(selection, temp.c_str());
586   }
587 
588   if (volumename) {
589     temp.bsprintf("AND Media.Volumename = '%s' ", volumename);
590     PmStrcat(selection, temp.c_str());
591   }
592 
593   if (poolname) {
594     temp.bsprintf(
595         "AND Job.poolid = (SELECT poolid FROM pool WHERE name = '%s' LIMIT 1) ",
596         poolname);
597     PmStrcat(selection, temp.c_str());
598   }
599 
600   if (since_time) {
601     bstrutime(dt, sizeof(dt), since_time);
602     temp.bsprintf("AND Job.SchedTime > '%s' ", dt);
603     PmStrcat(selection, temp.c_str());
604   }
605 
606   DbLock(this);
607 
608   if (count) {
609     FillQuery(SQL_QUERY::list_jobs_count, selection.c_str(), range);
610   } else if (last) {
611     if (type == VERT_LIST) {
612       FillQuery(SQL_QUERY::list_jobs_long_last, selection.c_str(), range);
613     } else {
614       FillQuery(SQL_QUERY::list_jobs_last, selection.c_str(), range);
615     }
616   } else {
617     if (type == VERT_LIST) {
618       FillQuery(SQL_QUERY::list_jobs_long, selection.c_str(), range);
619     } else {
620       FillQuery(SQL_QUERY::list_jobs, selection.c_str(), range);
621     }
622   }
623 
624   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
625 
626   sendit->ArrayStart("jobs");
627   ListResult(jcr, sendit, type);
628   sendit->ArrayEnd("jobs");
629 
630   SqlFreeResult();
631 
632 bail_out:
633   DbUnlock(this);
634 }
635 
636 /**
637  * List Job totals
638  */
ListJobTotals(JobControlRecord * jcr,JobDbRecord * jr,OutputFormatter * sendit)639 void BareosDb::ListJobTotals(JobControlRecord* jcr,
640                              JobDbRecord* jr,
641                              OutputFormatter* sendit)
642 {
643   DbLock(this);
644 
645   /*
646    * List by Job
647    */
648   Mmsg(cmd,
649        "SELECT count(*) AS Jobs,sum(JobFiles) "
650        "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
651 
652   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
653 
654   sendit->ArrayStart("jobs");
655   ListResult(jcr, sendit, HORZ_LIST);
656   sendit->ArrayEnd("jobs");
657 
658   SqlFreeResult();
659 
660   /*
661    * Do Grand Total
662    */
663   Mmsg(cmd,
664        "SELECT COUNT(*) AS Jobs,sum(JobFiles) "
665        "AS Files,sum(JobBytes) As Bytes FROM Job");
666 
667   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
668 
669   sendit->ObjectStart("jobtotals");
670   ListResult(jcr, sendit, HORZ_LIST);
671   sendit->ObjectEnd("jobtotals");
672 
673   SqlFreeResult();
674 
675 bail_out:
676   DbUnlock(this);
677 }
678 
ListFilesForJob(JobControlRecord * jcr,JobId_t jobid,OutputFormatter * sendit)679 void BareosDb::ListFilesForJob(JobControlRecord* jcr,
680                                JobId_t jobid,
681                                OutputFormatter* sendit)
682 {
683   char ed1[50];
684   ListContext lctx(jcr, this, sendit, NF_LIST);
685 
686   DbLock(this);
687 
688   /*
689    * Stupid MySQL is NON-STANDARD !
690    */
691   if (GetTypeIndex() == SQL_TYPE_MYSQL) {
692     Mmsg(cmd,
693          "SELECT CONCAT(Path.Path,Name) AS Filename "
694          "FROM (SELECT PathId, Name FROM File WHERE JobId=%s "
695          "UNION ALL "
696          "SELECT PathId, Name "
697          "FROM BaseFiles JOIN File "
698          "ON (BaseFiles.FileId = File.FileId) "
699          "WHERE BaseFiles.JobId = %s"
700          ") AS F, Path "
701          "WHERE Path.PathId=F.PathId",
702          edit_int64(jobid, ed1), ed1);
703   } else {
704     Mmsg(cmd,
705          "SELECT Path.Path||Name AS Filename "
706          "FROM (SELECT PathId, Name FROM File WHERE JobId=%s "
707          "UNION ALL "
708          "SELECT PathId, Name "
709          "FROM BaseFiles JOIN File "
710          "ON (BaseFiles.FileId = File.FileId) "
711          "WHERE BaseFiles.JobId = %s"
712          ") AS F, Path "
713          "WHERE Path.PathId=F.PathId",
714          edit_int64(jobid, ed1), ed1);
715   }
716 
717   sendit->ArrayStart("filenames");
718   if (!BigSqlQuery(cmd, ::ListResult, &lctx)) { goto bail_out; }
719   sendit->ArrayEnd("filenames");
720 
721   SqlFreeResult();
722 
723 bail_out:
724   DbUnlock(this);
725 }
726 
ListBaseFilesForJob(JobControlRecord * jcr,JobId_t jobid,OutputFormatter * sendit)727 void BareosDb::ListBaseFilesForJob(JobControlRecord* jcr,
728                                    JobId_t jobid,
729                                    OutputFormatter* sendit)
730 {
731   char ed1[50];
732   ListContext lctx(jcr, this, sendit, NF_LIST);
733 
734   DbLock(this);
735 
736   /*
737    * Stupid MySQL is NON-STANDARD !
738    */
739   if (GetTypeIndex() == SQL_TYPE_MYSQL) {
740     Mmsg(cmd,
741          "SELECT CONCAT(Path.Path,File.Name) AS Filename "
742          "FROM BaseFiles, File, Path "
743          "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
744          "AND BaseFiles.FileId = File.FileId "
745          "AND Path.PathId=File.PathId",
746          edit_int64(jobid, ed1));
747   } else {
748     Mmsg(cmd,
749          "SELECT Path.Path||File.Name AS Filename "
750          "FROM BaseFiles, File, Path "
751          "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
752          "AND BaseFiles.FileId = File.FileId "
753          "AND Path.PathId=File.PathId",
754          edit_int64(jobid, ed1));
755   }
756 
757   sendit->ArrayStart("files");
758   if (!BigSqlQuery(cmd, ::ListResult, &lctx)) { goto bail_out; }
759   sendit->ArrayEnd("files");
760 
761   SqlFreeResult();
762 
763 bail_out:
764   DbUnlock(this);
765 }
766 
767 /**
768  * List fileset
769  */
ListFilesets(JobControlRecord * jcr,JobDbRecord * jr,const char * range,OutputFormatter * sendit,e_list_type type)770 void BareosDb::ListFilesets(JobControlRecord* jcr,
771                             JobDbRecord* jr,
772                             const char* range,
773                             OutputFormatter* sendit,
774                             e_list_type type)
775 {
776   char esc[MAX_ESCAPE_NAME_LENGTH];
777 
778   DbLock(this);
779   if (jr->Name[0] != 0) {
780     EscapeString(jcr, esc, jr->Name, strlen(jr->Name));
781     Mmsg(cmd,
782          "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
783          "CreateTime, FileSetText "
784          "FROM Job, FileSet "
785          "WHERE Job.FileSetId = FileSet.FileSetId "
786          "AND Job.Name='%s'%s",
787          esc, range);
788   } else if (jr->Job[0] != 0) {
789     EscapeString(jcr, esc, jr->Job, strlen(jr->Job));
790     Mmsg(cmd,
791          "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
792          "CreateTime, FileSetText "
793          "FROM Job, FileSet "
794          "WHERE Job.FileSetId = FileSet.FileSetId "
795          "AND Job.Name='%s'%s",
796          esc, range);
797   } else if (jr->JobId != 0) {
798     Mmsg(cmd,
799          "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
800          "CreateTime, FileSetText "
801          "FROM Job, FileSet "
802          "WHERE Job.FileSetId = FileSet.FileSetId "
803          "AND Job.JobId='%s'%s",
804          edit_int64(jr->JobId, esc), range);
805   } else if (jr->FileSetId != 0) {
806     Mmsg(cmd,
807          "SELECT FileSetId, FileSet, MD5, CreateTime, FileSetText "
808          "FROM FileSet "
809          "WHERE  FileSetId=%s",
810          edit_int64(jr->FileSetId, esc));
811   } else { /* all records */
812     Mmsg(cmd,
813          "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
814          "CreateTime, FileSetText "
815          "FROM FileSet ORDER BY FileSetId ASC%s",
816          range);
817   }
818 
819   if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
820   sendit->ArrayStart("filesets");
821   ListResult(jcr, sendit, type);
822   sendit->ArrayEnd("filesets");
823 
824   SqlFreeResult();
825 
826 bail_out:
827   DbUnlock(this);
828 }
829 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || \
830           HAVE_DBI */
831