]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_dotcmds.c
Tweak messages from .bvfs commands
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
index 62c8cf500e41d7a984abc3c9f60ff86a4d716c08..c7fd97dead279360f7305f9d5ad26771fc25b79a 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-2010 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.
    This program is Free Software; you can redistribute it and/or
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -52,7 +52,7 @@ extern bool dot_status_cmd(UAContext *ua, const char *cmd);
 
 
 /* Forward referenced functions */
 
 
 /* Forward referenced functions */
-static bool diecmd(UAContext *ua, const char *cmd);
+static bool admin_cmds(UAContext *ua, const char *cmd);
 static bool jobscmd(UAContext *ua, const char *cmd);
 static bool filesetscmd(UAContext *ua, const char *cmd);
 static bool clientscmd(UAContext *ua, const char *cmd);
 static bool jobscmd(UAContext *ua, const char *cmd);
 static bool filesetscmd(UAContext *ua, const char *cmd);
 static bool clientscmd(UAContext *ua, const char *cmd);
@@ -73,40 +73,50 @@ 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 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 dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
+static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
+static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
+static bool dot_bvfs_cleanup(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);
 
 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);
+static int one_handler(void *ctx, int num_field, char **row);
 
 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 */
 
 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} 
+ { NT_(".api"),        api_cmd,                  NULL,       false},
+ { NT_(".backups"),    backupscmd,               NULL,       false},
+ { NT_(".clients"),    clientscmd,               NULL,       true},
+ { NT_(".defaults"),   defaultscmd,              NULL,       false},
+ { NT_(".die"),        admin_cmds,               NULL,       false},
+ { NT_(".dump"),       admin_cmds,               NULL,       false},
+ { NT_(".exit"),       admin_cmds,               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_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL,       true},
+ { NT_(".bvfs_versions"), dot_bvfs_versions,     NULL,       true},
+ { NT_(".bvfs_restore"), dot_bvfs_restore,       NULL,       true},
+ { NT_(".bvfs_cleanup"), dot_bvfs_cleanup,       NULL,       true},
+ { NT_(".types"),      typescmd,                 NULL,       false}
              };
 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
 
              };
 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
 
@@ -165,8 +175,7 @@ bool do_a_dot_command(UAContext *ua)
 
 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
 {
 
 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
 {
-
-   if (!open_client_db(ua)) {
+   if (!open_new_client_db(ua)) {
       return 1;
    }
 
       return 1;
    }
 
@@ -179,6 +188,8 @@ static bool dot_bvfs_update(UAContext *ua, const char *cmd)
       /* update cache for all jobids */
       bvfs_update_cache(ua->jcr, ua->db);
    }
       /* update cache for all jobids */
       bvfs_update_cache(ua->jcr, ua->db);
    }
+   
+   close_db(ua);
    return true;
 }
 
    return true;
 }
 
@@ -187,31 +198,77 @@ static int bvfs_result_handler(void *ctx, int fields, char **row)
    UAContext *ua = (UAContext *)ctx;
    struct stat statp;
    int32_t LinkFI;
    UAContext *ua = (UAContext *)ctx;
    struct stat statp;
    int32_t LinkFI;
-   const char *fileid;
-   char *lstat;
+   char *fileid=row[BVFS_FileId];
+   char *lstat=row[BVFS_LStat];
+   char *jobid=row[BVFS_JobId];
+   
    char empty[] = "A A A A A A A A A A A A A A";
    char empty[] = "A A A A A A A A A A A A A A";
+   char zero[] = "0";
 
 
-   lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
-   fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
+   /* We need to deal with non existant path */
+   if (!fileid || !is_a_number(fileid)) {
+      lstat = empty;
+      jobid = zero;
+      fileid = zero;
+   }
 
    memset(&statp, 0, sizeof(struct stat));
    decode_stat(lstat, &statp, &LinkFI);
 
 
    memset(&statp, 0, sizeof(struct stat));
    decode_stat(lstat, &statp, &LinkFI);
 
