Пример #1
0
/*
 *   Prune records from database
 *
 *    prune files (from) client=xxx [pool=yyy]
 *    prune jobs (from) client=xxx [pool=yyy]
 *    prune volume=xxx
 *    prune stats
 */
int prunecmd(UAContext *ua, const char *cmd)
{
   CLIENTRES *client;
   POOLRES *pool;
   POOL_DBR pr;
   MEDIA_DBR mr;
   utime_t retention;
   int kw;

   static const char *keywords[] = {
      NT_("Files"),
      NT_("Jobs"),
      NT_("Volume"),
      NT_("Stats"),
      NULL};

   if (!open_client_db(ua)) {
      return false;
   }

   /* First search args */
   kw = find_arg_keyword(ua, keywords);
   if (kw < 0 || kw > 3) {
      /* no args, so ask user */
      kw = do_keyword_prompt(ua, _("Choose item to prune"), keywords);
   }

   switch (kw) {
   case 0:  /* prune files */
      if (!(client = get_client_resource(ua))) {
         return false;
      }
      if (find_arg_with_value(ua, "pool") >= 0) {
         pool = get_pool_resource(ua);
      } else {
         pool = NULL;
      }
      /* Pool File Retention takes precedence over client File Retention */
      if (pool && pool->FileRetention > 0) {
         if (!confirm_retention(ua, &pool->FileRetention, "File")) {
            return false;
         }
      } else if (!confirm_retention(ua, &client->FileRetention, "File")) {
         return false;
      }
      prune_files(ua, client, pool);
      return true;
   case 1:  /* prune jobs */
      if (!(client = get_client_resource(ua))) {
         return false;
      }
      if (find_arg_with_value(ua, "pool") >= 0) {
         pool = get_pool_resource(ua);
      } else {
         pool = NULL;
      }
      /* Pool Job Retention takes precedence over client Job Retention */
      if (pool && pool->JobRetention > 0) {
         if (!confirm_retention(ua, &pool->JobRetention, "Job")) {
            return false;
         }
      } else if (!confirm_retention(ua, &client->JobRetention, "Job")) {
         return false;
      }
      /* ****FIXME**** allow user to select JobType */
      prune_jobs(ua, client, pool, JT_BACKUP);
      return 1;
   case 2:  /* prune volume */
      if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
         return false;
      }
      if (mr.Enabled == 2) {
         ua->error_msg(_("Cannot prune Volume \"%s\" because it is archived.\n"),
            mr.VolumeName);
         return false;
      }
      if (!confirm_retention(ua, &mr.VolRetention, "Volume")) {
         return false;
      }
      prune_volume(ua, &mr);
      return true;
   case 3:  /* prune stats */
      if (!director->stats_retention) {
         return false;
      }
      retention = director->stats_retention;
      if (!confirm_retention(ua, &retention, "Statistics")) {
         return false;
      }
      prune_stats(ua, retention);
      return true;
   default:
      break;
   }

   return true;
}
Пример #2
0
/*
 *   Purge records from database
 *
 *     Purge Files (from) [Job|JobId|Client|Volume]
 *     Purge Jobs  (from) [Client|Volume]
 *
 *  N.B. Not all above is implemented yet.
 */
