2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
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.
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.
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
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.
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.
36 * Kern Sibbald, April MMII
44 /* Imported variables */
47 extern struct s_res resources[];
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);
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);
70 static bool api_cmd(UAContext *ua, const char *cmd);
71 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
72 static bool dot_help_cmd(UAContext *ua, const char *cmd);
74 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help; };
75 static struct cmdstruct commands[] = {
76 { NT_(".api"), api_cmd, NULL},
77 { NT_(".backups"), backupscmd, NULL},
78 { NT_(".clients"), clientscmd, NULL},
79 { NT_(".defaults"), defaultscmd, NULL},
80 { NT_(".die"), diecmd, NULL},
81 { NT_(".exit"), dot_quit_cmd, NULL},
82 { NT_(".filesets"), filesetscmd, NULL},
83 { NT_(".help"), dot_help_cmd, NULL},
84 { NT_(".jobs"), jobscmd, NULL},
85 { NT_(".levels"), levelscmd, NULL},
86 { NT_(".messages"), getmsgscmd, NULL},
87 { NT_(".msgs"), msgscmd, NULL},
88 { NT_(".pools"), poolscmd, NULL},
89 { NT_(".quit"), dot_quit_cmd, NULL},
90 { NT_(".status"), dot_status_cmd, NULL},
91 { NT_(".storage"), storagecmd, NULL},
92 { NT_(".types"), typescmd, NULL}
94 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
97 * Execute a command from the UA
99 int do_a_dot_command(UAContext *ua, const char *cmd)
105 BSOCK *user = ua->UA_sock;
107 Dmsg1(1400, "Dot command: %s\n", user->msg);
112 len = strlen(ua->argk[0]);
114 if (ua->api) user->signal(BNET_CMD_BEGIN);
115 if (ua->api) user->signal(BNET_CMD_OK);
116 return 1; /* no op */
118 for (i=0; i<comsize; i++) { /* search for command */
119 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
121 /* Check if command permitted, but "quit" is always OK */
122 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
123 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
127 if (ua->api) user->signal(BNET_CMD_BEGIN);
128 ok = (*commands[i].func)(ua, cmd); /* go execute command */
135 pm_strcat(user->msg, _(": is an invalid command.\n"));
136 user->msglen = strlen(user->msg);
139 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
143 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
149 static bool dot_help_cmd(UAContext *ua, const char *cmd)
155 static bool getmsgscmd(UAContext *ua, const char *cmd)
157 if (console_msg_pending) {
158 do_messages(ua, cmd);
164 * Create segmentation fault
166 static bool diecmd(UAContext *ua, const char *cmd)
171 bsendmsg(ua, _("The Director will segment fault.\n"));
172 a = jcr->JobId; /* ref NULL pointer */
173 jcr->JobId = 1000; /* another ref NULL pointer */
177 static bool jobscmd(UAContext *ua, const char *cmd)
181 while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) {
182 if (acl_access_ok(ua, Job_ACL, job->name())) {
183 bsendmsg(ua, "%s\n", job->name());
190 static bool filesetscmd(UAContext *ua, const char *cmd)
194 while ( (fs = (FILESET *)GetNextRes(R_FILESET, (RES *)fs)) ) {
195 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
196 bsendmsg(ua, "%s\n", fs->name());
203 static bool clientscmd(UAContext *ua, const char *cmd)
205 CLIENT *client = NULL;
207 while ( (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)) ) {
208 if (acl_access_ok(ua, Client_ACL, client->name())) {
209 bsendmsg(ua, "%s\n", client->name());
216 static bool msgscmd(UAContext *ua, const char *cmd)
220 while ( (msgs = (MSGS *)GetNextRes(R_MSGS, (RES *)msgs)) ) {
221 bsendmsg(ua, "%s\n", msgs->name());
227 static bool poolscmd(UAContext *ua, const char *cmd)
231 while ( (pool = (POOL *)GetNextRes(R_POOL, (RES *)pool)) ) {
232 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
233 bsendmsg(ua, "%s\n", pool->name());
240 static bool storagecmd(UAContext *ua, const char *cmd)
244 while ( (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)) ) {
245 if (acl_access_ok(ua, Storage_ACL, store->name())) {
246 bsendmsg(ua, "%s\n", store->name());
254 static bool typescmd(UAContext *ua, const char *cmd)
256 bsendmsg(ua, "Backup\n");
257 bsendmsg(ua, "Restore\n");
258 bsendmsg(ua, "Admin\n");
259 bsendmsg(ua, "Verify\n");
260 bsendmsg(ua, "Migrate\n");
264 static int client_backups_handler(void *ctx, int num_field, char **row)
266 UAContext *ua = (UAContext *)ctx;
267 bsendmsg(ua, "| %s | %s | %s | %s | %s | %s | %s | %s |\n",
268 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
273 * If this command is called, it tells the director that we
274 * are a program that wants a sort of API, and hence,
275 * we will probably suppress certain output, include more
276 * error codes, and most of all send back a good number
277 * of new signals that indicate whether or not the command
280 static bool api_cmd(UAContext *ua, const char *cmd)
282 /* Eventually we will probably have several levels or
283 * capabilities enabled by this.
290 * Return the backups for this client
292 static bool backupscmd(UAContext *ua, const char *cmd)
294 if (!open_client_db(ua)) {
297 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || strcmp(ua->argk[2], "fileset") != 0) {
300 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
301 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
304 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
305 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
306 bsendmsg(ua, _("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
314 static bool levelscmd(UAContext *ua, const char *cmd)
316 bsendmsg(ua, "Incremental\n");
317 bsendmsg(ua, "Full\n");
318 bsendmsg(ua, "Differential\n");
319 bsendmsg(ua, "Catalog\n");
320 bsendmsg(ua, "InitCatalog\n");
321 bsendmsg(ua, "VolumeToCatalog\n");
326 * Return default values for a job
328 static bool defaultscmd(UAContext *ua, const char *cmd)
335 if (ua->argc != 2 || !ua->argv[1]) {
340 if (strcmp(ua->argk[1], "job") == 0) {
341 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
344 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
347 bsendmsg(ua, "job=%s", job->name());
348 bsendmsg(ua, "pool=%s", job->pool->name());
349 bsendmsg(ua, "messages=%s", job->messages->name());
350 bsendmsg(ua, "client=%s", job->client->name());
351 get_job_storage(&store, job, NULL);
352 bsendmsg(ua, "storage=%s", store.store->name());
353 bsendmsg(ua, "where=%s", job->RestoreWhere?job->RestoreWhere:"");
354 bsendmsg(ua, "level=%s", level_to_str(job->JobLevel));
355 bsendmsg(ua, "type=%s", job_type_to_str(job->JobType));
356 bsendmsg(ua, "fileset=%s", job->fileset->name());
357 bsendmsg(ua, "enabled=%d", job->enabled);
358 bsendmsg(ua, "catalog=%s", job->client->catalog->name());
361 /* Client defaults */
362 else if (strcmp(ua->argk[1], "client") == 0) {
363 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
366 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
368 bsendmsg(ua, "client=%s", client->name());
369 bsendmsg(ua, "address=%s", client->address);
370 bsendmsg(ua, "fdport=%d", client->FDport);
371 bsendmsg(ua, "file_retention=%d", client->FileRetention);
372 bsendmsg(ua, "job_retention=%d", client->JobRetention);
373 bsendmsg(ua, "autoprune=%d", client->AutoPrune);
374 bsendmsg(ua, "catalog=%s", client->catalog->name());
377 /* Storage defaults */
378 else if (strcmp(ua->argk[1], "storage") == 0) {
379 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
382 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
385 bsendmsg(ua, "storage=%s", storage->name());
386 bsendmsg(ua, "address=%s", storage->address);
387 bsendmsg(ua, "enabled=%d", storage->enabled);
388 bsendmsg(ua, "media_type=%s", storage->media_type);
389 bsendmsg(ua, "sdport=%d", storage->SDport);
390 device = (DEVICE *)storage->device->first();
391 bsendmsg(ua, "device=%s", device->name());
392 if (storage->device->size() > 1) {
393 while ((device = (DEVICE *)storage->device->next())) {
394 bsendmsg(ua, ",%s", device->name());
400 else if (strcmp(ua->argk[1], "pool") == 0) {
401 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
404 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
406 bsendmsg(ua, "pool=%s", pool->name());
407 bsendmsg(ua, "pool_type=%s", pool->pool_type);
408 bsendmsg(ua, "label_format=%s", pool->label_format?pool->label_format:"");
409 bsendmsg(ua, "use_volume_once=%d", pool->use_volume_once);
410 bsendmsg(ua, "purge_oldest_volume=%d", pool->purge_oldest_volume);
411 bsendmsg(ua, "recycle_oldest_volume=%d", pool->recycle_oldest_volume);
412 bsendmsg(ua, "recycle_current_volume=%d", pool->recycle_current_volume);
413 bsendmsg(ua, "max_volumes=%d", pool->max_volumes);
414 bsendmsg(ua, "vol_retention=%d", pool->VolRetention);
415 bsendmsg(ua, "vol_use_duration=%d", pool->VolUseDuration);
416 bsendmsg(ua, "max_vol_jobs=%d", pool->MaxVolJobs);
417 bsendmsg(ua, "max_vol_files=%d", pool->MaxVolFiles);
418 bsendmsg(ua, "max_vol_bytes=%d", pool->MaxVolBytes);
419 bsendmsg(ua, "auto_prune=%d", pool->AutoPrune);
420 bsendmsg(ua, "recycle=%d", pool->Recycle);