-   Dmsg1(0, "type=%s\n", row[0]);
+   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,
    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);
+                   jobid, lstat, path);
+
+   } else if (bvfs_is_version(row)) {
+      ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
+                   row[BVFS_FilenameId], fileid, jobid,
+                   lstat, row[BVFS_Md5], row[BVFS_VolName], 
+                   row[BVFS_VolInchanger]);
 
    } else if (bvfs_is_file(row)) {
       ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
 
    } 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]);
+                   row[BVFS_FilenameId], fileid, jobid,
+                   lstat, row[BVFS_Name]);
    }
 
    return 0;
 }
 
    }
 
    return 0;
 }
 
+static bool bvfs_parse_arg_version(UAContext *ua,
+                                   char **client,
+                                   DBId_t *fnid, 
+                                   bool *versions, 
+                                   bool *copies)
+{
+   *fnid=0;
+   *client=NULL;
+   *versions=false;
+   *copies=false;
+
+   for (int i=1; i<ua->argc; i++) {
+      if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
+         if (is_a_number(ua->argv[i])) {
+            *fnid = str_to_int64(ua->argv[i]);
+         }
+      }
+
+      if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
+         *client = ua->argv[i];
+      }
+
+      if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
+         *copies = true;
+      }
+
+      if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
+         *versions = true;
+      }
+   }
+   return (*client && *fnid > 0);
+}
+
 static bool bvfs_parse_arg(UAContext *ua, 
                            DBId_t *pathid, char **path, char **jobid,
                            int *limit, int *offset)
 static bool bvfs_parse_arg(UAContext *ua, 
                            DBId_t *pathid, char **path, char **jobid,
                            int *limit, int *offset)
@@ -228,6 +285,7 @@ static bool bvfs_parse_arg(UAContext *ua,
             *pathid = str_to_int64(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_("path")) == 0) {
          *path = ua->argv[i];
       }
@@ -262,6 +320,58 @@ static bool bvfs_parse_arg(UAContext *ua,
    return true;
 }
 
    return true;
 }
 
+/* .bvfs_cleanup path=b2XXXXX
+ */
+static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
+{
+   int i;
+   if ((i = find_arg_with_value(ua, "path")) >= 0) {
+      open_client_db(ua);
+      Bvfs fs(ua->jcr, ua->db);
+      fs.drop_restore_list(ua->argv[i]);
+   }
+   return true;
+}
+
+/* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
+ */
+static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
+{
+   DBId_t pathid=0;
+   int limit=2000, offset=0, i;
+   char *path=NULL, *jobid=NULL;
+   char *empty = (char *)"";
+   char *fileid, *dirid, *hardlink, *id;
+   id = fileid = dirid = hardlink = empty;
+
+   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);
+
+   if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
+      fileid = ua->argv[i];
+   }
+   if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
+      dirid = ua->argv[i];
+   }
+   if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
+      hardlink = ua->argv[i];
+   }
+
+   if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
+      ua->send_msg("OK\n");
+   } else {
+      ua->error_msg("Can't create restore list\n");
+   }
+   return true;
+}
+
 /* 
  * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
  * .bvfs_lsfiles jobid=1,2,3,4 path=/
 /* 
  * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
  * .bvfs_lsfiles jobid=1,2,3,4 path=/
@@ -271,6 +381,8 @@ static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
    DBId_t pathid=0;
    int limit=2000, offset=0;
    char *path=NULL, *jobid=NULL;
    DBId_t pathid=0;
    int limit=2000, offset=0;
    char *path=NULL, *jobid=NULL;
+   char *pattern=NULL;
+   int i;
 
    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
                        &limit, &offset))
 
    if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
                        &limit, &offset))
@@ -278,18 +390,23 @@ static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
       ua->error_msg("Can't find jobid, pathid or path argument\n");
       return true;              /* not enough param */
    }
       ua->error_msg("Can't find jobid, pathid or path argument\n");
       return true;              /* not enough param */
    }