int purgecmd(UAContext *ua, const char *cmd)
{
   int i;
   CLIENTRES *client;
   MEDIA_DBR mr;
   JOB_DBR  jr;
   static const char *keywords[] = {
      NT_("files"),
      NT_("jobs"),
      NT_("volume"),
      NT_("quota"),
      NULL
   };

   static const char *files_keywords[] = {
      NT_("Job"),
      NT_("JobId"),
      NT_("Client"),
      NT_("Volume"),
      NULL
   };

   static const char *quota_keywords[] = {
      NT_("Client"),
      NULL
   };

   static const char *jobs_keywords[] = {
      NT_("Client"),
      NT_("Volume"),
      NULL
   };

   ua->warning_msg(_(
      "\nThis command can be DANGEROUS!!!\n\n"
      "It purges (deletes) all Files from a Job,\n"
      "JobId, Client or Volume; or it purges (deletes)\n"
      "all Jobs from a Client or Volume without regard\n"
      "to retention periods. Normally you should use the\n"
      "PRUNE command, which respects retention periods.\n"));

   if (!open_db(ua)) {
      return 1;
   }
   switch (find_arg_keyword(ua, keywords)) {
   /* Files */
   case 0:
      switch(find_arg_keyword(ua, files_keywords)) {
      case 0:                         /* Job */
      case 1:                         /* JobId */
         if (get_job_dbr(ua, &jr)) {
            char jobid[50];
            edit_int64(jr.JobId, jobid);
            purge_files_from_jobs(ua, jobid);
         }
         return 1;
      case 2:                         /* client */
         client = get_client_resource(ua);
         if (client) {
            purge_files_from_client(ua, client);
         }
         return 1;
      case 3:                         /* Volume */
         if (select_media_dbr(ua, &mr)) {
            purge_files_from_volume(ua, &mr);
         }
         return 1;
      }
   /* Jobs */
   case 1:
      switch(find_arg_keyword(ua, jobs_keywords)) {
      case 0:                         /* client */
         client = get_client_resource(ua);
         if (client) {
            purge_jobs_from_client(ua, client);
         }
         return 1;
      case 1:                         /* Volume */
         if (select_media_dbr(ua, &mr)) {
            purge_jobs_from_volume(ua, &mr, /*force*/true);
         }
         return 1;
      }
   /* Volume */
   case 2:
      /* Perform ActionOnPurge (action=truncate) */
      if (find_arg(ua, "action") >= 0) {
         return action_on_purge_cmd(ua, ua->cmd);
      }

      while ((i=find_arg(ua, NT_("volume"))) >= 0) {
         if (select_media_dbr(ua, &mr)) {
            purge_jobs_from_volume(ua, &mr, /*force*/true);
         }
         *ua->argk[i] = 0;            /* zap keyword already seen */
         ua->send_msg("\n");
      }
      return 1;
   /* Quota */
   case 3:
      switch(find_arg_keyword(ua, quota_keywords)) {
      case 0:                         /* client */
         client = get_client_resource(ua);
         if (client) {
            purge_quota_from_client(ua, client);
         }
         return 1;
      }
   default:
      break;
   }
   switch (do_keyword_prompt(ua, _("Choose item to purge"), keywords)) {
   case 0:                            /* files */
      client = get_client_resource(ua);
      if (client) {
         purge_files_from_client(ua, client);
      }
      break;
   case 1:                            /* jobs */
      client = get_client_resource(ua);
      if (client) {
         purge_jobs_from_client(ua, client);
      }
      break;
   case 2:                            /* Volume */
      if (select_media_dbr(ua, &mr)) {
         purge_jobs_from_volume(ua, &mr, /*force*/true);
      }
      break;
   case 3:
      client = get_client_resource(ua); /* Quota */
      if (client) {
         purge_quota_from_client(ua, client);
      }
   }
   return 1;
}
Пример #3
0
/*
 * Prune records from database
 *
 * prune files client=xxx [pool=yyy]
 * prune jobs client=xxx [pool=yyy]
 * prune volume=xxx
 * prune stats
 * prune directory=xxx [client=xxx] [recursive]
 */
