]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Fix plugin backup/restore sizes
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- User Agent Commands
31  *     These are "dot" commands, i.e. commands preceded
32  *        by a period. These commands are meant to be used
33  *        by a program, so there is no prompting, and the
34  *        returned results are (supposed to be) predictable.
35  *
36  *     Kern Sibbald, April MMII
37  *
38  *   Version $Id$
39  */
40
41 #include "bacula.h"
42 #include "dird.h"
43
44 /* Imported variables */
45 extern int r_first;
46 extern int r_last;
47 extern struct s_res resources[];
48
49 /* Imported functions */
50 extern void do_messages(UAContext *ua, const char *cmd);
51 extern int quit_cmd(UAContext *ua, const char *cmd);
52 extern int qhelp_cmd(UAContext *ua, const char *cmd);
53 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
54
55
56 /* Forward referenced functions */
57 static bool diecmd(UAContext *ua, const char *cmd);
58 static bool jobscmd(UAContext *ua, const char *cmd);
59 static bool filesetscmd(UAContext *ua, const char *cmd);
60 static bool clientscmd(UAContext *ua, const char *cmd);
61 static bool msgscmd(UAContext *ua, const char *cmd);
62 static bool poolscmd(UAContext *ua, const char *cmd);
63 static bool storagecmd(UAContext *ua, const char *cmd);
64 static bool defaultscmd(UAContext *ua, const char *cmd);
65 static bool typescmd(UAContext *ua, const char *cmd);
66 static bool backupscmd(UAContext *ua, const char *cmd);
67 static bool levelscmd(UAContext *ua, const char *cmd);
68 static bool getmsgscmd(UAContext *ua, const char *cmd);
69
70 static bool api_cmd(UAContext *ua, const char *cmd);
71 static bool sql_cmd(UAContext *ua, const char *cmd);
72 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
73 static bool dot_help_cmd(UAContext *ua, const char *cmd);
74
75 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help; };
76 static struct cmdstruct commands[] = {
77  { NT_(".api"),        api_cmd,        NULL},
78  { NT_(".backups"),    backupscmd,     NULL},
79  { NT_(".clients"),    clientscmd,     NULL},
80  { NT_(".defaults"),   defaultscmd,    NULL},
81  { NT_(".die"),        diecmd,         NULL},
82  { NT_(".exit"),       dot_quit_cmd,   NULL},
83  { NT_(".filesets"),   filesetscmd,    NULL},
84  { NT_(".help"),       dot_help_cmd,   NULL},
85  { NT_(".jobs"),       jobscmd,        NULL},
86  { NT_(".levels"),     levelscmd,      NULL},
87  { NT_(".messages"),   getmsgscmd,     NULL},
88  { NT_(".msgs"),       msgscmd,        NULL},
89  { NT_(".pools"),      poolscmd,       NULL},
90  { NT_(".quit"),       dot_quit_cmd,   NULL},
91  { NT_(".sql"),        sql_cmd,        NULL},
92  { NT_(".status"),     dot_status_cmd, NULL},
93  { NT_(".storage"),    storagecmd,     NULL},
94  { NT_(".types"),      typescmd,       NULL} 
95              };
96 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
97
98 /*
99  * Execute a command from the UA
100  */
101 bool do_a_dot_command(UAContext *ua) 
102 {
103    int i;
104    int len;
105    bool ok = false;
106    bool found = false;
107    BSOCK *user = ua->UA_sock;
108
109    Dmsg1(1400, "Dot command: %s\n", user->msg);
110    if (ua->argc == 0) {
111       return false;
112    }
113
114    len = strlen(ua->argk[0]);
115    if (len == 1) {
116       if (ua->api) user->signal(BNET_CMD_BEGIN);
117       if (ua->api) user->signal(BNET_CMD_OK);
118       return true;                    /* no op */
119    }
120    for (i=0; i<comsize; i++) {     /* search for command */
121       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
122          bool gui = ua->gui;
123          /* Check if command permitted, but "quit" is always OK */
124          if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
125              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
126             break;
127          }
128          Dmsg1(100, "Cmd: %s\n", ua->cmd);
129          ua->gui = true;
130          if (ua->api) user->signal(BNET_CMD_BEGIN);
131          ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
132          ua->gui = gui;
133          found = true;
134          break;
135       }
136    }
137    if (!found) {
138       pm_strcat(user->msg, _(": is an invalid command.\n"));
139       ua->error_msg("%s", user->msg);
140       ok = false;
141    }
142    if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
143    return ok;
144 }
145
146 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
147 {
148    quit_cmd(ua, cmd);
149    return true;
150 }
151
152 static bool dot_help_cmd(UAContext *ua, const char *cmd)
153 {
154    qhelp_cmd(ua, cmd);
155    return true;
156 }
157
158 static bool getmsgscmd(UAContext *ua, const char *cmd)
159 {
160    if (console_msg_pending) {
161       do_messages(ua, cmd);
162    }
163    return 1;
164 }
165
166 #ifdef DEVELOPER
167 static void do_storage_die(UAContext *ua, STORE *store)
168 {
169    BSOCK *sd;
170    JCR *jcr = ua->jcr;
171    USTORE lstore;
172    
173    lstore.store = store;
174    pm_strcpy(lstore.store_source, _("unknown source"));
175    set_wstorage(jcr, &lstore);
176    /* Try connecting for up to 15 seconds */
177    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
178       store->name(), store->address, store->SDport);
179    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
180       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
181       return;
182    }
183    Dmsg0(120, _("Connected to storage daemon\n"));
184    sd = jcr->store_bsock;
185    sd->fsend(".die");
186    if (sd->recv() >= 0) {
187       ua->send_msg("%s", sd->msg);
188    }
189    sd->signal(BNET_TERMINATE);
190    sd->close();
191    jcr->store_bsock = NULL;
192    return;
193 }
194
195 static void do_client_die(UAContext *ua, CLIENT *client)
196 {
197    BSOCK *fd;
198
199    /* Connect to File daemon */
200
201    ua->jcr->client = client;
202    /* Try to connect for 15 seconds */
203    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
204       client->name(), client->address, client->FDport);
205    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
206       ua->error_msg(_("Failed to connect to Client.\n"));
207       return;
208    }
209    Dmsg0(120, "Connected to file daemon\n");
210    fd = ua->jcr->file_bsock;
211    fd->fsend(".die");
212    if (fd->recv() >= 0) {
213       ua->send_msg("%s", fd->msg);
214    }
215    fd->signal(BNET_TERMINATE);
216    fd->close();
217    ua->jcr->file_bsock = NULL;
218    return;
219 }
220
221 /*
222  * Create segmentation fault
223  */
224 static bool diecmd(UAContext *ua, const char *cmd)
225 {
226    STORE *store;
227    CLIENT *client;
228    int i;
229    JCR *jcr = NULL;
230    int a;
231
232    Dmsg1(120, "diecmd:%s:\n", cmd);
233
234    /* General debug? */
235    for (i=1; i<ua->argc; i++) {
236       if (strcasecmp(ua->argk[i], "dir") == 0 ||
237           strcasecmp(ua->argk[i], "director") == 0) {
238          ua->send_msg(_("The Director will segment fault.\n"));
239          a = jcr->JobId; /* ref NULL pointer */
240          jcr->JobId = 1000; /* another ref NULL pointer */
241          return 1;
242       }
243       if (strcasecmp(ua->argk[i], "client") == 0 ||
244           strcasecmp(ua->argk[i], "fd") == 0) {
245          client = NULL;
246          if (ua->argv[i]) {
247             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
248             if (client) {
249                do_client_die(ua, client);
250                return 1;
251             }
252          }
253          client = select_client_resource(ua);
254          if (client) {
255             do_client_die(ua, client);
256             return 1;
257          }
258       }
259
260       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
261           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
262           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
263          store = NULL;
264          if (ua->argv[i]) {
265             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
266             if (store) {
267                do_storage_die(ua, store);
268                return 1;
269             }
270          }
271          store = get_storage_resource(ua, false/*no default*/);
272          if (store) {
273             do_storage_die(ua, store);
274             return 1;
275          }
276       }
277    }
278    /*
279     * We didn't find an appropriate keyword above, so
280     * prompt the user.
281     */
282    start_prompt(ua, _("Available daemons are: \n"));
283    add_prompt(ua, _("Director"));
284    add_prompt(ua, _("Storage"));
285    add_prompt(ua, _("Client"));
286    switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
287    case 0:                         /* Director */
288       ua->send_msg(_("The Director will segment fault.\n"));
289       a = jcr->JobId; /* ref NULL pointer */
290       jcr->JobId = 1000; /* another ref NULL pointer */
291       break;
292    case 1:
293       store = get_storage_resource(ua, false/*no default*/);
294       if (store) {
295          do_storage_die(ua, store);
296       }
297       break;
298    case 2:
299       client = select_client_resource(ua);
300       if (client) {
301          do_client_die(ua, client);
302       }
303       break;
304    default:
305       break;
306    }
307    return true;
308 }
309
310 #else
311
312 /*
313  * Dummy routine for non-development version
314  */
315 static bool diecmd(UAContext *ua, const char *cmd)
316 {
317    return true;
318 }
319
320 #endif
321
322 static bool jobscmd(UAContext *ua, const char *cmd)
323 {
324    JOB *job;
325    LockRes();
326    foreach_res(job, R_JOB) {
327       if (acl_access_ok(ua, Job_ACL, job->name())) {
328          ua->send_msg("%s\n", job->name());
329       }
330    }
331    UnlockRes();
332    return true;
333 }
334
335 static bool filesetscmd(UAContext *ua, const char *cmd)
336 {
337    FILESET *fs;
338    LockRes();
339    foreach_res(fs, R_FILESET) {
340       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
341          ua->send_msg("%s\n", fs->name());
342       }
343    }
344    UnlockRes();
345    return true;
346 }
347
348 static bool clientscmd(UAContext *ua, const char *cmd)
349 {
350    CLIENT *client;       
351    LockRes();
352    foreach_res(client, R_CLIENT) {
353       if (acl_access_ok(ua, Client_ACL, client->name())) {
354          ua->send_msg("%s\n", client->name());
355       }
356    }
357    UnlockRes();
358    return true;
359 }
360
361 static bool msgscmd(UAContext *ua, const char *cmd)
362 {
363    MSGS *msgs = NULL;
364    LockRes();
365    foreach_res(msgs, R_MSGS) {
366       ua->send_msg("%s\n", msgs->name());
367    }
368    UnlockRes();
369    return true;
370 }
371
372 static bool poolscmd(UAContext *ua, const char *cmd)
373 {
374    POOL *pool;       
375    LockRes();
376    foreach_res(pool, R_POOL) {
377       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
378          ua->send_msg("%s\n", pool->name());
379       }
380    }
381    UnlockRes();
382    return true;
383 }
384
385 static bool storagecmd(UAContext *ua, const char *cmd)
386 {
387    STORE *store;
388    LockRes();
389    foreach_res(store, R_STORAGE) {
390       if (acl_access_ok(ua, Storage_ACL, store->name())) {
391          ua->send_msg("%s\n", store->name());
392       }
393    }
394    UnlockRes();
395    return true;
396 }
397
398
399 static bool typescmd(UAContext *ua, const char *cmd)
400 {
401    ua->send_msg("Backup\n");
402    ua->send_msg("Restore\n");
403    ua->send_msg("Admin\n");
404    ua->send_msg("Verify\n");
405    ua->send_msg("Migrate\n");
406    return true;
407 }
408
409
410 /*
411  * If this command is called, it tells the director that we
412  *  are a program that wants a sort of API, and hence,
413  *  we will probably suppress certain output, include more
414  *  error codes, and most of all send back a good number
415  *  of new signals that indicate whether or not the command
416  *  succeeded.
417  */
418 static bool api_cmd(UAContext *ua, const char *cmd)
419 {
420    if (ua->argc == 2) {
421       ua->api = atoi(ua->argk[1]);
422    } else {
423       ua->api = 1;
424    }
425    return true;
426 }
427
428 static int client_backups_handler(void *ctx, int num_field, char **row)
429 {
430    UAContext *ua = (UAContext *)ctx;
431    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
432       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
433    return 0;
434 }
435
436 /*
437  * Return the backups for this client 
438  *
439  *  .backups client=xxx fileset=yyy
440  *
441  */
442 static bool backupscmd(UAContext *ua, const char *cmd)
443 {
444    if (!open_client_db(ua)) {
445       return true;
446    }
447    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
448        strcmp(ua->argk[2], "fileset") != 0) {
449       return true;
450    }
451    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
452        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
453       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
454       return true;
455    }
456    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
457    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
458       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
459       return true;
460    }
461    return true;
462 }
463
464 static int sql_handler(void *ctx, int num_field, char **row)
465 {
466    UAContext *ua = (UAContext *)ctx;
467    POOL_MEM rows(PM_MESSAGE);
468
469    for (int i=0; num_field--; i++) {
470       if (i == 0) {
471          pm_strcpy(rows, NPRT(row[0]));
472       } else {
473          pm_strcat(rows, NPRT(row[i]));
474       }
475       pm_strcat(rows, "\t");
476    }
477    if (!rows.c_str() || !*rows.c_str()) {
478       ua->send_msg("\t");
479    } else {
480       ua->send_msg("%s", rows.c_str());
481    }
482    return 0;
483 }
484
485 static bool sql_cmd(UAContext *ua, const char *cmd)
486 {
487    int index;
488    if (!open_client_db(ua)) {
489       return true;
490    }
491    index = find_arg_with_value(ua, "query");
492    if (index < 0) {
493       ua->error_msg(_("query keyword not found.\n"));
494       return true;
495    }
496    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
497       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
498       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
499       return true;
500    }
501    return true;
502 }
503       
504
505
506 static bool levelscmd(UAContext *ua, const char *cmd)
507 {
508    ua->send_msg("Incremental\n");
509    ua->send_msg("Full\n");
510    ua->send_msg("Differential\n");
511    ua->send_msg("Catalog\n");
512    ua->send_msg("InitCatalog\n");
513    ua->send_msg("VolumeToCatalog\n");
514    return true;
515 }
516
517 /*
518  * Return default values for a job
519  */
520 static bool defaultscmd(UAContext *ua, const char *cmd)
521 {
522    JOB *job;
523    CLIENT *client;
524    STORE *storage;
525    POOL *pool;
526    char ed1[50];
527
528    if (ua->argc != 2 || !ua->argv[1]) {
529       return true;
530    }
531
532    /* Job defaults */   
533    if (strcmp(ua->argk[1], "job") == 0) {
534       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
535          return true;
536       }
537       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
538       if (job) {
539          USTORE store;
540          ua->send_msg("job=%s", job->name());
541          ua->send_msg("pool=%s", job->pool->name());
542          ua->send_msg("messages=%s", job->messages->name());
543          ua->send_msg("client=%s", job->client->name());
544          get_job_storage(&store, job, NULL);
545          ua->send_msg("storage=%s", store.store->name());
546          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
547          ua->send_msg("level=%s", level_to_str(job->JobLevel));
548          ua->send_msg("type=%s", job_type_to_str(job->JobType));
549          ua->send_msg("fileset=%s", job->fileset->name());
550          ua->send_msg("enabled=%d", job->enabled);
551          ua->send_msg("catalog=%s", job->client->catalog->name());
552       }
553    } 
554    /* Client defaults */
555    else if (strcmp(ua->argk[1], "client") == 0) {
556       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
557          return true;   
558       }
559       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
560       if (client) {
561          ua->send_msg("client=%s", client->name());
562          ua->send_msg("address=%s", client->address);
563          ua->send_msg("fdport=%d", client->FDport);
564          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
565          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
566          ua->send_msg("autoprune=%d", client->AutoPrune);
567          ua->send_msg("catalog=%s", client->catalog->name());
568       }
569    }
570    /* Storage defaults */
571    else if (strcmp(ua->argk[1], "storage") == 0) {
572       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
573          return true;
574       }
575       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
576       DEVICE *device;
577       if (storage) {
578          ua->send_msg("storage=%s", storage->name());
579          ua->send_msg("address=%s", storage->address);
580          ua->send_msg("enabled=%d", storage->enabled);
581          ua->send_msg("media_type=%s", storage->media_type);
582          ua->send_msg("sdport=%d", storage->SDport);
583          device = (DEVICE *)storage->device->first();
584          ua->send_msg("device=%s", device->name());
585          if (storage->device->size() > 1) {
586             while ((device = (DEVICE *)storage->device->next())) {
587                ua->send_msg(",%s", device->name());
588             }
589          }
590       }
591    }
592    /* Pool defaults */
593    else if (strcmp(ua->argk[1], "pool") == 0) {
594       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
595          return true;
596       }
597       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
598       if (pool) {
599          ua->send_msg("pool=%s", pool->name());
600          ua->send_msg("pool_type=%s", pool->pool_type);
601          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
602          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
603          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
604          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
605          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
606          ua->send_msg("max_volumes=%d", pool->max_volumes);
607          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
608          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
609          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
610          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
611          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
612          ua->send_msg("auto_prune=%d", pool->AutoPrune);
613          ua->send_msg("recycle=%d", pool->Recycle);
614       }
615    }
616    return true;
617 }