+   if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
+      pattern = ua->argv[i];
+   }
 
    Bvfs fs(ua->jcr, ua->db);
    fs.set_jobids(jobid);   
    fs.set_handler(bvfs_result_handler, ua);
    fs.set_limit(limit);
 
    Bvfs fs(ua->jcr, ua->db);
    fs.set_jobids(jobid);   
    fs.set_handler(bvfs_result_handler, ua);
    fs.set_limit(limit);
-
+   if (pattern) {
+      fs.set_pattern(pattern);
+   }
    if (pathid) {
       fs.ch_dir(pathid);
    } else {
       fs.ch_dir(path);
    }
    if (pathid) {
       fs.ch_dir(pathid);
    } else {
       fs.ch_dir(path);
    }
-
+   
    fs.set_offset(offset);
 
    fs.ls_files();
    fs.set_offset(offset);
 
    fs.ls_files();
@@ -334,6 +451,96 @@ static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
    return true;
 }
 
    return true;
 }
 
+/* 
+ * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
+ * (jobid isn't used)
+ */
+static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
+{
+   DBId_t pathid=0, fnid=0;
+   int limit=2000, offset=0;
+   char *path=NULL, *jobid=NULL, *client=NULL;
+   bool copies=false, versions=false;
+   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 */
+   }
+
+   if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
+   {
+      ua->error_msg("Can't find client or fnid argument\n");
+      return true;              /* not enough param */
+   }
+
+   Bvfs fs(ua->jcr, ua->db);
+   fs.set_limit(limit);
+   fs.set_see_all_versions(versions);
+   fs.set_see_copies(copies);
+   fs.set_handler(bvfs_result_handler, ua);
+   fs.set_offset(offset);
+   fs.get_all_file_versions(pathid, fnid, client);
+
+   return true;
+}
+
+/* .bvfs_get_jobids jobid=1
+ *  -> returns needed jobids to restore
+ * .bvfs_get_jobids jobid=1 all
+ *  -> returns needed jobids to restore with all filesets a JobId=1 time
+ */
+static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
+{
+   JOB_DBR jr;
+   db_list_ctx jobids, tempids;
+   int pos;
+   char ed1[50];
+   POOL_MEM query;
+   dbid_list ids;               /* Store all FileSetIds for this client */
+
+   if (!open_client_db(ua)) {
+      return true;
+   }
+
+   memset(&jr, 0, sizeof(JOB_DBR));
+   if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
+      jr.JobId = str_to_int64(ua->argv[pos]);
+   }
+
+   if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
+      ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
+                    ua->cmd, db_strerror(ua->db));
+      return true;
+   }
+
+   /* If we have the "all" option, we do a search on all defined fileset
+    * for this client
+    */
+   if (find_arg(ua, "all") > 0) {
+      edit_int64(jr.ClientId, ed1);
+      Mmsg(query, uar_sel_filesetid, ed1);
+      db_get_query_dbids(ua->jcr, ua->db, query, ids);
+   } else {
+      ids.num_ids = 1;
+      ids.DBId[0] = jr.FileSetId;
+   }
+
+   jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
+
+   /* Foreach different FileSet, we build a restore jobid list */
+   for (int i=0; i < ids.num_ids; i++) {
+      jr.FileSetId = ids.DBId[i];
+      if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
+         return true;
+      }
+      jobids.cat(tempids);
+   }
+
+   ua->send_msg("%s\n", jobids.list);
+   return true;
+}
+
 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
 {
    quit_cmd(ua, cmd);
 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
 {
    quit_cmd(ua, cmd);
@@ -355,7 +562,7 @@ static bool getmsgscmd(UAContext *ua, const char *cmd)
 }
 
 #ifdef DEVELOPER
 }
 
 #ifdef DEVELOPER
