Exemple #1
0
/*
 * Update Client record
 * Returns: false on failure
 *          true on success
 */
bool db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
{
    bool retval = false;
    char ed1[50], ed2[50];
    char esc_name[MAX_ESCAPE_NAME_LENGTH];
    char esc_uname[MAX_ESCAPE_NAME_LENGTH];
    CLIENT_DBR tcr;

    db_lock(mdb);
    memcpy(&tcr, cr, sizeof(tcr));
    if (!db_create_client_record(jcr, mdb, &tcr)) {
        goto bail_out;
    }

    mdb->db_escape_string(jcr, esc_name, cr->Name, strlen(cr->Name));
    mdb->db_escape_string(jcr, esc_uname, cr->Uname, strlen(cr->Uname));
    Mmsg(mdb->cmd,
         "UPDATE Client SET AutoPrune=%d,FileRetention=%s,JobRetention=%s,"
         "Uname='%s' WHERE Name='%s'",
         cr->AutoPrune,
         edit_uint64(cr->FileRetention, ed1),
         edit_uint64(cr->JobRetention, ed2),
         esc_uname, esc_name);

    retval = UPDATE_DB(jcr, mdb, mdb->cmd);

bail_out:
    db_unlock(mdb);
    return retval;
}
Exemple #2
0
/*
 * Get or create a Client record for this Job
 */
bool get_or_create_client_record(JCR *jcr)
{
   CLIENT_DBR cr;

   memset(&cr, 0, sizeof(cr));
   bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
   cr.AutoPrune = jcr->client->AutoPrune;
   cr.FileRetention = jcr->client->FileRetention;
   cr.JobRetention = jcr->client->JobRetention;
   if (!jcr->client_name) {
      jcr->client_name = get_pool_memory(PM_NAME);
   }
   pm_strcpy(jcr->client_name, jcr->client->hdr.name);
   if (!db_create_client_record(jcr, jcr->db, &cr)) {
      Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
         db_strerror(jcr->db));
      return false;
   }
   jcr->jr.ClientId = cr.ClientId;
   if (cr.Uname[0]) {
      if (!jcr->client_uname) {
         jcr->client_uname = get_pool_memory(PM_NAME);
      }
      pm_strcpy(jcr->client_uname, cr.Uname);
   }
   Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
      jcr->jr.ClientId);
   return true;
}
Exemple #3
0
/*
 * Get or create a Client record for this Job
 */
bool get_or_create_client_record(JCR *jcr)
{
   CLIENT_DBR cr;

   memset(&cr, 0, sizeof(cr));
   bstrncpy(cr.Name, jcr->res.client->hdr.name, sizeof(cr.Name));
   cr.AutoPrune = jcr->res.client->AutoPrune;
   cr.FileRetention = jcr->res.client->FileRetention;
   cr.JobRetention = jcr->res.client->JobRetention;
   if (!jcr->client_name) {
      jcr->client_name = get_pool_memory(PM_NAME);
   }
   pm_strcpy(jcr->client_name, jcr->res.client->hdr.name);
   if (!db_create_client_record(jcr, jcr->db, &cr)) {
      Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
         db_strerror(jcr->db));
      return false;
   }
   /*
    * Only initialize quota when a Soft or Hard Limit is set.
    */
   if (jcr->res.client->HardQuota != 0 ||
       jcr->res.client->SoftQuota != 0) {
      if (!db_get_quota_record(jcr, jcr->db, &cr)) {
         if (!db_create_quota_record(jcr, jcr->db, &cr)) {
            Jmsg(jcr, M_FATAL, 0, _("Could not create Quota record. ERR=%s\n"),
               db_strerror(jcr->db));
         }
         jcr->res.client->QuotaLimit = 0;
         jcr->res.client->GraceTime = 0;
      }
   }
   jcr->jr.ClientId = cr.ClientId;
   jcr->res.client->QuotaLimit = cr.QuotaLimit;
   jcr->res.client->GraceTime = cr.GraceTime;
   if (cr.Uname[0]) {
      if (!jcr->client_uname) {
         jcr->client_uname = get_pool_memory(PM_NAME);
      }
      pm_strcpy(jcr->client_uname, cr.Uname);
   }
   Dmsg2(100, "Created Client %s record %d\n", jcr->res.client->hdr.name,
      jcr->jr.ClientId);
   return true;
}
Exemple #4
0
static int purge_quota_from_client(UAContext *ua, CLIENTRES *client)
{
   CLIENT_DBR cr;

   memset(&cr, 0, sizeof(cr));
   bstrncpy(cr.Name, client->name(), sizeof(cr.Name));
   if (!db_create_client_record(ua->jcr, ua->db, &cr)) {
      return 0;
   }
   if (!db_create_quota_record(ua->jcr, ua->db, &cr)) {
      return 0;
   }
   if (!db_reset_quota_record(ua->jcr, ua->db, &cr)) {
      return 0;
   }
   ua->info_msg(_("Purged quota for Client \"%s\"\n"), cr.Name);

   return 1;
}
Exemple #5
0
/*
 * Purge Job records from the database. For any Job which
 * is older than the retention period, we unconditionally delete
 * it and all File records for that Job.  This is simple enough that no
 * temporary tables are needed. We simply make an in memory list of
 * the JobIds then delete the Job, Files, and JobMedia records in that list.
 */
