]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
ebl fix segfault with debug mode
[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 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          ua->gui = gui;
135          found = true;
136          break;
137       }
138    }
139    if (!found) {
140       pm_strcat(user->msg, _(": is an invalid command.\n"));
141       ua->error_msg("%s", user->msg);
142       ok = false;
143    }
144    if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
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    for (int i=0; num_field--; i++) {
472       if (i == 0) {
473          pm_strcpy(rows, NPRT(row[0]));
474       } else {
475          pm_strcat(rows, NPRT(row[i]));
476       }
477       pm_strcat(rows, "\t");
478    }
479    if (!rows.c_str() || !*rows.c_str()) {
480       ua->send_msg("\t");
481    } else {
482       ua->send_msg("%s", rows.c_str());
483    }
484    return 0;
485 }
486
487 static bool sql_cmd(UAContext *ua, const char *cmd)
488 {
489    int index;
490    if (!open_client_db(ua)) {
491       return true;
492    }
493    index = find_arg_with_value(ua, "query");
494    if (index < 0) {
495       ua->error_msg(_("query keyword not found.\n"));
496       return true;
497    }
498    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
499       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
500       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
501       return true;
502    }
503    return true;
504 }
505       
506
507
508 static bool levelscmd(UAContext *ua, const char *cmd)
509 {
510    ua->send_msg("Incremental\n");
511    ua->send_msg("Full\n");
512    ua->send_msg("Differential\n");
513    ua->send_msg("VirtualFull\n");
514    ua->send_msg("Catalog\n");
515    ua->send_msg("InitCatalog\n");
516    ua->send_msg("VolumeToCatalog\n");
517    return true;
518 }
519
520 /*
521  * Return default values for a job
522  */
523 static bool defaultscmd(UAContext *ua, const char *cmd)
524 {
525    JOB *job;
526    CLIENT *client;
527    STORE *storage;
528    POOL *pool;
529    char ed1[50];
530
531    if (ua->argc != 2 || !ua->argv[1]) {
532       return true;
533    }
534
535    /* Job defaults */   
536    if (strcmp(ua->argk[1], "job") == 0) {
537       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
538          return true;
539       }
540       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
541       if (job) {
542          USTORE store;
543          ua->send_msg("job=%s", job->name());
544          ua->send_msg("pool=%s", job->pool->name());
545          ua->send_msg("messages=%s", job->messages->name());
546          ua->send_msg("client=%s", job->client->name());
547          get_job_storage(&store, job, NULL);
548          ua->send_msg("storage=%s", store.store->name());
549          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
550          ua->send_msg("level=%s", level_to_str(job->JobLevel));
551          ua->send_msg("type=%s", job_type_to_str(job->JobType));
552          ua->send_msg("fileset=%s", job->fileset->name());
553          ua->send_msg("enabled=%d", job->enabled);
554          ua->send_msg("catalog=%s", job->client->catalog->name());
555       }
556    } 
557    /* Client defaults */
558    else if (strcmp(ua->argk[1], "client") == 0) {
559       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
560          return true;   
561       }
562       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
563       if (client) {
564          ua->send_msg("client=%s", client->name());
565          ua->send_msg("address=%s", client->address);
566          ua->send_msg("fdport=%d", client->FDport);
567          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
568          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
569          ua->send_msg("autoprune=%d", client->AutoPrune);
570          ua->send_msg("catalog=%s", client->catalog->name());
571       }
572    }
573    /* Storage defaults */
574    else if (strcmp(ua->argk[1], "storage") == 0) {
575       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
576          return true;
577       }
578       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
579       DEVICE *device;
580       if (storage) {
581          ua->send_msg("storage=%s", storage->name());
582          ua->send_msg("address=%s", storage->address);
583          ua->send_msg("enabled=%d", storage->enabled);
584          ua->send_msg("media_type=%s", storage->media_type);
585          ua->send_msg("sdport=%d", storage->SDport);
586          device = (DEVICE *)storage->device->first();
587          ua->send_msg("device=%s", device->name());
588          if (storage->device->size() > 1) {
589             while ((device = (DEVICE *)storage->device->next())) {
590                ua->send_msg(",%s", device->name());
591             }
592          }
593       }
594    }
595    /* Pool defaults */
596    else if (strcmp(ua->argk[1], "pool") == 0) {
597       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
598          return true;
599       }
600       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
601       if (pool) {
602          ua->send_msg("pool=%s", pool->name());
603          ua->send_msg("pool_type=%s", pool->pool_type);
604          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
605          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
606          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
607          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
608          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
609          ua->send_msg("max_volumes=%d", pool->max_volumes);
610          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
611          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
612          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
613          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
614          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
615          ua->send_msg("auto_prune=%d", pool->AutoPrune);
616          ua->send_msg("recycle=%d", pool->Recycle);
617       }
618    }
619    return true;
620 }