-static void do_storage_die(UAContext *ua, STORE *store)
+static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
 {
    BSOCK *sd;
    JCR *jcr = ua->jcr;
 {
    BSOCK *sd;
    JCR *jcr = ua->jcr;
@@ -373,7 +580,7 @@ static void do_storage_die(UAContext *ua, STORE *store)
    }
    Dmsg0(120, _("Connected to storage daemon\n"));
    sd = jcr->store_bsock;
    }
    Dmsg0(120, _("Connected to storage daemon\n"));
    sd = jcr->store_bsock;
-   sd->fsend(".die");
+   sd->fsend("%s", cmd);
    if (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
    if (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
@@ -383,7 +590,7 @@ static void do_storage_die(UAContext *ua, STORE *store)
    return;
 }
 
    return;
 }
 
-static void do_client_die(UAContext *ua, CLIENT *client)
+static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
 {
    BSOCK *fd;
 
 {
    BSOCK *fd;
 
@@ -399,7 +606,7 @@ static void do_client_die(UAContext *ua, CLIENT *client)
    }
    Dmsg0(120, "Connected to file daemon\n");
    fd = ua->jcr->file_bsock;
    }
    Dmsg0(120, "Connected to file daemon\n");
    fd = ua->jcr->file_bsock;
-   fd->fsend(".die");
+   fd->fsend("%s", cmd);
    if (fd->recv() >= 0) {
       ua->send_msg("%s", fd->msg);
    }
    if (fd->recv() >= 0) {
       ua->send_msg("%s", fd->msg);
    }
@@ -410,91 +617,116 @@ static void do_client_die(UAContext *ua, CLIENT *client)
 }
 
 /*
 }
 
 /*
- * Create segmentation fault
+ *   .die (seg fault)
+ *   .dump (sm_dump)
+ *   .exit (no arg => .quit)
  */
  */
-static bool diecmd(UAContext *ua, const char *cmd)
+static bool admin_cmds(UAContext *ua, const char *cmd)
 {
 {
-   STORE *store;
-   CLIENT *client;
+   pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+   STORE *store=NULL;
+   CLIENT *client=NULL;
+   bool dir=false;
+   bool do_deadlock=false;
+   const char *remote_cmd;
    int i;
    JCR *jcr = NULL;
    int a;
    int i;
    JCR *jcr = NULL;
    int a;
-
-   Dmsg1(120, "diecmd:%s:\n", cmd);
-
+   if (strncmp(ua->argk[0], ".die", 4) == 0) {
+      if (find_arg(ua, "deadlock") > 0) {
+         do_deadlock = true;
+         remote_cmd = ".die deadlock";
+      } else {
+         remote_cmd = ".die";
+      }
+   } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
+      remote_cmd = "sm_dump";
+   } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
+      remote_cmd = "exit";
+   } else {
+      ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
+      return true;
+   }
    /* General debug? */
    for (i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], "dir") == 0 ||
           strcasecmp(ua->argk[i], "director") == 0) {
    /* General debug? */
    for (i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], "dir") == 0 ||
           strcasecmp(ua->argk[i], "director") == 0) {
-         ua->send_msg(_("The Director will segment fault.\n"));
-         a = jcr->JobId; /* ref NULL pointer */
-         jcr->JobId = 1000; /* another ref NULL pointer */
-         return 1;
+         dir = true;
       }
       if (strcasecmp(ua->argk[i], "client") == 0 ||
           strcasecmp(ua->argk[i], "fd") == 0) {
          client = NULL;
          if (ua->argv[i]) {
             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
       }
       if (strcasecmp(ua->argk[i], "client") == 0 ||
           strcasecmp(ua->argk[i], "fd") == 0) {
          client = NULL;
          if (ua->argv[i]) {
             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
-            if (client) {
-               do_client_die(ua, client);
-               return 1;
-            }
          }
          }
-         client = select_client_resource(ua);
-         if (client) {
-            do_client_die(ua, client);
-            return 1;
+         if (!client) {
+            client = select_client_resource(ua);
          }
       }
          }
       }
-
+   
       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
          store = NULL;
          if (ua->argv[i]) {
             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
          store = NULL;
          if (ua->argv[i]) {
             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
-            if (store) {
-               do_storage_die(ua, store);
-               return 1;
-            }
          }
          }
