1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2002-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2020 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, April MMII
25 */
26 /**
27 * @file
28 * User Agent Commands
29 *
30 * These are "dot" commands, i.e. commands preceded
31 * by a period. These commands are meant to be used
32 * by a program, so there is no prompting, and the
33 * returned results are (supposed to be) predictable.
34 */
35
36 #include "include/bareos.h"
37 #include "dird.h"
38 #include "dird/jcr_private.h"
39 #include "dird/job.h"
40 #include "dird/dird_globals.h"
41 #include "dird/sd_cmds.h"
42 #include "dird/fd_cmds.h"
43 #include "cats/bvfs.h"
44 #include "findlib/find.h"
45 #include "dird/ua_db.h"
46 #include "dird/ua_select.h"
47 #include "dird/storage.h"
48 #include "include/auth_protocol_types.h"
49 #include "lib/edit.h"
50 #include "lib/parse_conf.h"
51 #include "lib/util.h"
52
53 namespace directordaemon {
54
55 /* Imported variables */
56 extern struct s_jl joblevels[];
57 extern struct s_jt jobtypes[];
58 extern struct s_kw ActionOnPurgeOptions[];
59 extern struct s_kw VolumeStatus[];
60
61 /* Imported functions */
62
63 #ifdef DEVELOPER
64 /* ua_cmds.c */
65 extern bool quit_cmd(UaContext* ua, const char* cmd);
66 #endif
67
68 /* ua_output.c */
69 extern void DoMessages(UaContext* ua, const char* cmd);
70
71 struct authorization_mapping {
72 const char* type;
73 int acl_type;
74 };
75
76 static authorization_mapping authorization_mappings[] = {
77 {"job", Job_ACL},
78 {"client", Client_ACL},
79 {"storage", Storage_ACL},
80 {"schedule", Schedule_ACL},
81 {"pool", Pool_ACL},
82 {"cmd", Command_ACL},
83 {"fileset", FileSet_ACL},
84 {"catalog", Catalog_ACL},
85 {NULL, 0},
86 };
87
DotAuthorizedCmd(UaContext * ua,const char * cmd)88 bool DotAuthorizedCmd(UaContext* ua, const char* cmd)
89 {
90 bool retval = false;
91
92 for (int i = 1; i < ua->argc; i++) {
93 for (int j = 0; authorization_mappings[j].type; j++) {
94 if (Bstrcasecmp(ua->argk[i], authorization_mappings[j].type)) {
95 if (ua->argv[i]
96 && ua->AclAccessOk(authorization_mappings[j].acl_type, ua->argv[i],
97 false)) {
98 retval = true;
99 } else {
100 retval = false;
101 }
102 }
103 }
104 }
105
106 ua->send->ObjectStart(".authorized");
107 if (retval) {
108 ua->send->ObjectKeyValueBool("authorized", retval, "authorized\n");
109 } else {
110 ua->send->ObjectKeyValueBool("authorized", retval, "not authorized\n");
111 }
112 ua->send->ObjectEnd(".authorized");
113
114 return retval;
115 }
116
DotBvfsUpdateCmd(UaContext * ua,const char * cmd)117 bool DotBvfsUpdateCmd(UaContext* ua, const char* cmd)
118 {
119 int pos;
120
121 if (!OpenClientDb(ua, true)) { return 1; }
122 pos = FindArgWithValue(ua, "jobid");
123 if (pos != -1 && Is_a_number_list(ua->argv[pos])) {
124 if (!ua->db->BvfsUpdatePathHierarchyCache(ua->jcr, ua->argv[pos])) {
125 ua->ErrorMsg("ERROR: BVFS reported a problem for %s\n", ua->argv[pos]);
126 }
127 } else {
128 /* update cache for all jobids */
129 ua->db->BvfsUpdateCache(ua->jcr);
130 }
131
132 return true;
133 }
134
DotBvfsClearCacheCmd(UaContext * ua,const char * cmd)135 bool DotBvfsClearCacheCmd(UaContext* ua, const char* cmd)
136 {
137 if (!OpenClientDb(ua, true)) { return 1; }
138
139 int pos = FindArg(ua, "yes");
140 if (pos != -1) {
141 Bvfs fs(ua->jcr, ua->db);
142 fs.clear_cache();
143 ua->InfoMsg("OK\n");
144 } else {
145 ua->ErrorMsg("Can't find 'yes' argument\n");
146 }
147
148 return true;
149 }
150
BvfsStat(UaContext * ua,char * lstat,int32_t * LinkFI)151 static int BvfsStat(UaContext* ua, char* lstat, int32_t* LinkFI)
152 {
153 struct stat statp;
154 char en1[30], en2[30];
155
156 memset(&statp, 0, sizeof(struct stat));
157 DecodeStat(lstat, &statp, sizeof(statp), LinkFI);
158
159 ua->send->ObjectStart("stat");
160 ua->send->ObjectKeyValue("dev", statp.st_dev);
161 ua->send->ObjectKeyValue("ino", statp.st_ino);
162 ua->send->ObjectKeyValue("mode", statp.st_mode);
163 ua->send->ObjectKeyValue("nlink", statp.st_nlink);
164 ua->send->ObjectKeyValue("uid", statp.st_uid);
165 ua->send->ObjectKeyValue("gid", statp.st_gid);
166 ua->send->ObjectKeyValue(
167 "user", ua->guid->uid_to_name(statp.st_uid, en1, sizeof(en1)));
168 ua->send->ObjectKeyValue(
169 "group", ua->guid->gid_to_name(statp.st_gid, en2, sizeof(en2)));
170 ua->send->ObjectKeyValue("rdev", statp.st_rdev);
171 ua->send->ObjectKeyValue("size", statp.st_size);
172 ua->send->ObjectKeyValue("atime", statp.st_atime);
173 ua->send->ObjectKeyValue("mtime", statp.st_mtime);
174 ua->send->ObjectKeyValue("ctime", statp.st_ctime);
175 ua->send->ObjectEnd("stat");
176
177 return 0;
178 }
179
BvfsResultHandler(void * ctx,int fields,char ** row)180 static int BvfsResultHandler(void* ctx, int fields, char** row)
181 {
182 UaContext* ua = (UaContext*)ctx;
183 char* fileid = row[BVFS_FileId];
184 char* lstat = row[BVFS_LStat];
185 char* jobid = row[BVFS_JobId];
186
187 char empty[] = "A A A A A A A A A A A A A A";
188 char zero[] = "0";
189 int32_t LinkFI = 0;
190
191 /*
192 * We need to deal with non existant path
193 */
194 if (!fileid || !Is_a_number(fileid)) {
195 lstat = empty;
196 jobid = zero;
197 fileid = zero;
198 }
199
200 Dmsg1(100, "type=%s\n", row[0]);
201 if (BvfsIsDir(row)) {
202 char* path = bvfs_basename_dir(row[BVFS_Name]);
203
204 ua->send->ObjectStart();
205 ua->send->ObjectKeyValue("Type", row[BVFS_Type]);
206 ua->send->ObjectKeyValue("PathId", str_to_uint64(row[BVFS_PathId]),
207 "%lld\t");
208 ua->send->ObjectKeyValue("FileId", str_to_uint64(fileid), "%lld\t");
209 ua->send->ObjectKeyValue("JobId", str_to_uint64(jobid), "%lld\t");
210 ua->send->ObjectKeyValue("lstat", lstat, "%s\t");
211 ua->send->ObjectKeyValue("Name", path, "%s\n");
212 ua->send->ObjectKeyValue("Fullpath", row[BVFS_Name]);
213 BvfsStat(ua, lstat, &LinkFI);
214 ua->send->ObjectKeyValue("LinkFileIndex", LinkFI);
215 ua->send->ObjectEnd();
216 } else if (BvfsIsVersion(row)) {
217 ua->send->ObjectStart();
218 ua->send->ObjectKeyValue("Type", row[BVFS_Type]);
219 ua->send->ObjectKeyValue("PathId", str_to_uint64(row[BVFS_PathId]),
220 "%lld\t");
221 ua->send->ObjectKeyValue("FileId", str_to_uint64(fileid), "%lld\t");
222 ua->send->ObjectKeyValue("JobId", str_to_uint64(jobid), "%lld\t");
223 ua->send->ObjectKeyValue("lstat", lstat, "%s\t");
224 ua->send->ObjectKeyValue("MD5", row[BVFS_Md5], "%s\t");
225 ua->send->ObjectKeyValue("VolumeName", row[BVFS_VolName], "%s\t");
226 ua->send->ObjectKeyValue("VolumeInChanger",
227 str_to_uint64(row[BVFS_VolInchanger]), "%lld\n");
228 BvfsStat(ua, lstat, &LinkFI);
229 ua->send->ObjectEnd();
230 } else if (BvfsIsFile(row)) {
231 ua->send->ObjectStart();
232 ua->send->ObjectKeyValue("Type", row[BVFS_Type]);
233 ua->send->ObjectKeyValue("PathId", str_to_uint64(row[BVFS_PathId]),
234 "%lld\t");
235 ua->send->ObjectKeyValue("FileId", str_to_uint64(fileid), "%lld\t");
236 ua->send->ObjectKeyValue("JobId", str_to_uint64(jobid), "%lld\t");
237 ua->send->ObjectKeyValue("lstat", lstat, "%s\t");
238 ua->send->ObjectKeyValue("Name", row[BVFS_Name], "%s\n");
239 BvfsStat(ua, lstat, &LinkFI);
240 ua->send->ObjectKeyValue("LinkFileIndex", LinkFI);
241 ua->send->ObjectEnd();
242 }
243
244 return 0;
245 }
246
BvfsParseArgVersion(UaContext * ua,char ** client,char ** fname,bool * versions,bool * copies)247 static inline bool BvfsParseArgVersion(UaContext* ua,
248 char** client,
249 char** fname,
250 bool* versions,
251 bool* copies)
252 {
253 *fname = NULL;
254 *client = NULL;
255 *versions = false;
256 *copies = false;
257
258 for (int i = 1; i < ua->argc; i++) {
259 if (Bstrcasecmp(ua->argk[i], NT_("name"))
260 || Bstrcasecmp(ua->argk[i], NT_("fname"))
261 || Bstrcasecmp(ua->argk[i], NT_("filename"))) {
262 *fname = ua->argv[i];
263 }
264
265 if (Bstrcasecmp(ua->argk[i], NT_("client"))) { *client = ua->argv[i]; }
266
267 if (copies && Bstrcasecmp(ua->argk[i], NT_("copies"))) { *copies = true; }
268
269 if (versions && Bstrcasecmp(ua->argk[i], NT_("versions"))) {
270 *versions = true;
271 }
272 }
273
274 return (*client && *fname);
275 }
276
BvfsParseArg(UaContext * ua,DBId_t * pathid,char ** path,char ** jobid,int * limit,int * offset)277 static bool BvfsParseArg(UaContext* ua,
278 DBId_t* pathid,
279 char** path,
280 char** jobid,
281 int* limit,
282 int* offset)
283 {
284 *pathid = 0;
285 *limit = 2000;
286 *offset = 0;
287 *path = NULL;
288 *jobid = NULL;
289
290 for (int i = 1; i < ua->argc; i++) {
291 if (Bstrcasecmp(ua->argk[i], NT_("pathid"))) {
292 if (ua->argv[i] && Is_a_number(ua->argv[i])) {
293 *pathid = str_to_int64(ua->argv[i]);
294 }
295 }
296
297 if (Bstrcasecmp(ua->argk[i], NT_("path"))) { *path = ua->argv[i]; }
298
299 if (Bstrcasecmp(ua->argk[i], NT_("jobid"))) {
300 if (ua->argv[i] && Is_a_number_list(ua->argv[i])) {
301 *jobid = ua->argv[i];
302 }
303 }
304
305 if (Bstrcasecmp(ua->argk[i], NT_("limit"))) {
306 if (ua->argv[i] && Is_a_number(ua->argv[i])) {
307 *limit = str_to_int64(ua->argv[i]);
308 }
309 }
310
311 if (Bstrcasecmp(ua->argk[i], NT_("offset"))) {
312 if (ua->argv[i] && Is_a_number(ua->argv[i])) {
313 *offset = str_to_int64(ua->argv[i]);
314 }
315 }
316 }
317
318 if (!((*pathid || *path) && *jobid)) { return false; }
319
320 if (!OpenClientDb(ua, true)) { return false; }
321
322 return true;
323 }
324
325 /**
326 * This checks to see if the JobId given is allowed under the current
327 * ACLs e.g. comparing the JobName against the Job_ACL and the client
328 * against the Client_ACL.
329 */
BvfsValidateJobid(UaContext * ua,const char * jobid,bool audit_event)330 static inline bool BvfsValidateJobid(UaContext* ua,
331 const char* jobid,
332 bool audit_event)
333 {
334 JobDbRecord jr;
335 ClientDbRecord cr;
336 bool retval = false;
337
338 jr.JobId = str_to_int64(jobid);
339
340 if (ua->db->GetJobRecord(ua->jcr, &jr)) {
341 if (!ua->AclAccessOk(Job_ACL, jr.Name, audit_event)) { goto bail_out; }
342
343 if (jr.ClientId) {
344 cr.ClientId = jr.ClientId;
345 if (ua->db->GetClientRecord(ua->jcr, &cr)) {
346 if (!ua->AclAccessOk(Client_ACL, cr.Name, audit_event)) {
347 goto bail_out;
348 }
349 }
350 }
351
352 retval = true;
353 }
354
355 bail_out:
356 return retval;
357 }
358
359 /**
360 * This returns in filtered_jobids the list of allowed jobids in the
361 * jobids variable under the current ACLs e.g. using BvfsValidateJobid().
362 */
BvfsValidateJobids(UaContext * ua,const char * jobids,PoolMem & filtered_jobids,bool audit_event)363 static bool BvfsValidateJobids(UaContext* ua,
364 const char* jobids,
365 PoolMem& filtered_jobids,
366 bool audit_event)
367 {
368 int cnt = 0;
369 char *cur_id, *bp;
370 PoolMem temp(PM_FNAME);
371
372 PmStrcpy(temp, jobids);
373 PmStrcpy(filtered_jobids, "");
374
375 cur_id = temp.c_str();
376 while (cur_id && strlen(cur_id)) {
377 bp = strchr(cur_id, ',');
378 if (bp) { *bp++ = '\0'; }
379
380 /*
381 * See if this JobId is allowed under the current ACLs.
382 */
383 if (BvfsValidateJobid(ua, cur_id, audit_event)) {
384 if (!cnt) {
385 PmStrcpy(filtered_jobids, cur_id);
386 } else {
387 PmStrcat(filtered_jobids, ",");
388 PmStrcat(filtered_jobids, cur_id);
389 }
390 cnt++;
391 } else {
392 Dmsg1(200, "Removing jobid from list, %s\n", cur_id);
393 }
394
395 cur_id = bp;
396 }
397
398 return (cnt > 0) ? true : false;
399 }
400
401 /**
402 * .bvfs_cleanup path=b2XXXXX
403 */
DotBvfsCleanupCmd(UaContext * ua,const char * cmd)404 bool DotBvfsCleanupCmd(UaContext* ua, const char* cmd)
405 {
406 int i;
407
408 if ((i = FindArgWithValue(ua, "path")) < 0) {
409 ua->ErrorMsg("Can't find path argument\n");
410 return false; /* not enough param */
411 }
412
413 if (!OpenClientDb(ua, true)) { return false; }
414
415 Bvfs fs(ua->jcr, ua->db);
416 fs.DropRestoreList(ua->argv[i]);
417
418 return true;
419 }
420
421 /**
422 * .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
423 */
DotBvfsRestoreCmd(UaContext * ua,const char * cmd)424 bool DotBvfsRestoreCmd(UaContext* ua, const char* cmd)
425 {
426 DBId_t pathid = 0;
427 char* empty = (char*)"";
428 int limit = 2000, offset = 0;
429 int i = 0;
430 char *path = NULL, *jobid = NULL;
431 char *fileid, *dirid, *hardlink;
432 PoolMem filtered_jobids(PM_FNAME);
433
434 fileid = dirid = hardlink = empty;
435 if (!BvfsParseArg(ua, &pathid, &path, &jobid, &limit, &offset)) {
436 ua->ErrorMsg("Can't find jobid, pathid or path argument\n");
437 return false; /* not enough param */
438 }
439
440 if (!BvfsValidateJobids(ua, jobid, filtered_jobids, true)) {
441 ua->ErrorMsg(_("Unauthorized command from this console.\n"));
442 return false;
443 }
444
445 Bvfs fs(ua->jcr, ua->db);
446 fs.SetJobids(filtered_jobids.c_str());
447
448 if ((i = FindArgWithValue(ua, "fileid")) >= 0) { fileid = ua->argv[i]; }
449 if ((i = FindArgWithValue(ua, "dirid")) >= 0) { dirid = ua->argv[i]; }
450 if ((i = FindArgWithValue(ua, "hardlink")) >= 0) { hardlink = ua->argv[i]; }
451
452 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
453 ua->SendMsg("OK\n");
454 } else {
455 ua->ErrorMsg("Can't create restore list\n");
456 }
457
458 return true;
459 }
460
461 /**
462 * .bvfs_lsfiles jobid=1,2,3,4 path=/
463 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
464 */
DotBvfsLsfilesCmd(UaContext * ua,const char * cmd)465 bool DotBvfsLsfilesCmd(UaContext* ua, const char* cmd)
466 {
467 int i;
468 DBId_t pathid = 0;
469 char* pattern = NULL;
470 int limit = 2000, offset = 0;
471 char *path = NULL, *jobid = NULL;
472 PoolMem filtered_jobids(PM_FNAME);
473
474 if (!BvfsParseArg(ua, &pathid, &path, &jobid, &limit, &offset)) {
475 ua->ErrorMsg("Can't find jobid, pathid or path argument\n");
476 return false; /* not enough param */
477 }
478
479 if (!BvfsValidateJobids(ua, jobid, filtered_jobids, true)) {
480 ua->ErrorMsg(_("Unauthorized command from this console.\n"));
481 return false;
482 }
483
484 if ((i = FindArgWithValue(ua, "pattern")) >= 0) { pattern = ua->argv[i]; }
485
486 if (!ua->guid) { ua->guid = new_guid_list(); }
487
488 Bvfs fs(ua->jcr, ua->db);
489 fs.SetJobids(filtered_jobids.c_str());
490 fs.SetHandler(BvfsResultHandler, ua);
491 fs.SetLimit(limit);
492 if (pattern) { fs.SetPattern(pattern); }
493 if (pathid) {
494 fs.ChDir(pathid);
495 } else {
496 fs.ChDir(path);
497 }
498
499 fs.SetOffset(offset);
500
501 ua->send->ArrayStart("files");
502 fs.ls_files();
503 ua->send->ArrayEnd("files");
504
505 return true;
506 }
507
508 /**
509 * .bvfs_lsdirs jobid=1,2,3,4 path=
510 * .bvfs_lsdirs jobid=1,2,3,4 path=/
511 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
512 */
DotBvfsLsdirsCmd(UaContext * ua,const char * cmd)513 bool DotBvfsLsdirsCmd(UaContext* ua, const char* cmd)
514 {
515 DBId_t pathid = 0;
516 int limit = 2000, offset = 0;
517 char *path = NULL, *jobid = NULL;
518 PoolMem filtered_jobids(PM_FNAME);
519
520 if (!BvfsParseArg(ua, &pathid, &path, &jobid, &limit, &offset)) {
521 ua->ErrorMsg("Can't find jobid, pathid or path argument\n");
522 return true; /* not enough param */
523 }
524
525 if (!BvfsValidateJobids(ua, jobid, filtered_jobids, true)) {
526 ua->ErrorMsg(_("Unauthorized command from this console.\n"));
527 return false;
528 }
529
530 if (!ua->guid) { ua->guid = new_guid_list(); }
531
532 Bvfs fs(ua->jcr, ua->db);
533 fs.SetJobids(filtered_jobids.c_str());
534
535 if (pathid) {
536 fs.ChDir(pathid);
537 } else {
538 if (!fs.ChDir(path)) {
539 /* path could not be found. Giving up. */
540 return false;
541 }
542 }
543
544 fs.SetHandler(BvfsResultHandler, ua);
545 fs.SetOffset(offset);
546 fs.SetLimit(limit);
547
548 ua->send->ArrayStart("directories");
549 fs.ls_dirs();
550 ua->send->ArrayEnd("directories");
551
552 return true;
553 }
554
555 /**
556 * .bvfs_versions jobid=0 client=<client-name> filename=<file-name>
557 * pathid=<number> [copies] [versions]
558 *
559 * jobid isn't used.
560 * versions is set, but not used.
561 */
DotBvfsVersionsCmd(UaContext * ua,const char * cmd)562 bool DotBvfsVersionsCmd(UaContext* ua, const char* cmd)
563 {
564 DBId_t pathid = 0;
565 int limit = 2000, offset = 0;
566 char *path = NULL, *jobid = NULL, *client = NULL, *fname = NULL;
567 bool copies = false, versions = false;
568
569 if (!BvfsParseArg(ua, &pathid, &path, &jobid, &limit, &offset)) {
570 ua->ErrorMsg("Can't find jobid, pathid or path argument\n");
571 return false; /* not enough param */
572 }
573
574 if (!BvfsParseArgVersion(ua, &client, &fname, &versions, &copies)) {
575 ua->ErrorMsg("Can't find client or fname argument\n");
576 return false; /* not enough param */
577 }
578
579 if (!ua->AclAccessOk(Client_ACL, client)) {
580 ua->ErrorMsg(_("Unauthorized command from this console.\n"));
581 return false;
582 }
583
584 if (!ua->guid) { ua->guid = new_guid_list(); }
585
586 Bvfs fs(ua->jcr, ua->db);
587 fs.SetSeeAllVersions(versions);
588 fs.SetSeeCopies(copies);
589 fs.SetHandler(BvfsResultHandler, ua);
590 fs.SetLimit(limit);
591 fs.SetOffset(offset);
592 ua->send->ArrayStart("versions");
593 if (pathid) {
594 fs.GetAllFileVersions(pathid, fname, client);
595 } else {
596 fs.GetAllFileVersions(path, fname, client);
597 }
598 ua->send->ArrayEnd("versions");
599
600 return true;
601 }
602
603 /**
604 * .bvfs_get_jobids jobid=1
605 * -> returns needed jobids to restore
606 * .bvfs_get_jobids jobid=1 all
607 * -> returns needed jobids to restore with all filesets a JobId=1 time
608 * .bvfs_get_jobids ujobid=JobName
609 * -> returns needed jobids to restore
610 */
DotBvfsGetJobidsCmd(UaContext * ua,const char * cmd)611 bool DotBvfsGetJobidsCmd(UaContext* ua, const char* cmd)
612 {
613 int pos;
614 JobDbRecord jr;
615 char ed1[50];
616 dbid_list ids; /* Store all FileSetIds for this client */
617 PoolMem query;
618 db_list_ctx jobids, tempids;
619 PoolMem filtered_jobids(PM_FNAME);
620
621 if (!OpenClientDb(ua, true)) { return true; }
622
623 if ((pos = FindArgWithValue(ua, "ujobid")) >= 0) {
624 bstrncpy(jr.Job, ua->argv[pos], sizeof(jr.Job));
625 } else if ((pos = FindArgWithValue(ua, "jobid")) >= 0) {
626 jr.JobId = str_to_int64(ua->argv[pos]);
627 } else {
628 ua->ErrorMsg(_("Can't find ujobid or jobid argument\n"));
629 return false;
630 }
631
632 if (!ua->db->GetJobRecord(ua->jcr, &jr)) {
633 ua->ErrorMsg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
634 ua->argv[pos], ua->db->strerror());
635 return false;
636 }
637
638 /*
639 * When in level base, we don't rely on any Full/Incr/Diff
640 */
641 if (jr.JobLevel == L_BASE) {
642 jobids.add(edit_int64(jr.JobId, ed1));
643 } else {
644 /*
645 * If we have the "all" option, we do a search on all defined fileset for
646 * this client
647 */
648 if (FindArg(ua, "all") > 0) {
649 ua->db->FillQuery(query, BareosDb::SQL_QUERY::uar_sel_filesetid,
650 edit_int64(jr.ClientId, ed1));
651 ua->db->GetQueryDbids(ua->jcr, query, ids);
652 } else {
653 ids.num_ids = 1;
654 ids.DBId[0] = jr.FileSetId;
655 }
656
657 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
658
659 /*
660 * Foreach different FileSet, we build a restore jobid list
661 */
662 for (int i = 0; i < ids.num_ids; i++) {
663 FileSetDbRecord fs;
664
665 /*
666 * Lookup the FileSet.
667 */
668 fs.FileSetId = ids.DBId[i];
669 if (!ua->db->GetFilesetRecord(ua->jcr, &fs)) { continue; }
670
671 /*
672 * Make sure the FileSet is allowed under the current ACLs.
673 */
674 if (!ua->AclAccessOk(FileSet_ACL, fs.FileSet, false)) { continue; }
675
676 /*
677 * Lookup the actual JobIds for the given fileset.
678 */
679 jr.FileSetId = fs.FileSetId;
680 if (!ua->db->AccurateGetJobids(ua->jcr, &jr, &tempids)) { return true; }
681 jobids.add(tempids);
682 }
683 }
684
685 BvfsValidateJobids(ua, jobids.GetAsString().c_str(), filtered_jobids, false);
686 switch (ua->api) {
687 case API_MODE_JSON: {
688 char *cur_id, *bp;
689
690 ua->send->ArrayStart("jobids");
691 cur_id = filtered_jobids.c_str();
692 while (cur_id && strlen(cur_id)) {
693 bp = strchr(cur_id, ',');
694 if (bp) { *bp++ = '\0'; }
695
696 ua->send->ObjectStart();
697 ua->send->ObjectKeyValue("id", cur_id, "%s\n");
698 ua->send->ObjectEnd();
699
700 cur_id = bp;
701 }
702 ua->send->ArrayEnd("jobids");
703 break;
704 }
705 default:
706 ua->SendMsg("%s\n", filtered_jobids.c_str());
707 break;
708 }
709
710 return true;
711 }
712
DotGetmsgsCmd(UaContext * ua,const char * cmd)713 bool DotGetmsgsCmd(UaContext* ua, const char* cmd)
714 {
715 if (console_msg_pending) { DoMessages(ua, cmd); }
716 return 1;
717 }
718
719 #ifdef DEVELOPER
DoStorageCmd(UaContext * ua,StorageResource * store,const char * cmd)720 static void DoStorageCmd(UaContext* ua, StorageResource* store, const char* cmd)
721 {
722 BareosSocket* sd;
723 JobControlRecord* jcr = ua->jcr;
724 UnifiedStorageResource lstore;
725
726 lstore.store = store;
727 PmStrcpy(lstore.store_source, _("unknown source"));
728 SetWstorage(jcr, &lstore);
729
730 if (!(sd = open_sd_bsock(ua))) {
731 ua->ErrorMsg(_("Could not open SD socket.\n"));
732 return;
733 }
734
735 Dmsg0(120, _("Connected to storage daemon\n"));
736 sd = jcr->store_bsock;
737 sd->fsend("%s", cmd);
738 if (sd->recv() >= 0) { ua->SendMsg("%s", sd->msg); }
739
740 CloseSdBsock(ua);
741 return;
742 }
743
DoClientCmd(UaContext * ua,ClientResource * client,const char * cmd)744 static void DoClientCmd(UaContext* ua, ClientResource* client, const char* cmd)
745 {
746 BareosSocket* fd;
747
748 /* Connect to File daemon */
749
750 ua->jcr->impl->res.client = client;
751 /* Try to connect for 15 seconds */
752 ua->SendMsg(_("Connecting to Client %s at %s:%d\n"), client->resource_name_,
753 client->address, client->FDport);
754 if (!ConnectToFileDaemon(ua->jcr, 1, 15, false, ua)) {
755 ua->ErrorMsg(_("Failed to connect to Client.\n"));
756 return;
757 }
758 Dmsg0(120, "Connected to file daemon\n");
759 fd = ua->jcr->file_bsock;
760 fd->fsend("%s", cmd);
761 if (fd->recv() >= 0) { ua->SendMsg("%s", fd->msg); }
762 fd->signal(BNET_TERMINATE);
763 fd->close();
764 ua->jcr->file_bsock = NULL;
765 return;
766 }
767
768 /**
769 * .die (seg fault)
770 * .exit (no arg => .quit)
771 */
DotAdminCmds(UaContext * ua,const char * cmd)772 bool DotAdminCmds(UaContext* ua, const char* cmd)
773 {
774 int i, a;
775 JobControlRecord* jcr = NULL;
776 bool dir = false;
777 bool result = true;
778 const char* remote_cmd;
779 StorageResource* store = NULL;
780 ClientResource* client = NULL;
781 bool do_deadlock = false;
782 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
783
784 if (strncmp(ua->argk[0], ".die", 4) == 0) {
785 if (FindArg(ua, "deadlock") > 0) {
786 do_deadlock = true;
787 remote_cmd = ".die deadlock";
788 } else {
789 remote_cmd = ".die";
790 }
791 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
792 remote_cmd = "exit";
793 } else {
794 ua->ErrorMsg(_("Unknown command: %s\n"), ua->argk[0]);
795 return true;
796 }
797
798 /*
799 * General debug?
800 */
801 for (i = 1; i < ua->argc; i++) {
802 if (Bstrcasecmp(ua->argk[i], "dir")
803 || Bstrcasecmp(ua->argk[i], "director")) {
804 dir = true;
805 }
806 if (Bstrcasecmp(ua->argk[i], "client") || Bstrcasecmp(ua->argk[i], "fd")) {
807 client = NULL;
808 if (ua->argv[i]) { client = ua->GetClientResWithName(ua->argv[i]); }
809 if (!client) { client = select_client_resource(ua); }
810 }
811
812 if (Bstrcasecmp(ua->argk[i], NT_("store"))
813 || Bstrcasecmp(ua->argk[i], NT_("storage"))
814 || Bstrcasecmp(ua->argk[i], NT_("sd"))) {
815 store = NULL;
816 if (ua->argv[i]) { store = ua->GetStoreResWithName(ua->argv[i]); }
817 if (!store) { store = get_storage_resource(ua); }
818 }
819 }
820
821 if (!dir && !store && !client) {
822 /*
823 * We didn't find an appropriate keyword above, so
824 * prompt the user.
825 */
826 StartPrompt(ua, _("Available daemons are: \n"));
827 AddPrompt(ua, _("Director"));
828 AddPrompt(ua, _("Storage"));
829 AddPrompt(ua, _("Client"));
830 switch (DoPrompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
831 case 0: /* Director */
832 dir = true;
833 break;
834 case 1:
835 store = get_storage_resource(ua);
836 break;
837 case 2:
838 client = select_client_resource(ua);
839 break;
840 default:
841 break;
842 }
843 }
844
845 if (store) {
846 switch (store->Protocol) {
847 case APT_NDMPV2:
848 case APT_NDMPV3:
849 case APT_NDMPV4:
850 ua->WarningMsg(_("Storage has non-native protocol.\n"));
851 break;
852 default:
853 DoStorageCmd(ua, store, remote_cmd);
854 break;
855 }
856 }
857
858 if (client) { DoClientCmd(ua, client, remote_cmd); }
859
860 if (dir) {
861 if (strncmp(remote_cmd, ".die", 4) == 0) {
862 if (do_deadlock) {
863 ua->SendMsg(_("The Director will generate a deadlock.\n"));
864 P(mutex);
865 P(mutex);
866 }
867 ua->SendMsg(_("The Director will segment fault.\n"));
868 a = jcr->JobId; /* ref NULL pointer */
869 jcr->JobId = 1000; /* another ref NULL pointer */
870 jcr->JobId = a;
871
872 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
873 quit_cmd(ua, cmd);
874 }
875 }
876
877 return result;
878 }
879 #else
880 /**
881 * Dummy routine for non-development version
882 */
DotAdminCmds(UaContext * ua,const char * cmd)883 bool DotAdminCmds(UaContext* ua, const char* cmd)
884 {
885 ua->ErrorMsg(_("Unknown command: %s\n"), ua->argk[0]);
886 return true;
887 }
888 #endif
889
DotJobdefsCmd(UaContext * ua,const char * cmd)890 bool DotJobdefsCmd(UaContext* ua, const char* cmd)
891 {
892 JobResource* jobdefs;
893
894 LockRes(my_config);
895 ua->send->ArrayStart("jobdefs");
896 foreach_res (jobdefs, R_JOBDEFS) {
897 if (ua->AclAccessOk(Job_ACL, jobdefs->resource_name_)) {
898 ua->send->ObjectStart();
899 ua->send->ObjectKeyValue("name", jobdefs->resource_name_, "%s\n");
900 ua->send->ObjectEnd();
901 }
902 }
903 ua->send->ArrayEnd("jobdefs");
904 UnlockRes(my_config);
905
906 return true;
907 }
908
909 /**
910 * Can use an argument to filter on JobType
911 * .jobs [type=B]
912 */
DotJobsCmd(UaContext * ua,const char * cmd)913 bool DotJobsCmd(UaContext* ua, const char* cmd)
914 {
915 int pos;
916 JobResource* job;
917 bool enabled;
918 bool disabled;
919 uint32_t type = 0;
920
921 if ((pos = FindArgWithValue(ua, "type")) >= 0) { type = ua->argv[pos][0]; }
922
923 enabled = FindArg(ua, NT_("enabled")) >= 0;
924 disabled = FindArg(ua, NT_("disabled")) >= 0;
925
926 LockRes(my_config);
927 ua->send->ArrayStart("jobs");
928 foreach_res (job, R_JOB) {
929 if (!type || type == job->JobType) {
930 if (ua->AclAccessOk(Job_ACL, job->resource_name_)) {
931 if (enabled && !job->enabled) { continue; }
932 if (disabled && job->enabled) { continue; }
933
934 ua->send->ObjectStart();
935 ua->send->ObjectKeyValue("name", job->resource_name_, "%s\n");
936 ua->send->ObjectKeyValueBool("enabled", job->enabled);
937 ua->send->ObjectEnd();
938 }
939 }
940 }
941 ua->send->ArrayEnd("jobs");
942 UnlockRes(my_config);
943
944 return true;
945 }
946
DotJobstatusCmd(UaContext * ua,const char * cmd)947 bool DotJobstatusCmd(UaContext* ua, const char* cmd)
948 {
949 bool retval = false;
950 PoolMem select;
951 PoolMem where;
952
953 if (ua->argv[0]) {
954 if (strlen(ua->argv[0]) == 1) {
955 Mmsg(where, "WHERE JobStatus = '%c' ", ua->argv[0][0]);
956 } else {
957 ua->ErrorMsg(
958 _("Unknown JobStatus '%s'. JobStatus must be a single character.\n"),
959 ua->argv[0]);
960 return false;
961 }
962 }
963
964 ua->db->FillQuery(select, BareosDb::SQL_QUERY::get_jobstatus_details,
965 where.c_str());
966
967 if (!OpenClientDb(ua)) { return false; }
968
969 ua->send->ArrayStart("jobstatus");
970 retval = ua->db->ListSqlQuery(ua->jcr, select.c_str(), ua->send, HORZ_LIST,
971 false);
972 ua->send->ArrayEnd("jobstatus");
973
974 return retval;
975 }
976
DotFilesetsCmd(UaContext * ua,const char * cmd)977 bool DotFilesetsCmd(UaContext* ua, const char* cmd)
978 {
979 FilesetResource* fs;
980
981 LockRes(my_config);
982 ua->send->ArrayStart("filesets");
983 foreach_res (fs, R_FILESET) {
984 if (ua->AclAccessOk(FileSet_ACL, fs->resource_name_)) {
985 ua->send->ObjectStart();
986 ua->send->ObjectKeyValue("name", fs->resource_name_, "%s\n");
987 ua->send->ObjectEnd();
988 }
989 }
990 ua->send->ArrayEnd("filesets");
991 UnlockRes(my_config);
992
993 return true;
994 }
995
DotCatalogsCmd(UaContext * ua,const char * cmd)996 bool DotCatalogsCmd(UaContext* ua, const char* cmd)
997 {
998 CatalogResource* cat;
999
1000 LockRes(my_config);
1001 ua->send->ArrayStart("catalogs");
1002 foreach_res (cat, R_CATALOG) {
1003 if (ua->AclAccessOk(Catalog_ACL, cat->resource_name_)) {
1004 ua->send->ObjectStart();
1005 ua->send->ObjectKeyValue("name", cat->resource_name_, "%s\n");
1006 ua->send->ObjectEnd();
1007 }
1008 }
1009 ua->send->ArrayEnd("catalogs");
1010 UnlockRes(my_config);
1011
1012 return true;
1013 }
1014
DotClientsCmd(UaContext * ua,const char * cmd)1015 bool DotClientsCmd(UaContext* ua, const char* cmd)
1016 {
1017 bool enabled;
1018 bool disabled;
1019 ClientResource* client;
1020
1021 enabled = FindArg(ua, NT_("enabled")) >= 0;
1022 disabled = FindArg(ua, NT_("disabled")) >= 0;
1023
1024 LockRes(my_config);
1025 ua->send->ArrayStart("clients");
1026 foreach_res (client, R_CLIENT) {
1027 if (ua->AclAccessOk(Client_ACL, client->resource_name_)) {
1028 if (enabled && !client->enabled) { continue; }
1029 if (disabled && client->enabled) { continue; }
1030
1031 ua->send->ObjectStart();
1032 ua->send->ObjectKeyValue("name", client->resource_name_, "%s\n");
1033 ua->send->ObjectKeyValueBool("enabled", client->enabled);
1034 ua->send->ObjectEnd();
1035 }
1036 }
1037 ua->send->ArrayEnd("clients");
1038 UnlockRes(my_config);
1039
1040 return true;
1041 }
1042
DotConsolesCmd(UaContext * ua,const char * cmd)1043 bool DotConsolesCmd(UaContext* ua, const char* cmd)
1044 {
1045 ConsoleResource* console;
1046
1047 LockRes(my_config);
1048 ua->send->ArrayStart("consoles");
1049 foreach_res (console, R_CONSOLE) {
1050 ua->send->ObjectStart();
1051 ua->send->ObjectKeyValue("name", console->resource_name_, "%s\n");
1052 ua->send->ObjectEnd();
1053 }
1054 ua->send->ArrayEnd("consoles");
1055 UnlockRes(my_config);
1056
1057 return true;
1058 }
1059
DotUsersCmd(UaContext * ua,const char * cmd)1060 bool DotUsersCmd(UaContext* ua, const char* cmd)
1061 {
1062 UserResource* user;
1063
1064 LockRes(my_config);
1065 ua->send->ArrayStart("users");
1066 foreach_res (user, R_USER) {
1067 ua->send->ObjectStart();
1068 ua->send->ObjectKeyValue("name", user->resource_name_, "%s\n");
1069 ua->send->ObjectEnd();
1070 }
1071 ua->send->ArrayEnd("users");
1072 UnlockRes(my_config);
1073
1074 return true;
1075 }
1076
DotMsgsCmd(UaContext * ua,const char * cmd)1077 bool DotMsgsCmd(UaContext* ua, const char* cmd)
1078 {
1079 MessagesResource* msgs = NULL;
1080
1081 LockRes(my_config);
1082 ua->send->ArrayStart("messages");
1083 foreach_res (msgs, R_MSGS) {
1084 ua->send->ObjectStart();
1085 ua->send->ObjectKeyValue("text", msgs->resource_name_, "%s\n");
1086 ua->send->ObjectEnd();
1087 }
1088 ua->send->ArrayEnd("messages");
1089 UnlockRes(my_config);
1090
1091 return true;
1092 }
1093
DotPoolsCmd(UaContext * ua,const char * cmd)1094 bool DotPoolsCmd(UaContext* ua, const char* cmd)
1095 {
1096 int pos, length;
1097 PoolResource* pool;
1098
1099 pos = FindArgWithValue(ua, "type");
1100 if (pos >= 0) {
1101 length = strlen(ua->argv[pos]);
1102 } else {
1103 length = 0;
1104 }
1105
1106 LockRes(my_config);
1107 ua->send->ArrayStart("pools");
1108 foreach_res (pool, R_POOL) {
1109 if (ua->AclAccessOk(Pool_ACL, pool->resource_name_)) {
1110 if (pos == -1 || bstrncasecmp(pool->pool_type, ua->argv[pos], length)) {
1111 ua->send->ObjectStart();
1112 ua->send->ObjectKeyValue("name", pool->resource_name_, "%s\n");
1113 ua->send->ObjectEnd();
1114 }
1115 }
1116 }
1117 ua->send->ArrayEnd("pools");
1118 UnlockRes(my_config);
1119
1120 return true;
1121 }
1122
DotStorageCmd(UaContext * ua,const char * cmd)1123 bool DotStorageCmd(UaContext* ua, const char* cmd)
1124 {
1125 bool enabled;
1126 bool disabled;
1127 StorageResource* store;
1128
1129 enabled = FindArg(ua, NT_("enabled")) >= 0;
1130 disabled = FindArg(ua, NT_("disabled")) >= 0;
1131
1132 LockRes(my_config);
1133 ua->send->ArrayStart("storages");
1134 foreach_res (store, R_STORAGE) {
1135 if (ua->AclAccessOk(Storage_ACL, store->resource_name_)) {
1136 if (enabled && !store->enabled) { continue; }
1137 if (disabled && store->enabled) { continue; }
1138
1139 ua->send->ObjectStart();
1140 ua->send->ObjectKeyValue("name", store->resource_name_, "%s\n");
1141 ua->send->ObjectKeyValueBool("enabled", store->enabled);
1142 ua->send->ObjectEnd();
1143 }
1144 }
1145 ua->send->ArrayEnd("storages");
1146 UnlockRes(my_config);
1147
1148 return true;
1149 }
1150
DotProfilesCmd(UaContext * ua,const char * cmd)1151 bool DotProfilesCmd(UaContext* ua, const char* cmd)
1152 {
1153 ProfileResource* profile;
1154
1155 LockRes(my_config);
1156 ua->send->ArrayStart("profiles");
1157 foreach_res (profile, R_PROFILE) {
1158 ua->send->ObjectStart();
1159 ua->send->ObjectKeyValue("name", profile->resource_name_, "%s\n");
1160 ua->send->ObjectEnd();
1161 }
1162 ua->send->ArrayEnd("profiles");
1163 UnlockRes(my_config);
1164
1165 return true;
1166 }
1167
DotAopCmd(UaContext * ua,const char * cmd)1168 bool DotAopCmd(UaContext* ua, const char* cmd)
1169 {
1170 ua->send->ArrayStart("actiononpurge");
1171 for (int i = 0; ActionOnPurgeOptions[i].name; i++) {
1172 ua->send->ObjectStart();
1173 ua->send->ObjectKeyValue("name", ActionOnPurgeOptions[i].name, "%s\n");
1174 ua->send->ObjectEnd();
1175 }
1176 ua->send->ArrayEnd("actiononpurge");
1177
1178 return true;
1179 }
1180
DotTypesCmd(UaContext * ua,const char * cmd)1181 bool DotTypesCmd(UaContext* ua, const char* cmd)
1182 {
1183 ua->send->ArrayStart("jobtypes");
1184 for (int i = 0; jobtypes[i].type_name; i++) {
1185 ua->send->ObjectStart();
1186 ua->send->ObjectKeyValue("name", jobtypes[i].type_name, "%s\n");
1187 ua->send->ObjectEnd();
1188 }
1189 ua->send->ArrayEnd("jobtypes");
1190
1191 return true;
1192 }
1193
1194 /**
1195 * If this command is called, it tells the director that we
1196 * are a program that wants a sort of API, and hence,
1197 * we will probably suppress certain output, include more
1198 * error codes, and most of all send back a good number
1199 * of new signals that indicate whether or not the command
1200 * succeeded.
1201 */
DotApiCmd(UaContext * ua,const char * cmd)1202 bool DotApiCmd(UaContext* ua, const char* cmd)
1203 {
1204 if (ua->argc == 1) {
1205 ua->api = 1;
1206 } else if ((ua->argc >= 2) && (ua->argc <= 3)) {
1207 if (Bstrcasecmp(ua->argk[1], "off") || Bstrcasecmp(ua->argk[1], "0")) {
1208 ua->api = API_MODE_OFF;
1209 ua->batch = false;
1210 } else if (Bstrcasecmp(ua->argk[1], "on")
1211 || Bstrcasecmp(ua->argk[1], "1")) {
1212 ua->api = API_MODE_ON;
1213 ua->batch = false;
1214 } else if (Bstrcasecmp(ua->argk[1], "json")
1215 || Bstrcasecmp(ua->argk[1], "2")) {
1216 ua->api = API_MODE_JSON;
1217 ua->batch = true;
1218 if ((ua->argc == 3) && (FindArgWithValue(ua, "compact") == 2)) {
1219 if (Bstrcasecmp(ua->argv[2], "yes")) {
1220 ua->send->SetCompact(true);
1221 } else {
1222 ua->send->SetCompact(false);
1223 }
1224 }
1225 } else {
1226 return false;
1227 }
1228 } else {
1229 return false;
1230 }
1231
1232 ua->send->SetMode(ua->api);
1233 ua->send->ObjectKeyValue("api", "%s: ", ua->api, "%d\n");
1234
1235 return true;
1236 }
1237
SqlHandler(void * ctx,int num_field,char ** row)1238 static int SqlHandler(void* ctx, int num_field, char** row)
1239 {
1240 UaContext* ua = (UaContext*)ctx;
1241 PoolMem rows(PM_MESSAGE);
1242
1243 /* Check for nonsense */
1244 if (num_field == 0 || row == NULL || row[0] == NULL) {
1245 return 0; /* nothing returned */
1246 }
1247 for (int i = 0; num_field--; i++) {
1248 if (i == 0) {
1249 PmStrcpy(rows, NPRT(row[0]));
1250 } else {
1251 PmStrcat(rows, NPRT(row[i]));
1252 }
1253 PmStrcat(rows, "\t");
1254 }
1255 if (!rows.c_str() || !*rows.c_str()) {
1256 ua->SendMsg("\t");
1257 } else {
1258 ua->SendMsg("%s", rows.c_str());
1259 }
1260 return 0;
1261 }
1262
DotSqlCmd(UaContext * ua,const char * cmd)1263 bool DotSqlCmd(UaContext* ua, const char* cmd)
1264 {
1265 int pos;
1266 bool retval = false;
1267
1268 if (!OpenClientDb(ua, true)) { return false; }
1269
1270 pos = FindArgWithValue(ua, "query");
1271 if (pos < 0) {
1272 ua->ErrorMsg(_("query keyword not found.\n"));
1273 return false;
1274 }
1275
1276 switch (ua->api) {
1277 case API_MODE_ON:
1278 /*
1279 * BAT uses the ".sql" command and expects this format
1280 */
1281 retval = ua->db->SqlQuery(ua->argv[pos], SqlHandler, (void*)ua);
1282 break;
1283 default:
1284 /*
1285 * General format
1286 */
1287 retval = ua->db->ListSqlQuery(ua->jcr, ua->argv[pos], ua->send, HORZ_LIST,
1288 false);
1289 break;
1290 }
1291
1292 if (!retval) {
1293 Dmsg1(100, "Query failed: ERR=%s", ua->db->strerror());
1294 ua->ErrorMsg(_("Query failed: %s. ERR=%s"), ua->cmd, ua->db->strerror());
1295 }
1296
1297 return retval;
1298 }
1299
OneHandler(void * ctx,int num_field,char ** row)1300 static int OneHandler(void* ctx, int num_field, char** row)
1301 {
1302 UaContext* ua = (UaContext*)ctx;
1303
1304 ua->send->ObjectStart();
1305 ua->send->ObjectKeyValue("name", row[0], "%s\n");
1306 ua->send->ObjectEnd();
1307
1308 return 0;
1309 }
1310
DotMediatypesCmd(UaContext * ua,const char * cmd)1311 bool DotMediatypesCmd(UaContext* ua, const char* cmd)
1312 {
1313 if (!OpenClientDb(ua)) { return true; }
1314
1315 ua->send->ArrayStart("mediatypes");
1316 if (!ua->db->SqlQuery(
1317 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1318 OneHandler, (void*)ua)) {
1319 ua->ErrorMsg(_("List MediaType failed: ERR=%s\n"), ua->db->strerror());
1320 }
1321 ua->send->ArrayEnd("mediatypes");
1322
1323 return true;
1324 }
1325
DotMediaCmd(UaContext * ua,const char * cmd)1326 bool DotMediaCmd(UaContext* ua, const char* cmd)
1327 {
1328 if (!OpenClientDb(ua)) { return true; }
1329
1330 ua->send->ArrayStart("media");
1331 if (!ua->db->SqlQuery(
1332 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1333 OneHandler, (void*)ua)) {
1334 ua->ErrorMsg(_("List Media failed: ERR=%s\n"), ua->db->strerror());
1335 }
1336 ua->send->ArrayEnd("media");
1337
1338 return true;
1339 }
1340
DotScheduleCmd(UaContext * ua,const char * cmd)1341 bool DotScheduleCmd(UaContext* ua, const char* cmd)
1342 {
1343 bool enabled;
1344 bool disabled;
1345 ScheduleResource* sched;
1346
1347 enabled = FindArg(ua, NT_("enabled")) >= 0;
1348 disabled = FindArg(ua, NT_("disabled")) >= 0;
1349
1350 LockRes(my_config);
1351 ua->send->ArrayStart("schedules");
1352 foreach_res (sched, R_SCHEDULE) {
1353 if (ua->AclAccessOk(Schedule_ACL, sched->resource_name_)) {
1354 if (enabled && !sched->enabled) { continue; }
1355 if (disabled && sched->enabled) { continue; }
1356
1357 ua->send->ObjectStart();
1358 ua->send->ObjectKeyValue("name", sched->resource_name_, "%s\n");
1359 ua->send->ObjectKeyValueBool("enabled", sched->enabled);
1360 ua->send->ObjectEnd();
1361 }
1362 }
1363 ua->send->ArrayEnd("schedules");
1364 UnlockRes(my_config);
1365
1366 return true;
1367 }
1368
DotLocationsCmd(UaContext * ua,const char * cmd)1369 bool DotLocationsCmd(UaContext* ua, const char* cmd)
1370 {
1371 if (!OpenClientDb(ua)) { return true; }
1372
1373 ua->send->ArrayStart("locations");
1374 if (!ua->db->SqlQuery(
1375 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1376 OneHandler, (void*)ua)) {
1377 ua->ErrorMsg(_("List Location failed: ERR=%s\n"), ua->db->strerror());
1378 }
1379 ua->send->ArrayEnd("locations");
1380
1381 return true;
1382 }
1383
DotLevelsCmd(UaContext * ua,const char * cmd)1384 bool DotLevelsCmd(UaContext* ua, const char* cmd)
1385 {
1386 /*
1387 * Note some levels are blank, which means none is needed
1388 */
1389 ua->send->ArrayStart("levels");
1390 if (ua->argc == 1) {
1391 for (int i = 0; joblevels[i].level_name; i++) {
1392 if (joblevels[i].level_name[0] != ' ') {
1393 ua->send->ObjectStart();
1394 ua->send->ObjectKeyValue("name", joblevels[i].level_name, "%s\n");
1395 ua->send->ObjectKeyValue("level", joblevels[i].level);
1396 ua->send->ObjectKeyValue("jobtype", joblevels[i].job_type);
1397 ua->send->ObjectEnd();
1398 }
1399 }
1400 } else if (ua->argc == 2) {
1401 int jobtype = 0;
1402
1403 /*
1404 * Assume that first argument is the Job Type
1405 */
1406 for (int i = 0; jobtypes[i].type_name; i++) {
1407 if (Bstrcasecmp(ua->argk[1], jobtypes[i].type_name)) {
1408 jobtype = jobtypes[i].job_type;
1409 break;
1410 }
1411 }
1412
1413 for (int i = 0; joblevels[i].level_name; i++) {
1414 if ((joblevels[i].job_type == jobtype)
1415 && (joblevels[i].level_name[0] != ' ')) {
1416 ua->send->ObjectStart();
1417 ua->send->ObjectKeyValue("name", joblevels[i].level_name, "%s\n");
1418 ua->send->ObjectKeyValue("level", joblevels[i].level);
1419 ua->send->ObjectKeyValue("jobtype", joblevels[i].job_type);
1420 ua->send->ObjectEnd();
1421 }
1422 }
1423 }
1424 ua->send->ArrayEnd("levels");
1425
1426 return true;
1427 }
1428
DotVolstatusCmd(UaContext * ua,const char * cmd)1429 bool DotVolstatusCmd(UaContext* ua, const char* cmd)
1430 {
1431 ua->send->ArrayStart("volstatus");
1432 for (int i = 0; VolumeStatus[i].name; i++) {
1433 ua->send->ObjectStart();
1434 ua->send->ObjectKeyValue("name", VolumeStatus[i].name, "%s\n");
1435 ua->send->ObjectEnd();
1436 }
1437 ua->send->ArrayEnd("volstatus");
1438
1439 return true;
1440 }
1441
1442 /**
1443 * Return default values for a job
1444 */
DotDefaultsCmd(UaContext * ua,const char * cmd)1445 bool DotDefaultsCmd(UaContext* ua, const char* cmd)
1446 {
1447 char ed1[50];
1448 int pos = 0;
1449
1450 ua->send->ObjectStart("defaults");
1451 if ((pos = FindArgWithValue(ua, "job")) >= 0) {
1452 JobResource* job;
1453
1454 /*
1455 * Job defaults
1456 */
1457 job = ua->GetJobResWithName(ua->argv[pos]);
1458 if (job) {
1459 UnifiedStorageResource store;
1460
1461 /*
1462 * BAT parses the result of this command message by message,
1463 * instead of looking for a separator.
1464 * Therefore the SendBuffer() function is called after each line.
1465 */
1466 ua->send->ObjectKeyValue("job", "%s=", job->resource_name_, "%s\n");
1467 ua->send->SendBuffer();
1468 ua->send->ObjectKeyValue("pool", "%s=", job->pool->resource_name_,
1469 "%s\n");
1470 ua->send->SendBuffer();
1471 ua->send->ObjectKeyValue("messages", "%s=", job->messages->resource_name_,
1472 "%s\n");
1473 ua->send->SendBuffer();
1474 ua->send->ObjectKeyValue(
1475 "client",
1476 "%s=", ((job->client) ? job->client->resource_name_ : _("*None*")),
1477 "%s\n");
1478 ua->send->SendBuffer();
1479 GetJobStorage(&store, job, NULL);
1480 ua->send->ObjectKeyValue(
1481 "storage",
1482 "%s=", store.store ? store.store->resource_name_ : "*None*", "%s\n");
1483 ua->send->SendBuffer();
1484 ua->send->ObjectKeyValue(
1485 "where", "%s=", (job->RestoreWhere ? job->RestoreWhere : ""), "%s\n");
1486 if (job->JobType == JT_RESTORE) {
1487 ua->send->SendBuffer();
1488 ua->send->ObjectKeyValue(
1489 "replace", "%s=", job_replace_to_str(job->replace), "%s\n");
1490 }
1491 ua->send->SendBuffer();
1492 ua->send->ObjectKeyValue("level", "%s=", JobLevelToString(job->JobLevel),
1493 "%s\n");
1494 ua->send->SendBuffer();
1495 ua->send->ObjectKeyValue("type", "%s=", job_type_to_str(job->JobType),
1496 "%s\n");
1497 ua->send->SendBuffer();
1498 ua->send->ObjectKeyValue(
1499 "fileset",
1500 "%s=", ((job->fileset) ? job->fileset->resource_name_ : _("*None*")),
1501 "%s\n");
1502 ua->send->SendBuffer();
1503 ua->send->ObjectKeyValue("enabled", "%s=", job->enabled, "%d\n");
1504 ua->send->SendBuffer();
1505 ua->send->ObjectKeyValue(
1506 "catalog", "%s=",
1507 ((job->client) ? job->client->catalog->resource_name_ : _("*None*")),
1508 "%s\n");
1509 ua->send->SendBuffer();
1510 }
1511 } else if ((pos = FindArgWithValue(ua, "client")) >= 0) {
1512 ClientResource* client;
1513
1514 /*
1515 * Client defaults
1516 */
1517 client = ua->GetClientResWithName(ua->argv[pos]);
1518 if (client) {
1519 ua->send->ObjectKeyValue("client", "%s=", client->resource_name_, "%s\n");
1520 ua->send->ObjectKeyValue("address", "%s=", client->address, "%s\n");
1521 ua->send->ObjectKeyValue("port", "%s=", client->FDport, "%d\n");
1522 ua->send->ObjectKeyValue("file_retention",
1523 "%s=", edit_uint64(client->FileRetention, ed1),
1524 "%s\n");
1525 ua->send->ObjectKeyValue("job_retention",
1526 "%s=", edit_uint64(client->JobRetention, ed1),
1527 "%s\n");
1528 ua->send->ObjectKeyValue("autoprune", "%s=", client->AutoPrune, "%d\n");
1529 ua->send->ObjectKeyValue("enabled", "%s=", client->enabled, "%d\n");
1530 ua->send->ObjectKeyValue("catalog",
1531 "%s=", client->catalog->resource_name_, "%s\n");
1532 }
1533 } else if ((pos = FindArgWithValue(ua, "storage")) >= 0) {
1534 StorageResource* storage;
1535
1536 /*
1537 * Storage defaults
1538 */
1539 storage = ua->GetStoreResWithName(ua->argv[pos]);
1540 if (storage) {
1541 DeviceResource* device_resource;
1542 PoolMem devices;
1543
1544 ua->send->ObjectKeyValue("storage", "%s=", storage->resource_name_,
1545 "%s\n");
1546 ua->send->ObjectKeyValue("address", "%s=", storage->address, "%s\n");
1547 ua->send->ObjectKeyValue("port", "%s=", storage->SDport, "%d\n");
1548 ua->send->ObjectKeyValue("enabled", "%s=", storage->enabled, "%d\n");
1549 ua->send->ObjectKeyValue("media_type", "%s=", storage->media_type,
1550 "%s\n");
1551
1552 device_resource = (DeviceResource*)storage->device->first();
1553 if (device_resource) {
1554 devices.strcpy(device_resource->resource_name_);
1555 if (storage->device->size() > 1) {
1556 while ((device_resource = (DeviceResource*)storage->device->next())) {
1557 devices.strcat(",");
1558 devices.strcat(device_resource->resource_name_);
1559 }
1560 }
1561 ua->send->ObjectKeyValue("device", "%s=", devices.c_str(), "%s\n");
1562 }
1563 }
1564 } else if ((pos = FindArgWithValue(ua, "pool")) >= 0) {
1565 PoolResource* pool;
1566
1567 /*
1568 * Pool defaults
1569 */
1570 pool = ua->GetPoolResWithName(ua->argv[pos]);
1571 if (pool) {
1572 ua->send->ObjectKeyValue("pool", "%s=", pool->resource_name_, "%s\n");
1573 ua->send->ObjectKeyValue("pool_type", "%s=", pool->pool_type, "%s\n");
1574 ua->send->ObjectKeyValue(
1575 "label_format", "%s=", (pool->label_format ? pool->label_format : ""),
1576 "%s\n");
1577 ua->send->ObjectKeyValue("use_volume_once", "%s=", pool->use_volume_once,
1578 "%d\n");
1579 ua->send->ObjectKeyValue(
1580 "purge_oldest_volume=", "%s=", pool->purge_oldest_volume, "%d\n");
1581 ua->send->ObjectKeyValue("recycle_oldest_volume",
1582 "%s=", pool->recycle_oldest_volume, "%d\n");
1583 ua->send->ObjectKeyValue("max_volumes", "%s=", pool->max_volumes, "%d\n");
1584 ua->send->ObjectKeyValue(
1585 "vol_retention", "%s=", edit_uint64(pool->VolRetention, ed1), "%s\n");
1586 ua->send->ObjectKeyValue("vol_use_duration",
1587 "%s=", edit_uint64(pool->VolUseDuration, ed1),
1588 "%s\n");
1589 ua->send->ObjectKeyValue("max_vol_jobs", "%s=", pool->MaxVolJobs, "%d\n");
1590 ua->send->ObjectKeyValue("max_vol_files", "%s=", pool->MaxVolFiles,
1591 "%d\n");
1592 ua->send->ObjectKeyValue(
1593 "max_vol_bytes", "%s=", edit_uint64(pool->MaxVolBytes, ed1), "%s\n");
1594 ua->send->ObjectKeyValue("auto_prune", "%s=", pool->AutoPrune, "%d\n");
1595 ua->send->ObjectKeyValue("recycle", "%s=", pool->Recycle, "%d\n");
1596 ua->send->ObjectKeyValue("file_retention",
1597 "%s=", edit_uint64(pool->FileRetention, ed1),
1598 "%s\n");
1599 ua->send->ObjectKeyValue(
1600 "job_retention", "%s=", edit_uint64(pool->JobRetention, ed1), "%s\n");
1601 }
1602 } else {
1603 ua->SendMsg(".defaults command requires a parameter.\n");
1604 return false;
1605 }
1606 ua->send->ObjectEnd("defaults");
1607
1608 return true;
1609 }
1610 } /* namespace directordaemon */
1611