int prune_cmd(UAContext *ua, const char *cmd)
{
   CLIENTRES *client;
   POOLRES *pool;
   POOL_DBR pr;
   MEDIA_DBR mr;
   utime_t retention;
   int kw;
   static const char *keywords[] = {
      NT_("Files"),
      NT_("Jobs"),
      NT_("Volume"),
      NT_("Stats"),
      NT_("Directory"),
      NULL
   };

   if (!open_client_db(ua, true)) {
      return false;
   }

   /*
    * First search args
    */
   kw = find_arg_keyword(ua, keywords);
   if (kw < 0 || kw > 4) {
      /*
       * No args, so ask user
       */
      kw = do_keyword_prompt(ua, _("Choose item to prune"), keywords);
   }

   switch (kw) {
   case 0: /* prune files */
      if (!(client = get_client_resource(ua))) {
         return false;
      }

      if (find_arg_with_value(ua, NT_("pool")) >= 0) {
         pool = get_pool_resource(ua);
      } else {
         pool = NULL;
      }

      /*
       * Pool File Retention takes precedence over client File Retention
       */
      if (pool && pool->FileRetention > 0) {
         if (!confirm_retention(ua, &pool->FileRetention, "File")) {
            return false;
         }
      } else if (!confirm_retention(ua, &client->FileRetention, "File")) {
         return false;
      }

      prune_files(ua, client, pool);

      return true;
   case 1: { /* prune jobs */
      int i;
      char jobtype[MAX_NAME_LENGTH];

      if (!(client = get_client_resource(ua))) {
         return false;
      }

      if (find_arg_with_value(ua, NT_("pool")) >= 0) {
         pool = get_pool_resource(ua);
      } else {
         pool = NULL;
      }

      /*
       * Ask what jobtype to prune.
       */
      if ((i = find_arg_with_value(ua, NT_("jobtype"))) >= 0) {
         bstrncpy(jobtype, ua->argv[i], sizeof(jobtype));
      } else {
         start_prompt(ua, _("Jobtype to prune:\n"));
         for (i = 0; jobtypes[i].type_name; i++) {
            add_prompt(ua, jobtypes[i].type_name);
         }

         if (do_prompt(ua, _("JobType"),  _("Select Job Type"), jobtype, sizeof(jobtype)) < 0) {
            return true;
         }
      }

      for (i = 0; jobtypes[i].type_name; i++) {
         if (bstrcasecmp(jobtypes[i].type_name, jobtype)) {
            break;
         }
      }

      if (!jobtypes[i].type_name) {
         ua->warning_msg(_("Illegal jobtype %s.\n"), jobtype);
         return false;
      }

      /*
       * Pool Job Retention takes precedence over client Job Retention
       */
      if (pool && pool->JobRetention > 0) {
         if (!confirm_retention(ua, &pool->JobRetention, "Job")) {
            return false;
         }
      } else if (!confirm_retention(ua, &client->JobRetention, "Job")) {
         return false;
      }

      if (jobtypes[i].type_name) {
         return prune_jobs(ua, client, pool, jobtypes[i].job_type);
      }

      return false;
   }
   case 2: /* prune volume */
      if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
         return false;
      }

      if (mr.Enabled == 2) {
         ua->error_msg(_("Cannot prune Volume \"%s\" because it is archived.\n"),
                       mr.VolumeName);
         return false;
      }

      if (!confirm_retention(ua, &mr.VolRetention, "Volume")) {
         return false;
      }

      return prune_volume(ua, &mr);
   case 3: /* prune stats */
      if (!me->stats_retention) {
         return false;
      }

      retention = me->stats_retention;

      if (!confirm_retention(ua, &retention, "Statistics")) {
         return false;
      }

      return prune_stats(ua, retention);
   case 4: /* prune directory */
      if (find_arg_with_value(ua, NT_("client")) >= 0) {
         if (!(client = get_client_resource(ua))) {
            return false;
         }
      } else {
         client = NULL;
      }

      return prune_directory(ua, client);
   default:
      break;
   }

   return true;
}
Пример #4
0
/*
 * Prune Directory meta data records from the database.
 */
