X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fua_dotcmds.c;h=b6c52c069cc5c9321805aff7d7c0328c70ddbaf2;hb=480ed6815f1f3e860ce9e245733208aed3888bef;hp=da23d78a368e2c7e90713e5fe01290f8974fbe17;hpb=c879001a9d7a768affedf971d023f943eb1bf787;p=bacula%2Fbacula diff --git a/bacula/src/dird/ua_dotcmds.c b/bacula/src/dird/ua_dotcmds.c index da23d78a36..b6c52c069c 100644 --- a/bacula/src/dird/ua_dotcmds.c +++ b/bacula/src/dird/ua_dotcmds.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2008 Free Software Foundation Europe e.V. + Copyright (C) 2002-2009 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -35,11 +35,12 @@ * * Kern Sibbald, April MMII * - * Version $Id$ */ #include "bacula.h" #include "dird.h" +#include "cats/bvfs.h" +#include "findlib/find.h" /* Imported variables */ @@ -63,32 +64,49 @@ static bool typescmd(UAContext *ua, const char *cmd); static bool backupscmd(UAContext *ua, const char *cmd); static bool levelscmd(UAContext *ua, const char *cmd); static bool getmsgscmd(UAContext *ua, const char *cmd); +static bool volstatuscmd(UAContext *ua, const char *cmd); +static bool mediatypescmd(UAContext *ua, const char *cmd); +static bool locationscmd(UAContext *ua, const char *cmd); +static bool mediacmd(UAContext *ua, const char *cmd); +static bool aopcmd(UAContext *ua, const char *cmd); + +static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd); +static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd); +static bool dot_bvfs_update(UAContext *ua, const char *cmd); static bool api_cmd(UAContext *ua, const char *cmd); static bool sql_cmd(UAContext *ua, const char *cmd); static bool dot_quit_cmd(UAContext *ua, const char *cmd); static bool dot_help_cmd(UAContext *ua, const char *cmd); -struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help; }; -static struct cmdstruct commands[] = { - { NT_(".api"), api_cmd, NULL}, - { NT_(".backups"), backupscmd, NULL}, - { NT_(".clients"), clientscmd, NULL}, - { NT_(".defaults"), defaultscmd, NULL}, - { NT_(".die"), diecmd, NULL}, - { NT_(".exit"), dot_quit_cmd, NULL}, - { NT_(".filesets"), filesetscmd, NULL}, - { NT_(".help"), dot_help_cmd, NULL}, - { NT_(".jobs"), jobscmd, NULL}, - { NT_(".levels"), levelscmd, NULL}, - { NT_(".messages"), getmsgscmd, NULL}, - { NT_(".msgs"), msgscmd, NULL}, - { NT_(".pools"), poolscmd, NULL}, - { NT_(".quit"), dot_quit_cmd, NULL}, - { NT_(".sql"), sql_cmd, NULL}, - { NT_(".status"), dot_status_cmd, NULL}, - { NT_(".storage"), storagecmd, NULL}, - { NT_(".types"), typescmd, NULL} +struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;}; +static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */ + { NT_(".api"), api_cmd, NULL, false}, + { NT_(".backups"), backupscmd, NULL, false}, + { NT_(".clients"), clientscmd, NULL, true}, + { NT_(".defaults"), defaultscmd, NULL, false}, + { NT_(".die"), diecmd, NULL, false}, + { NT_(".exit"), dot_quit_cmd, NULL, false}, + { NT_(".filesets"), filesetscmd, NULL, false}, + { NT_(".help"), dot_help_cmd, NULL, false}, + { NT_(".jobs"), jobscmd, NULL, true}, + { NT_(".levels"), levelscmd, NULL, false}, + { NT_(".messages"), getmsgscmd, NULL, false}, + { NT_(".msgs"), msgscmd, NULL, false}, + { NT_(".pools"), poolscmd, NULL, true}, + { NT_(".quit"), dot_quit_cmd, NULL, false}, + { NT_(".sql"), sql_cmd, NULL, false}, + { NT_(".status"), dot_status_cmd, NULL, false}, + { NT_(".storage"), storagecmd, NULL, true}, + { NT_(".volstatus"), volstatuscmd, NULL, true}, + { NT_(".media"), mediacmd, NULL, true}, + { NT_(".mediatypes"), mediatypescmd, NULL, true}, + { NT_(".locations"), locationscmd, NULL, true}, + { NT_(".actiononpurge"),aopcmd, NULL, true}, + { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true}, + { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,NULL, true}, + { NT_(".bvfs_update"), dot_bvfs_update, NULL, true}, + { NT_(".types"), typescmd, NULL, false} }; #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct))) @@ -116,6 +134,11 @@ bool do_a_dot_command(UAContext *ua) } for (i=0; iargk[0], _(commands[i].key), len) == 0) { + /* Check if this command is authorized in RunScript */ + if (ua->runscript && !commands[i].use_in_rs) { + ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]); + break; + } bool gui = ua->gui; /* Check if command permitted, but "quit" is always OK */ if (strcmp(ua->argk[0], NT_(".quit")) != 0 && @@ -126,6 +149,7 @@ bool do_a_dot_command(UAContext *ua) ua->gui = true; if (ua->api) user->signal(BNET_CMD_BEGIN); ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ + if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); ua->gui = gui; found = true; break; @@ -136,10 +160,180 @@ bool do_a_dot_command(UAContext *ua) ua->error_msg("%s", user->msg); ok = false; } - if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); return ok; } +static bool dot_bvfs_update(UAContext *ua, const char *cmd) +{ + + if (!open_client_db(ua)) { + return 1; + } + + int pos = find_arg_with_value(ua, "jobid"); + if (pos != -1 && is_a_number_list(ua->argv[pos])) { + POOL_MEM jobids; + pm_strcpy(jobids, ua->argv[pos]); + bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str()); + } else { + /* update cache for all jobids */ + bvfs_update_cache(ua->jcr, ua->db); + } + return true; +} + +static int bvfs_result_handler(void *ctx, int fields, char **row) +{ + UAContext *ua = (UAContext *)ctx; + struct stat statp; + int32_t LinkFI; + const char *fileid; + char *lstat; + char empty[] = "A A A A A A A A A A A A A A"; + + lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty; + fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0"; + + memset(&statp, 0, sizeof(struct stat)); + decode_stat(lstat, &statp, &LinkFI); + + Dmsg1(100, "type=%s\n", row[0]); + if (bvfs_is_dir(row)) { + char *path = bvfs_basename_dir(row[BVFS_Name]); + ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid, + row[BVFS_JobId], row[BVFS_LStat], path); + + } else if (bvfs_is_file(row)) { + ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], + row[BVFS_FilenameId], fileid, row[BVFS_JobId], + row[BVFS_LStat], row[BVFS_Name]); + } + + return 0; +} + +static bool bvfs_parse_arg(UAContext *ua, + DBId_t *pathid, char **path, char **jobid, + int *limit, int *offset) +{ + *pathid=0; + *limit=2000; + *offset=0; + *path=NULL; + *jobid=NULL; + + for (int i=1; iargc; i++) { + if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) { + if (is_a_number(ua->argv[i])) { + *pathid = str_to_int64(ua->argv[i]); + } + } + if (strcasecmp(ua->argk[i], NT_("path")) == 0) { + *path = ua->argv[i]; + } + + if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) { + if (is_a_number_list(ua->argv[i])) { + *jobid = ua->argv[i]; + } + } + + if (strcasecmp(ua->argk[i], NT_("limit")) == 0) { + if (is_a_number(ua->argv[i])) { + *limit = str_to_int64(ua->argv[i]); + } + } + + if (strcasecmp(ua->argk[i], NT_("offset")) == 0) { + if (is_a_number(ua->argv[i])) { + *offset = str_to_int64(ua->argv[i]); + } + } + } + + if (!((*pathid || *path) && *jobid)) { + return false; + } + + if (!open_client_db(ua)) { + return false; + } + + return true; +} + +/* + * .bvfs_lsfiles jobid=1,2,3,4 pathid=10 + * .bvfs_lsfiles jobid=1,2,3,4 path=/ + */ +static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd) +{ + DBId_t pathid=0; + int limit=2000, offset=0; + char *path=NULL, *jobid=NULL; + + if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, + &limit, &offset)) + { + ua->error_msg("Can't find jobid, pathid or path argument\n"); + return true; /* not enough param */ + } + + Bvfs fs(ua->jcr, ua->db); + fs.set_jobids(jobid); + fs.set_handler(bvfs_result_handler, ua); + fs.set_limit(limit); + + if (pathid) { + fs.ch_dir(pathid); + } else { + fs.ch_dir(path); + } + + fs.set_offset(offset); + + fs.ls_files(); + + return true; +} + +/* + * .bvfs_lsdirs jobid=1,2,3,4 pathid=10 + * .bvfs_lsdirs jobid=1,2,3,4 path=/ + * .bvfs_lsdirs jobid=1,2,3,4 path= + */ +static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd) +{ + DBId_t pathid=0; + int limit=2000, offset=0; + char *path=NULL, *jobid=NULL; + + if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, + &limit, &offset)) + { + ua->error_msg("Can't find jobid, pathid or path argument\n"); + return true; /* not enough param */ + } + + Bvfs fs(ua->jcr, ua->db); + fs.set_jobids(jobid); + fs.set_limit(limit); + fs.set_handler(bvfs_result_handler, ua); + + if (pathid) { + fs.ch_dir(pathid); + } else { + fs.ch_dir(path); + } + + fs.set_offset(offset); + + fs.ls_special_dirs(); + fs.ls_dirs(); + + return true; +} + static bool dot_quit_cmd(UAContext *ua, const char *cmd) { quit_cmd(ua, cmd); @@ -316,13 +510,24 @@ static bool diecmd(UAContext *ua, const char *cmd) #endif +/* + * Can use an argument to filter on JobType + * .jobs [type=B] + */ static bool jobscmd(UAContext *ua, const char *cmd) { JOB *job; + uint32_t type = 0; + int pos; + if ((pos = find_arg_with_value(ua, "type")) >= 0) { + type = ua->argv[pos][0]; + } LockRes(); foreach_res(job, R_JOB) { - if (acl_access_ok(ua, Job_ACL, job->name())) { - ua->send_msg("%s\n", job->name()); + if (!type || type == job->JobType) { + if (acl_access_ok(ua, Job_ACL, job->name())) { + ua->send_msg("%s\n", job->name()); + } } } UnlockRes(); @@ -392,6 +597,12 @@ static bool storagecmd(UAContext *ua, const char *cmd) return true; } +static bool aopcmd(UAContext *ua, const char *cmd) +{ + ua->send_msg("None\n"); + ua->send_msg("Truncate\n"); + return true; +} static bool typescmd(UAContext *ua, const char *cmd) { @@ -403,7 +614,6 @@ static bool typescmd(UAContext *ua, const char *cmd) return true; } - /* * If this command is called, it tells the director that we * are a program that wants a sort of API, and hence, @@ -463,6 +673,10 @@ static int sql_handler(void *ctx, int num_field, char **row) UAContext *ua = (UAContext *)ctx; POOL_MEM rows(PM_MESSAGE); + /* Check for nonsense */ + if (num_field == 0 || row == NULL || row[0] == NULL) { + return 0; /* nothing returned */ + } for (int i=0; num_field--; i++) { if (i == 0) { pm_strcpy(rows, NPRT(row[0])); @@ -498,19 +712,79 @@ static bool sql_cmd(UAContext *ua, const char *cmd) return true; } +static int one_handler(void *ctx, int num_field, char **row) +{ + UAContext *ua = (UAContext *)ctx; + ua->send_msg("%s\n", row[0]); + return 0; +} +static bool mediatypescmd(UAContext *ua, const char *cmd) +{ + if (!open_client_db(ua)) { + return true; + } + if (!db_sql_query(ua->db, + "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType", + one_handler, (void *)ua)) + { + ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db)); + } + return true; +} + +static bool mediacmd(UAContext *ua, const char *cmd) +{ + if (!open_client_db(ua)) { + return true; + } + if (!db_sql_query(ua->db, + "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName", + one_handler, (void *)ua)) + { + ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db)); + } + return true; +} + +static bool locationscmd(UAContext *ua, const char *cmd) +{ + if (!open_client_db(ua)) { + return true; + } + if (!db_sql_query(ua->db, + "SELECT DISTINCT Location FROM Location ORDER BY Location", + one_handler, (void *)ua)) + { + ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db)); + } + return true; +} static bool levelscmd(UAContext *ua, const char *cmd) { ua->send_msg("Incremental\n"); ua->send_msg("Full\n"); ua->send_msg("Differential\n"); + ua->send_msg("VirtualFull\n"); ua->send_msg("Catalog\n"); ua->send_msg("InitCatalog\n"); ua->send_msg("VolumeToCatalog\n"); return true; } +static bool volstatuscmd(UAContext *ua, const char *cmd) +{ + ua->send_msg("Append\n"); + ua->send_msg("Full\n"); + ua->send_msg("Used\n"); + ua->send_msg("Recycle\n"); + ua->send_msg("Purged\n"); + ua->send_msg("Cleaning\n"); + ua->send_msg("Error\n"); + return true; +} + /* * Return default values for a job */ @@ -608,6 +882,8 @@ static bool defaultscmd(UAContext *ua, const char *cmd) ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1)); ua->send_msg("auto_prune=%d", pool->AutoPrune); ua->send_msg("recycle=%d", pool->Recycle); + ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1)); + ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1)); } } return true;