]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
af8258ff1746493646f44d610ffd133461a4047d
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 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 plus additions
11    that are listed 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 int do_a_dot_command(UAContext *ua, const char *cmd)
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 1;
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 1;                       /* 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          ua->gui = true;
129          if (ua->api) user->signal(BNET_CMD_BEGIN);
130          ok = (*commands[i].func)(ua, cmd);   /* go execute command */
131          ua->gui = gui;
132          found = true;
133          break;
134       }
135    }
136    if (!found) {
137       pm_strcat(user->msg, _(": is an invalid command.\n"));
138       user->msglen = strlen(user->msg);
139       user->send();
140    }
141    if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
142    return 1;
143 }
144
145 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
146 {
147    quit_cmd(ua, cmd);
148    return true;
149 }
150
151 static bool dot_help_cmd(UAContext *ua, const char *cmd)
152 {
153    qhelp_cmd(ua, cmd);
154    return true;
155 }
156
157 static bool getmsgscmd(UAContext *ua, const char *cmd)
158 {
159    if (console_msg_pending) {
160       do_messages(ua, cmd);
161    }
162    return 1;
163 }
164
165 /*
166  * Create segmentation fault
167  */
168 static bool diecmd(UAContext *ua, const char *cmd)
169 {
170    JCR *jcr = NULL;
171    int a;
172
173    bsendmsg(ua, _("The Director will segment fault.\n"));
174    a = jcr->JobId; /* ref NULL pointer */
175    jcr->JobId = 1000; /* another ref NULL pointer */
176    return true;
177 }
178
179 static bool jobscmd(UAContext *ua, const char *cmd)
180 {
181    JOB *job;
182    LockRes();
183    foreach_res(job, R_JOB) {
184       if (acl_access_ok(ua, Job_ACL, job->name())) {
185          bsendmsg(ua, "%s\n", job->name());
186       }
187    }
188    UnlockRes();
189    return true;
190 }
191
192 static bool filesetscmd(UAContext *ua, const char *cmd)
193 {
194    FILESET *fs;
195    LockRes();
196    foreach_res(fs, R_FILESET) {
197       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
198          bsendmsg(ua, "%s\n", fs->name());
199       }
200    }
201    UnlockRes();
202    return true;
203 }
204
205 static bool clientscmd(UAContext *ua, const char *cmd)
206 {
207    CLIENT *client;       
208    LockRes();
209    foreach_res(client, R_CLIENT) {
210       if (acl_access_ok(ua, Client_ACL, client->name())) {
211          bsendmsg(ua, "%s\n", client->name());
212       }
213    }
214    UnlockRes();
215    return true;
216 }
217
218 static bool msgscmd(UAContext *ua, const char *cmd)
219 {
220    MSGS *msgs = NULL;
221    LockRes();
222    foreach_res(msgs, R_MSGS) {
223       bsendmsg(ua, "%s\n", msgs->name());
224    }
225    UnlockRes();
226    return true;
227 }
228
229 static bool poolscmd(UAContext *ua, const char *cmd)
230 {
231    POOL *pool;       
232    LockRes();
233    foreach_res(pool, R_POOL) {
234       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
235          bsendmsg(ua, "%s\n", pool->name());
236       }
237    }
238    UnlockRes();
239    return true;
240 }
241
242 static bool storagecmd(UAContext *ua, const char *cmd)
243 {
244    STORE *store;
245    LockRes();
246    foreach_res(store, R_STORAGE) {
247       if (acl_access_ok(ua, Storage_ACL, store->name())) {
248          bsendmsg(ua, "%s\n", store->name());
249       }
250    }
251    UnlockRes();
252    return true;
253 }
254
255
256 static bool typescmd(UAContext *ua, const char *cmd)
257 {
258    bsendmsg(ua, "Backup\n");
259    bsendmsg(ua, "Restore\n");
260    bsendmsg(ua, "Admin\n");
261    bsendmsg(ua, "Verify\n");
262    bsendmsg(ua, "Migrate\n");
263    return true;
264 }
265
266
267 /*
268  * If this command is called, it tells the director that we
269  *  are a program that wants a sort of API, and hence,
270  *  we will probably suppress certain output, include more
271  *  error codes, and most of all send back a good number
272  *  of new signals that indicate whether or not the command
273  *  succeeded.
274  */
275 static bool api_cmd(UAContext *ua, const char *cmd)
276 {
277    if (ua->argc == 2) {
278       ua->api = atoi(ua->argk[1]);
279    } else {
280       ua->api = 1;
281    }
282    return true;
283 }
284
285 static int client_backups_handler(void *ctx, int num_field, char **row)
286 {
287    UAContext *ua = (UAContext *)ctx;
288    bsendmsg(ua, "| %s | %s | %s | %s | %s | %s | %s | %s |\n",
289       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
290    return 0;
291 }
292
293 /*
294  * Return the backups for this client 
295  *
296  *  .backups client=xxx fileset=yyy
297  *
298  */
299 static bool backupscmd(UAContext *ua, const char *cmd)
300 {
301    if (!open_client_db(ua)) {
302       return true;
303    }
304    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
305        strcmp(ua->argk[2], "fileset") != 0) {
306       return true;
307    }
308    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
309        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
310       return true;
311    }
312    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
313    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
314       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
315       return true;
316    }
317    return true;
318 }
319
320 static int sql_handler(void *ctx, int num_field, char **row)
321 {
322    UAContext *ua = (UAContext *)ctx;
323    POOL_MEM rows(PM_MESSAGE);
324
325    for (int i=0; num_field--; i++) {
326       if (i == 0) {
327          pm_strcpy(rows, row[0]);
328       } else {
329          pm_strcat(rows, row[i]);
330       }
331       pm_strcat(rows, "\t");
332    }
333    bsendmsg(ua, rows.c_str());
334    return 0;
335 }
336
337 static bool sql_cmd(UAContext *ua, const char *cmd)
338 {
339    if (!db_sql_query(ua->db, ua->argk[1], sql_handler, (void *)ua)) {
340       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
341       return true;
342    }
343    return true;
344 }
345       
346
347
348 static bool levelscmd(UAContext *ua, const char *cmd)
349 {
350    bsendmsg(ua, "Incremental\n");
351    bsendmsg(ua, "Full\n");
352    bsendmsg(ua, "Differential\n");
353    bsendmsg(ua, "Catalog\n");
354    bsendmsg(ua, "InitCatalog\n");
355    bsendmsg(ua, "VolumeToCatalog\n");
356    return true;
357 }
358
359 /*
360  * Return default values for a job
361  */
362 static bool defaultscmd(UAContext *ua, const char *cmd)
363 {
364    JOB *job;
365    CLIENT *client;
366    STORE *storage;
367    POOL *pool;
368
369    if (ua->argc != 2 || !ua->argv[1]) {
370       return true;
371    }
372
373    /* Job defaults */   
374    if (strcmp(ua->argk[1], "job") == 0) {
375       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
376          return true;
377       }
378       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
379       if (job) {
380          USTORE store;
381          bsendmsg(ua, "job=%s", job->name());
382          bsendmsg(ua, "pool=%s", job->pool->name());
383          bsendmsg(ua, "messages=%s", job->messages->name());
384          bsendmsg(ua, "client=%s", job->client->name());
385          get_job_storage(&store, job, NULL);
386          bsendmsg(ua, "storage=%s", store.store->name());
387          bsendmsg(ua, "where=%s", job->RestoreWhere?job->RestoreWhere:"");
388          bsendmsg(ua, "level=%s", level_to_str(job->JobLevel));
389          bsendmsg(ua, "type=%s", job_type_to_str(job->JobType));
390          bsendmsg(ua, "fileset=%s", job->fileset->name());
391          bsendmsg(ua, "enabled=%d", job->enabled);
392          bsendmsg(ua, "catalog=%s", job->client->catalog->name());
393       }
394    } 
395    /* Client defaults */
396    else if (strcmp(ua->argk[1], "client") == 0) {
397       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
398          return true;   
399       }
400       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
401       if (client) {
402          bsendmsg(ua, "client=%s", client->name());
403          bsendmsg(ua, "address=%s", client->address);
404          bsendmsg(ua, "fdport=%d", client->FDport);
405          bsendmsg(ua, "file_retention=%d", client->FileRetention);
406          bsendmsg(ua, "job_retention=%d", client->JobRetention);
407          bsendmsg(ua, "autoprune=%d", client->AutoPrune);
408          bsendmsg(ua, "catalog=%s", client->catalog->name());
409       }
410    }
411    /* Storage defaults */
412    else if (strcmp(ua->argk[1], "storage") == 0) {
413       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
414          return true;
415       }
416       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
417       DEVICE *device;
418       if (storage) {
419          bsendmsg(ua, "storage=%s", storage->name());
420          bsendmsg(ua, "address=%s", storage->address);
421          bsendmsg(ua, "enabled=%d", storage->enabled);
422          bsendmsg(ua, "media_type=%s", storage->media_type);
423          bsendmsg(ua, "sdport=%d", storage->SDport);
424          device = (DEVICE *)storage->device->first();
425          bsendmsg(ua, "device=%s", device->name());
426          if (storage->device->size() > 1) {
427             while ((device = (DEVICE *)storage->device->next())) {
428                bsendmsg(ua, ",%s", device->name());
429             }
430          }
431       }
432    }
433    /* Pool defaults */
434    else if (strcmp(ua->argk[1], "pool") == 0) {
435       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
436          return true;
437       }
438       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
439       if (pool) {
440          bsendmsg(ua, "pool=%s", pool->name());
441          bsendmsg(ua, "pool_type=%s", pool->pool_type);
442          bsendmsg(ua, "label_format=%s", pool->label_format?pool->label_format:"");
443          bsendmsg(ua, "use_volume_once=%d", pool->use_volume_once);
444          bsendmsg(ua, "purge_oldest_volume=%d", pool->purge_oldest_volume);
445          bsendmsg(ua, "recycle_oldest_volume=%d", pool->recycle_oldest_volume);
446          bsendmsg(ua, "recycle_current_volume=%d", pool->recycle_current_volume);
447          bsendmsg(ua, "max_volumes=%d", pool->max_volumes);
448          bsendmsg(ua, "vol_retention=%d", pool->VolRetention);
449          bsendmsg(ua, "vol_use_duration=%d", pool->VolUseDuration);
450          bsendmsg(ua, "max_vol_jobs=%d", pool->MaxVolJobs);
451          bsendmsg(ua, "max_vol_files=%d", pool->MaxVolFiles);
452          bsendmsg(ua, "max_vol_bytes=%d", pool->MaxVolBytes);
453          bsendmsg(ua, "auto_prune=%d", pool->AutoPrune);
454          bsendmsg(ua, "recycle=%d", pool->Recycle);
455       }
456    }
457    return true;
458 }