static bool prune_directory(UAContext *ua, CLIENTRES *client)
{
   int i, len;
   CLIENT_DBR cr;
   char *prune_topdir = NULL;
   POOL_MEM query(PM_MESSAGE),
            temp(PM_MESSAGE);
   bool recursive = false;
   bool retval = false;

   /*
    * See if a client was selected.
    */
   if (!client) {
      if (!get_yesno(ua, _("No client restriction given really remove "
                           "directory for all clients (yes/no): ")) ||
          ua->pint32_val == 0) {
         if (!(client = get_client_resource(ua))) {
            return false;
         }
      }
   }

   /*
    * See if we need to recursively remove all directories under a certain path.
    */
   recursive = find_arg(ua, NT_("recursive")) >= 0;

   /*
    * Get the directory to prune.
    */
   i = find_arg_with_value(ua, NT_("directory"));
   if (i >= 0) {
      pm_strcpy(temp, ua->argv[i]);
   } else {
      if (recursive) {
         if (!get_cmd(ua, _("Please enter the full path prefix to remove: "), false)) {
            return false;
         }
      } else {
         if (!get_cmd(ua, _("Please enter the full path to remove: "), false)) {
            return false;
         }
      }
      pm_strcpy(temp, ua->cmd);
   }

   /*
    * See if the directory ends in a / and escape it for usage in a database query.
    */
   len = strlen(temp.c_str());
   if (*(temp.c_str() + len - 1) != '/') {
      pm_strcat(temp, "/");
      len++;
   }
   prune_topdir = (char *)malloc(len * 2 + 1);
   db_escape_string(ua->jcr, ua->db, prune_topdir, temp.c_str(), len);

   /*
    * Remove all files in particular directory.
    */
   if (recursive) {
      Mmsg(query, "DELETE FROM file WHERE pathid IN ("
                  "SELECT pathid FROM path "
                  "WHERE path LIKE '%s%%'"
                  ")", prune_topdir);
   } else {
      Mmsg(query, "DELETE FROM file WHERE pathid IN ("
                  "SELECT pathid FROM path "
                  "WHERE path LIKE '%s'"
                  ")", prune_topdir);
   }

   if (client) {
      char ed1[50];

      memset(&cr, 0, sizeof(cr));
      bstrncpy(cr.Name, client->name(), sizeof(cr.Name));
      if (!db_create_client_record(ua->jcr, ua->db, &cr)) {
         goto bail_out;
      }

      Mmsg(temp, " AND JobId IN ("
                 "SELECT JobId FROM Job "
                 "WHERE ClientId=%s"
                 ")", edit_int64(cr.ClientId, ed1));

      pm_strcat(query, temp.c_str());
   }

   db_lock(ua->db);
   db_sql_query(ua->db, query.c_str());
   db_unlock(ua->db);

   /*
    * If we removed the entries from the file table without limiting it to a
    * certain client we created orphaned path entries as no one is referencing
    * them anymore.
    */
   if (!client) {
      if (!get_yesno(ua, _("Cleanup orphaned path records (yes/no):")) ||
          ua->pint32_val == 0) {
         retval = true;
         goto bail_out;
      }

      if (recursive) {
         Mmsg(query, "DELETE FROM path "
                     "WHERE path LIKE '%s%%'", prune_topdir);
      } else {
         Mmsg(query, "DELETE FROM path "
                     "WHERE path LIKE '%s'", prune_topdir);
      }

      db_lock(ua->db);
      db_sql_query(ua->db, query.c_str());
      db_unlock(ua->db);
   }

   retval = true;

bail_out:
   if (prune_topdir) {
      free(prune_topdir);
   }

   return retval;
}
Пример #5
0
/*
 *   Prune records from database
 *
 *    prune files (from) client=xxx
 *    prune jobs (from) client=xxx
 *    prune volume=xxx
 *    prune stats
 */
int prunecmd(UAContext *ua, const char *cmd)
{
   DIRRES *dir;
   CLIENT *client;
   POOL_DBR pr;
   MEDIA_DBR mr;
   utime_t retention;
   int kw;

   static const char *keywords[] = {
      NT_("Files"),
      NT_("Jobs"),
      NT_("Volume"),
      NT_("Stats"),
      NULL};

   if (!open_client_db(ua)) {
      return false;
   }

   /* First search args */
   kw = find_arg_keyword(ua, keywords);
   if (kw < 0 || kw > 3) {
      /* no args, so ask user */
      kw = do_keyword_prompt(ua, _("Choose item to prune"), keywords);
   }

   switch (kw) {
   case 0:  /* prune files */
      client = get_client_resource(ua);
      if (!client || !confirm_retention(ua, &client->FileRetention, "File")) {
         return false;
      }
      prune_files(ua, client);
      return true;
   case 1:  /* prune jobs */
      client = get_client_resource(ua);
      if (!client || !confirm_retention(ua, &client->JobRetention, "Job")) {
         return false;
      }
      /* ****FIXME**** allow user to select JobType */
      prune_jobs(ua, client, JT_BACKUP);
      return 1;
   case 2:  /* prune volume */
      if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
         return false;
      }
      if (mr.Enabled == 2) {
         ua->error_msg(_("Cannot prune Volume \"%s\" because it is archived.\n"),
            mr.VolumeName);
         return false;
      }
      if (!confirm_retention(ua, &mr.VolRetention, "Volume")) {
         return false;
      }
      prune_volume(ua, &mr);
      return true;
   case 3:  /* prune stats */
      dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
      if (!dir->stats_retention) {
         return false;
      }
      retention = dir->stats_retention;
      if (!confirm_retention(ua, &retention, "Statistics")) {
         return false;
      }
      prune_stats(ua, retention);
      return true;
   default:
      break;
   }

   return true;
}