-         store = get_storage_resource(ua, false/*no default*/);
-         if (store) {
-            do_storage_die(ua, store);
-            return 1;
+         if (!store) {
+            store = get_storage_resource(ua, false/*no default*/);
          }
       }
    }
          }
       }
    }
-   /*
-    * We didn't find an appropriate keyword above, so
-    * prompt the user.
-    */
-   start_prompt(ua, _("Available daemons are: \n"));
-   add_prompt(ua, _("Director"));
-   add_prompt(ua, _("Storage"));
-   add_prompt(ua, _("Client"));
-   switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
-   case 0:                         /* Director */
-      ua->send_msg(_("The Director will segment fault.\n"));
-      a = jcr->JobId; /* ref NULL pointer */
-      jcr->JobId = 1000; /* another ref NULL pointer */
-      break;
-   case 1:
-      store = get_storage_resource(ua, false/*no default*/);
-      if (store) {
-         do_storage_die(ua, store);
+
+   if (!dir && !store && !client) {
+      /*
+       * We didn't find an appropriate keyword above, so
+       * prompt the user.
+       */
+      start_prompt(ua, _("Available daemons are: \n"));
+      add_prompt(ua, _("Director"));
+      add_prompt(ua, _("Storage"));
+      add_prompt(ua, _("Client"));
+      switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
+      case 0:                         /* Director */
+         dir=true;
+         break;
+      case 1:
+         store = get_storage_resource(ua, false/*no default*/);
+         break;
+      case 2:
+         client = select_client_resource(ua);
+         break;
+      default:
+         break;
       }
       }
-      break;
-   case 2:
-      client = select_client_resource(ua);
-      if (client) {
-         do_client_die(ua, client);
+   }
+
+   if (store) {
+      do_storage_cmd(ua, store, remote_cmd);
+   }
+
+   if (client) {
+      do_client_cmd(ua, client, remote_cmd);
+   }
+
+   if (dir) {
+      if (strncmp(remote_cmd, ".die", 4) == 0) {
+         if (do_deadlock) {
+            ua->send_msg(_("The Director will generate a deadlock.\n"));
+            P(mutex); 
+            P(mutex);
+         }
+         ua->send_msg(_("The Director will segment fault.\n"));
+         a = jcr->JobId; /* ref NULL pointer */
+         jcr->JobId = 1000; /* another ref NULL pointer */
+
+      } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
+         sm_dump(false, true);
+      } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
+         dot_quit_cmd(ua, cmd);
       }
       }
-      break;
-   default:
-      break;
    }
    }
+
    return true;
 }
 
    return true;
 }
 
@@ -503,8 +735,9 @@ static bool diecmd(UAContext *ua, const char *cmd)
 /*
  * Dummy routine for non-development version
  */
 /*
  * Dummy routine for non-development version
  */
-static bool diecmd(UAContext *ua, const char *cmd)
+static bool admin_cmds(UAContext *ua, const char *cmd)
 {
 {
+   ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
    return true;
 }
 
    return true;
 }
 
@@ -611,6 +844,7 @@ static bool typescmd(UAContext *ua, const char *cmd)
    ua->send_msg("Admin\n");
    ua->send_msg("Verify\n");
    ua->send_msg("Migrate\n");
    ua->send_msg("Admin\n");
    ua->send_msg("Verify\n");
    ua->send_msg("Migrate\n");
+   ua->send_msg("Copy\n");
    return true;
 }
 
    return true;
 }
 
@@ -770,6 +1004,7 @@ static bool levelscmd(UAContext *ua, const char *cmd)
    ua->send_msg("Catalog\n");
    ua->send_msg("InitCatalog\n");
    ua->send_msg("VolumeToCatalog\n");
    ua->send_msg("Catalog\n");
    ua->send_msg("InitCatalog\n");
    ua->send_msg("VolumeToCatalog\n");
+   ua->send_msg("Base\n");
    return true;
 }
 
    return true;
 }