static int purge_jobs_from_client(UAContext *ua, CLIENTRES *client)
{
   struct del_ctx del;
   POOL_MEM query(PM_MESSAGE);
   CLIENT_DBR cr;
   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)) {
      return 0;
   }

   memset(&del, 0, sizeof(del));
   del.max_ids = 1000;
   del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
   del.PurgedFiles = (char *)malloc(del.max_ids);

   ua->info_msg(_("Begin purging jobs from Client \"%s\"\n"), cr.Name);

   Mmsg(query, select_jobs_from_client, edit_int64(cr.ClientId, ed1));
   Dmsg1(150, "select sql=%s\n", query.c_str());
   db_sql_query(ua->db, query.c_str(), job_delete_handler, (void *)&del);

   purge_job_list_from_catalog(ua, del);

   if (del.num_ids == 0) {
      ua->warning_msg(_("No Files found for client %s to purge from %s catalog.\n"),
         client->name(), client->catalog->name());
   } else {
      ua->info_msg(_("%d Jobs for client %s purged from %s catalog.\n"), del.num_ids,
         client->name(), client->catalog->name());
   }

   if (del.JobId) {
      free(del.JobId);
   }
   if (del.PurgedFiles) {
      free(del.PurgedFiles);
   }
   return 1;
}
Exemple #6
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;
}
Exemple #7
0
/*
 * Pruning Jobs is a bit more complicated than purging Files
 * because we delete Job records only if there is a more current
 * backup of the FileSet. Otherwise, we keep the Job record.
 * In other words, we never delete the only Job record that
 * contains a current backup of a FileSet. This prevents the
 * Volume from being recycled and destroying a current backup.
 *
 * For Verify Jobs, we do not delete the last InitCatalog.
 *
 * For Restore Jobs there are no restrictions.
 */
