]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
kes Implement dir_sql() which issues an SQL query.
[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    ua->send_msg(_("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          ua->send_msg("%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          ua->send_msg("%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          ua->send_msg("%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       ua->send_msg("%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          ua->send_msg("%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          ua->send_msg("%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    ua->send_msg("Backup\n");
259    ua->send_msg("Restore\n");
260    ua->send_msg("Admin\n");
261    ua->send_msg("Verify\n");
262    ua->send_msg("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    ua->send_msg("| %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       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
311       return true;
312    }
313    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
314    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
315       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
316       return true;
317    }
318    return true;
319 }
320
321 static int sql_handler(void *ctx, int num_field, char **row)
322 {
323    UAContext *ua = (UAContext *)ctx;
324    POOL_MEM rows(PM_MESSAGE);
325
326    for (int i=0; num_field--; i++) {
327       if (i == 0) {
328          pm_strcpy(rows, row[0]);
329       } else {
330          pm_strcat(rows, row[i]);
331       }
332       pm_strcat(rows, "\t");
333    }
334    ua->send_msg(rows.c_str());
335    return 0;
336 }
337
338 static bool sql_cmd(UAContext *ua, const char *cmd)
339 {
340    int index;
341    if (!open_client_db(ua)) {
342       return true;
343    }
344    index = find_arg_with_value(ua, "query");
345    if (index < 0) {
346       ua->error_msg(_("query keyword not found.\n"));
347       return true;
348    }
349    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
350       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
351       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
352       return true;
353    }
354    return true;
355 }
356       
357
358
359 static bool levelscmd(UAContext *ua, const char *cmd)
360 {
361    ua->send_msg("Incremental\n");
362    ua->send_msg("Full\n");
363    ua->send_msg("Differential\n");
364    ua->send_msg("Catalog\n");
365    ua->send_msg("InitCatalog\n");
366    ua->send_msg("VolumeToCatalog\n");
367    return true;
368 }
369
370 /*
371  * Return default values for a job
372  */
373 static bool defaultscmd(UAContext *ua, const char *cmd)
374 {
375    JOB *job;
376    CLIENT *client;
377    STORE *storage;
378    POOL *pool;
379    char ed1[50];
380
381    if (ua->argc != 2 || !ua->argv[1]) {
382       return true;
383    }
384
385    /* Job defaults */   
386    if (strcmp(ua->argk[1], "job") == 0) {
387       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
388          return true;
389       }
390       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
391       if (job) {
392          USTORE store;
393          ua->send_msg("job=%s", job->name());
394          ua->send_msg("pool=%s", job->pool->name());
395          ua->send_msg("messages=%s", job->messages->name());
396          ua->send_msg("client=%s", job->client->name());
397          get_job_storage(&store, job, NULL);
398          ua->send_msg("storage=%s", store.store->name());
399          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
400          ua->send_msg("level=%s", level_to_str(job->JobLevel));
401          ua->send_msg("type=%s", job_type_to_str(job->JobType));
402          ua->send_msg("fileset=%s", job->fileset->name());
403          ua->send_msg("enabled=%d", job->enabled);
404          ua->send_msg("catalog=%s", job->client->catalog->name());
405       }
406    } 
407    /* Client defaults */
408    else if (strcmp(ua->argk[1], "client") == 0) {
409       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
410          return true;   
411       }
412       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
413       if (client) {
414          ua->send_msg("client=%s", client->name());
415          ua->send_msg("address=%s", client->address);
416          ua->send_msg("fdport=%d", client->FDport);
417          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
418          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
419          ua->send_msg("autoprune=%d", client->AutoPrune);
420          ua->send_msg("catalog=%s", client->catalog->name());
421       }
422    }
423    /* Storage defaults */
424    else if (strcmp(ua->argk[1], "storage") == 0) {
425       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
426          return true;
427       }
428       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
429       DEVICE *device;
430       if (storage) {
431          ua->send_msg("storage=%s", storage->name());
432          ua->send_msg("address=%s", storage->address);
433          ua->send_msg("enabled=%d", storage->enabled);
434          ua->send_msg("media_type=%s", storage->media_type);
435          ua->send_msg("sdport=%d", storage->SDport);
436          device = (DEVICE *)storage->device->first();
437          ua->send_msg("device=%s", device->name());
438          if (storage->device->size() > 1) {
439             while ((device = (DEVICE *)storage->device->next())) {
440                ua->send_msg(",%s", device->name());
441             }
442          }
443       }
444    }
445    /* Pool defaults */
446    else if (strcmp(ua->argk[1], "pool") == 0) {
447       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
448          return true;
449       }
450       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
451       if (pool) {
452          ua->send_msg("pool=%s", pool->name());
453          ua->send_msg("pool_type=%s", pool->pool_type);
454          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
455          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
456          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
457          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
458          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
459          ua->send_msg("max_volumes=%d", pool->max_volumes);
460          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
461          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
462          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
463          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
464          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
465          ua->send_msg("auto_prune=%d", pool->AutoPrune);
466          ua->send_msg("recycle=%d", pool->Recycle);
467       }
468    }
469    return true;
470 }