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