int prune_jobs(UAContext *ua, CLIENT *client, int JobType)
{
   struct del_ctx del;
   POOL_MEM query(PM_MESSAGE);
   utime_t now, period;
   CLIENT_DBR cr;
   char ed1[50], ed2[50];

   db_lock(ua->db);
   memset(&cr, 0, sizeof(cr));
   memset(&del, 0, sizeof(del));

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

   period = client->JobRetention;
   now = (utime_t)time(NULL);

   /* Drop any previous temporary tables still there */
   drop_temp_tables(ua);

   /* Create temp tables and indicies */
   if (!create_temp_tables(ua)) {
      goto bail_out;
   }

   /*
    * Select all files that are older than the JobRetention period
    *  and stuff them into the "DeletionCandidates" table.
    */
   edit_int64(now - period, ed1);
   Mmsg(query, insert_delcand, (char)JobType, ed1, 
        edit_int64(cr.ClientId, ed2));
   if (!db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL)) {
      if (ua->verbose) {
         ua->error_msg("%s", db_strerror(ua->db));
      }
      Dmsg0(050, "insert delcand failed\n");
      goto bail_out;
   }

   del.max_ids = 100;
   del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
   del.PurgedFiles = (char *)malloc(del.max_ids);

   /* ed1 = JobTDate */
   edit_int64(cr.ClientId, ed2);
   switch (JobType) {
   case JT_BACKUP:
      Mmsg(query, select_backup_del, ed1, ed2);
      break;
   case JT_RESTORE:
      Mmsg(query, select_restore_del, ed1, ed2);
      break;
   case JT_VERIFY:
      Mmsg(query, select_verify_del, ed1, ed2);
      break;
   case JT_ADMIN:
      Mmsg(query, select_admin_del, ed1, ed2);
      break;
   case JT_COPY:
      Mmsg(query, select_copy_del, ed1, ed2);
      break;
   case JT_MIGRATE:
      Mmsg(query, select_migrate_del, ed1, ed2);
      break;
   }

   Dmsg1(150, "Query=%s\n", query.c_str());
   if (!db_sql_query(ua->db, query.c_str(), job_delete_handler, (void *)&del)) {
      ua->error_msg("%s", db_strerror(ua->db));
   }

   purge_job_list_from_catalog(ua, del);

   if (del.num_del > 0) {
      ua->info_msg(_("Pruned %d %s for client %s from catalog.\n"), del.num_del,
         del.num_del==1?_("Job"):_("Jobs"), client->name());
    } else if (ua->verbose) {
       ua->info_msg(_("No Jobs found to prune.\n"));
    }

bail_out:
   drop_temp_tables(ua);
   db_unlock(ua->db);
   if (del.JobId) {
      free(del.JobId);
   }
   if (del.PurgedFiles) {
      free(del.PurgedFiles);
   }
   return 1;
}
Exemple #8
0
/*
 * Prune File records from the database. For any Job which
 * is older than the retention period, we unconditionally delete
 * all File records for that Job.  This is simple enough that no
 * temporary tables are needed. We simply make an in memory list of
 * the JobIds meeting the prune conditions, then delete all File records
 * pointing to each of those JobIds.
 *
 * This routine assumes you want the pruning to be done. All checking
 *  must be done before calling this routine.
 */
int prune_files(UAContext *ua, CLIENT *client)
{
   struct del_ctx del;
   struct s_count_ctx cnt;
   POOL_MEM query(PM_MESSAGE);
   utime_t now, period;
   CLIENT_DBR cr;
   char ed1[50], ed2[50];

   db_lock(ua->db);
   memset(&cr, 0, sizeof(cr));
   memset(&del, 0, sizeof(del));
   bstrncpy(cr.Name, client->hdr.name, sizeof(cr.Name));
   if (!db_create_client_record(ua->jcr, ua->db, &cr)) {
      db_unlock(ua->db);
      return 0;
   }

   period = client->FileRetention;
   now = (utime_t)time(NULL);

   /* Select Jobs -- for counting */
   Mmsg(query, count_select_job, edit_int64(now - period, ed1), 
        edit_int64(cr.ClientId, ed2));
   Dmsg3(050, "select now=%u period=%u sql=%s\n", (uint32_t)now, 
               (uint32_t)period, query.c_str());
   cnt.count = 0;
   if (!db_sql_query(ua->db, query.c_str(), del_count_handler, (void *)&cnt)) {
      ua->error_msg("%s", db_strerror(ua->db));
      Dmsg0(050, "Count failed\n");
      goto bail_out;
   }

   if (cnt.count == 0) {
      if (ua->verbose) {
         ua->warning_msg(_("No Files found to prune.\n"));
      }
      goto bail_out;
   }

   if (cnt.count < MAX_DEL_LIST_LEN) {
      del.max_ids = cnt.count + 1;
   } else {
      del.max_ids = MAX_DEL_LIST_LEN;
   }
   del.tot_ids = 0;

   del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);

   /* Now process same set but making a delete list */
   Mmsg(query, select_job, edit_int64(now - period, ed1), 
        edit_int64(cr.ClientId, ed2));
   db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);

   purge_files_from_job_list(ua, del);

   edit_uint64_with_commas(del.num_del, ed1);
   ua->info_msg(_("Pruned Files from %s Jobs for client %s from catalog.\n"),
      ed1, client->name());

bail_out:
   db_unlock(ua->db);
   if (del.JobId) {
      free(del.JobId);
   }
   return 1;
}