]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Fix new .sql command for bat
[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 (!open_client_db(ua)) {
340       return true;
341    }
342    if (!db_sql_query(ua->db, ua->argk[1], sql_handler, (void *)ua)) {
343       bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
344       return true;
345    }
346    return true;
347 }
348       
349
350
351 static bool levelscmd(UAContext *ua, const char *cmd)
352 {
353    bsendmsg(ua, "Incremental\n");
354    bsendmsg(ua, "Full\n");
355    bsendmsg(ua, "Differential\n");
356    bsendmsg(ua, "Catalog\n");
357    bsendmsg(ua, "InitCatalog\n");
358    bsendmsg(ua, "VolumeToCatalog\n");
359    return true;
360 }
361
362 /*
363  * Return default values for a job
364  */
365 static bool defaultscmd(UAContext *ua, const char *cmd)
366 {
367    JOB *job;
368    CLIENT *client;
369    STORE *storage;
370    POOL *pool;
371
372    if (ua->argc != 2 || !ua->argv[1]) {
373       return true;
374    }
375
376    /* Job defaults */   
377    if (strcmp(ua->argk[1], "job") == 0) {
378       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
379          return true;
380       }
381       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
382       if (job) {
383          USTORE store;
384          bsendmsg(ua, "job=%s", job->name());
385          bsendmsg(ua, "pool=%s", job->pool->name());
386          bsendmsg(ua, "messages=%s", job->messages->name());
387          bsendmsg(ua, "client=%s", job->client->name());
388          get_job_storage(&store, job, NULL);
389          bsendmsg(ua, "storage=%s", store.store->name());
390          bsendmsg(ua, "where=%s", job->RestoreWhere?job->RestoreWhere:"");
391          bsendmsg(ua, "level=%s", level_to_str(job->JobLevel));
392          bsendmsg(ua, "type=%s", job_type_to_str(job->JobType));
393          bsendmsg(ua, "fileset=%s", job->fileset->name());
394          bsendmsg(ua, "enabled=%d", job->enabled);
395          bsendmsg(ua, "catalog=%s", job->client->catalog->name());
396       }
397    } 
398    /* Client defaults */
399    else if (strcmp(ua->argk[1], "client") == 0) {
400       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
401          return true;   
402       }
403       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
404       if (client) {
405          bsendmsg(ua, "client=%s", client->name());
406          bsendmsg(ua, "address=%s", client->address);
407          bsendmsg(ua, "fdport=%d", client->FDport);
408          bsendmsg(ua, "file_retention=%d", client->FileRetention);
409          bsendmsg(ua, "job_retention=%d", client->JobRetention);
410          bsendmsg(ua, "autoprune=%d", client->AutoPrune);
411          bsendmsg(ua, "catalog=%s", client->catalog->name());
412       }
413    }
414    /* Storage defaults */
415    else if (strcmp(ua->argk[1], "storage") == 0) {
416       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
417          return true;
418       }
419       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
420       DEVICE *device;
421       if (storage) {
422          bsendmsg(ua, "storage=%s", storage->name());
423          bsendmsg(ua, "address=%s", storage->address);
424          bsendmsg(ua, "enabled=%d", storage->enabled);
425          bsendmsg(ua, "media_type=%s", storage->media_type);
426          bsendmsg(ua, "sdport=%d", storage->SDport);
427          device = (DEVICE *)storage->device->first();
428          bsendmsg(ua, "device=%s", device->name());
429          if (storage->device->size() > 1) {
430             while ((device = (DEVICE *)storage->device->next())) {
431                bsendmsg(ua, ",%s", device->name());
432             }
433          }
434       }
435    }
436    /* Pool defaults */
437    else if (strcmp(ua->argk[1], "pool") == 0) {
438       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
439          return true;
440       }
441       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
442       if (pool) {
443          bsendmsg(ua, "pool=%s", pool->name());
444          bsendmsg(ua, "pool_type=%s", pool->pool_type);
445          bsendmsg(ua, "label_format=%s", pool->label_format?pool->label_format:"");
446          bsendmsg(ua, "use_volume_once=%d", pool->use_volume_once);
447          bsendmsg(ua, "purge_oldest_volume=%d", pool->purge_oldest_volume);
448          bsendmsg(ua, "recycle_oldest_volume=%d", pool->recycle_oldest_volume);
449          bsendmsg(ua, "recycle_current_volume=%d", pool->recycle_current_volume);
450          bsendmsg(ua, "max_volumes=%d", pool->max_volumes);
451          bsendmsg(ua, "vol_retention=%d", pool->VolRetention);
452          bsendmsg(ua, "vol_use_duration=%d", pool->VolUseDuration);
453          bsendmsg(ua, "max_vol_jobs=%d", pool->MaxVolJobs);
454          bsendmsg(ua, "max_vol_files=%d", pool->MaxVolFiles);
455          bsendmsg(ua, "max_vol_bytes=%d", pool->MaxVolBytes);
456          bsendmsg(ua, "auto_prune=%d", pool->AutoPrune);
457          bsendmsg(ua, "recycle=%d", pool->Recycle);
458       }
459    }
460    return true;
461 }