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