#define uint64_t u_int64_t
#define uintmax_t u_intmax_t
+#define btime_t uint64_t
+
#ifdef HAVE_CYGWIN
#define socklen_t int
#endif
/* ***FIXME*** FileId_t should be uint64_t */
typedef uint32_t FileId_t;
typedef uint32_t DBId_t; /* general DB id type */
+typedef uint32_t JobId_t;
/* Job information passed to create job record and update
#define MAX_DEL_LIST_LEN 1000000
struct s_del_ctx {
- uint32_t *JobId;
+ JobId_t *JobId;
int num_ids; /* ids stored */
int max_ids; /* size of array */
int num_del; /* number deleted */
}
if (del->num_ids == del->max_ids) {
del->max_ids = (del->max_ids * 3) / 2;
- del->JobId = (uint32_t *)brealloc(del->JobId, sizeof(uint32_t) *
+ del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
del->max_ids);
}
- del->JobId[del->num_ids++] = (uint32_t)strtod(row[0], NULL);
+ del->JobId[del->num_ids++] = (JobId_t)strtod(row[0], NULL);
return 0;
}
} else if (del.max_ids > MAX_DEL_LIST_LEN) {
del.max_ids = MAX_DEL_LIST_LEN;
}
- del.JobId = (uint32_t *)malloc(sizeof(uint32_t) * del.max_ids);
+ del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
for (i=0; i < del.num_ids; i++) {
scheduler.c ua_cmds.c \
ua_dotcmds.c \
ua_db_query.c ua_retention.c \
- ua_input.c ua_output.c ua_run.c \
+ ua_input.c ua_output.c ua_prune.c ua_run.c \
ua_select.c ua_server.c \
ua_status.c verify.c
SVROBJS = dird.o authenticate.o backup.o catreq.o dird_conf.o \
scheduler.o ua_cmds.o \
ua_dotcmds.o \
ua_db_query.o ua_retention.o \
- ua_input.o ua_output.o ua_run.o \
+ ua_input.o ua_output.o ua_prune.o ua_run.o \
ua_select.o ua_server.o \
ua_status.o verify.o
{"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
{"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
{"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
-
{NULL, NULL, NULL, 0, 0, 0}
};
{"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, 0, 0},
{"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*30},
{"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*365},
+ {"autoprune", store_yesno, ITEM(res_client.AutoPrune), 1, ITEM_DEFAULT, 1},
{NULL, NULL, NULL, 0, 0, 0}
};
}
switch (type) {
case R_DIRECTOR:
- sendit(sock, "Director: name=%s maxjobs=%d FDtimeout=%d SDtimeout=%d\n",
+ sendit(sock, "Director: name=%s maxjobs=%d FDtimeout=%" lld " SDtimeout=%" lld "\n",
reshdr->name, res->res_dir.MaxConcurrentJobs,
res->res_dir.FDConnectTimeout,
res->res_dir.SDConnectTimeout);
case R_CLIENT:
sendit(sock, "Client: name=%s address=%s FDport=%d\n",
res->res_client.hdr.name, res->res_client.address, res->res_client.FDport);
- sendit(sock, "JobRetention=%d FileRetention=%d\n",
- res->res_client.JobRetention, res->res_client.FileRetention);
+ sendit(sock, "JobRetention=%" lld " FileRetention=%" lld " AutoPrune=%d\n",
+ res->res_client.JobRetention, res->res_client.FileRetention,
+ res->res_client.AutoPrune);
if (res->res_client.catalog) {
sendit(sock, " --> ");
dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
case R_POOL:
sendit(sock, "Pool: name=%s PoolType=%s\n", res->res_pool.hdr.name,
res->res_pool.pool_type);
- sendit(sock, " use_cat=%d use_once=%d acpt_any=%d\n",
+ sendit(sock, " use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n",
res->res_pool.use_catalog, res->res_pool.use_volume_once,
- res->res_pool.accept_any_volume);
- sendit(sock, " cat_files=%d max_vols=%d\n",
- res->res_pool.catalog_files, res->res_pool.max_volumes);
+ res->res_pool.accept_any_volume, res->res_pool.catalog_files);
+ sendit(sock, " max_vols=%d auto_recycle=%d VolumeRetention=%" lld "\n",
+ res->res_pool.max_volumes, res->res_pool.AutoRecycle,
+ res->res_pool.VolumeRetention);
+
sendit(sock, " LabelFormat=%s\n", res->res_pool.label_format?
res->res_pool.label_format:"NONE");
break;
char *subsys_directory; /* SubsysDirectory */
struct s_res_msgs *messages;
int MaxConcurrentJobs;
- int FDConnectTimeout; /* timeout for connect in seconds */
- int SDConnectTimeout; /* timeout in seconds */
+ btime_t FDConnectTimeout; /* timeout for connect in seconds */
+ btime_t SDConnectTimeout; /* timeout in seconds */
};
typedef struct s_res_dir DIRRES;
RES hdr;
int FDport; /* Where File daemon listens */
- uint32_t FileRetention; /* file retention period in seconds */
- uint32_t JobRetention; /* job retention period in seconds */
+ int AutoPrune; /* Do automatic pruning? */
+ btime_t FileRetention; /* file retention period in seconds */
+ btime_t JobRetention; /* job retention period in seconds */
char *address;
char *password;
struct s_res_cat *catalog; /* Catalog resource */
int RestoreJobId; /* What -- JobId to restore */
char *RestoreWhere; /* Where on disk to restore -- directory */
int RestoreOptions; /* How (overwrite, ..) */
- int MaxRunTime; /* max run time in seconds */
- int MaxStartDelay; /* max start delay in seconds */
+ btime_t MaxRunTime; /* max run time in seconds */
+ btime_t MaxStartDelay; /* max start delay in seconds */
struct s_res_msgs *messages; /* How and where to send messages */
struct s_res_sch *schedule; /* When -- Automatic schedule */
int use_volume_once; /* write on volume only once */
int accept_any_volume; /* accept any volume */
int max_volumes; /* max number of volumes */
- uint32_t VolumeRetention; /* volume retention period in seconds */
+ btime_t VolumeRetention; /* volume retention period in seconds */
int AutoRecycle; /* auto recycle */
};
typedef struct s_res_pool POOL;
Dmsg0(100, "=====Start Job=========\n");
jcr->start_time = now; /* set the real start time */
if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
- (jcr->start_time - jcr->sched_time)) {
+ (btime_t)(jcr->start_time - jcr->sched_time)) {
Jmsg(jcr, M_FATAL, 0, _("Job cancelled because max delay time exceeded.\n"));
free_jcr(jcr);
}
extern int querycmd(UAContext *ua, char *cmd);
extern int runcmd(UAContext *ua, char *cmd);
extern int retentioncmd(UAContext *ua, char *cmd);
+extern int prunecmd(UAContext *ua, char *cmd);
/* Forward referenced functions */
static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
{ N_("list"), listcmd, _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
{ N_("messages"), messagescmd, _("messages")},
{ N_("mount"), mountcmd, _("mount <storage-name>")},
- { N_("retention"), retentioncmd, _("retention")},
+ { N_("prune"), prunecmd, _("prune expired records from catalog")},
{ N_("run"), runcmd, _("run <job-name>")},
{ N_("setdebug"), setdebugcmd, _("sets debug level")},
{ N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")},
}
} else if (stat == 0) {
if (ua.UA_sock->msglen == BNET_TERMINATE) {
+ quit = TRUE;
break;
}
bnet_sig(ua.UA_sock, BNET_POLL);
if (items[i].handler == store_yesno) {
*(int *)(items[i].value) |= items[i].code;
} else if (items[i].handler == store_pint ||
- items[i].handler == store_int ||
- items[i].handler == store_time) {
+ items[i].handler == store_int) {
*(int *)(items[i].value) = items[i].default_value;
} else if (items[i].handler == store_int64) {
*(int64_t *)(items[i].value) = items[i].default_value;
- } else if (items[i].handler == store_size) {
+ } else if (items[i].handler == store_size ||
+ items[i].handler == store_time) {
*(uint64_t *)(items[i].value) = items[i].default_value;
}
}
/* Store a time period in seconds */
void store_time(LEX *lc, struct res_items *item, int index, int pass)
{
- int token, i, ch, value;
+ int token, i, ch;
+ btime_t value;
int mod[] = {'*', 's', 'm', 'h', 'd', 'w', 'o', 'q', 'y', 0};
int mult[] = {1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30,
60*60*24*91, 60*60*24*365};
errno = 0;
switch (token) {
case T_NUMBER:
- token = (int)strtod(lc->str, NULL);
- if (errno != 0 || token < 0) {
+ value = (btime_t)strtod(lc->str, NULL);
+ if (errno != 0 || value < 0) {
scan_err1(lc, "expected a time period, got: %s", lc->str);
}
- *(int *)(item->value) = token;
+ *(btime_t *)(item->value) = value;
break;
case T_IDENTIFIER:
case T_STRING:
if (mod[i] == 0 || !is_a_number(lc->str)) {
scan_err1(lc, "expected a time period, got: %s", lc->str);
}
- value = (int)strtod(lc->str, NULL);
+ value = (btime_t)strtod(lc->str, NULL);
if (errno != 0 || value < 0) {
scan_err1(lc, "expected a time period, got: %s", lc->str);
}
- *(int *)(item->value) = value * mult[i];
+ *(btime_t *)(item->value) = value * mult[i];
break;
default:
scan_err1(lc, "expected a time period, got: %s", lc->str);
char * encode_mode __PROTO((mode_t mode, char *buf));
char * edit_uint_with_commas __PROTO((uint64_t val, char *buf));
char * add_commas __PROTO((char *val, char *buf));
-int do_shell_expansion(char *name);
-int is_a_number(const char *num);
+char * edit_uint (uint64_t val, char *buf);
+int do_shell_expansion (char *name);
+int is_a_number (const char *num);
/*
}
if (digit_seen && (*n == 'e' || *n == 'E')
&& (ISDIGIT(n[1]) || ((n[1]=='-' || n[1] == '+') && ISDIGIT(n[2])))) {
- n += 2; /* skip e- or e+ */
+ n += 2; /* skip e- or e+ or e digit */
while (ISDIGIT(*n)) { n++; }
}
return digit_seen && *n==0;
return add_commas(buf, buf);
}
+/*
+ * Edit an integer number, the supplied buffer
+ * must be at least 27 bytes long. The incoming number
+ * is always widened to 64 bits.
+ */
+char *edit_uint(uint64_t val, char *buf)
+{
+ sprintf(buf, "%" lld, val);
+ return buf;
+}
+
+
/*
* Add commas to a string, which is presumably
* a number.
/* */
#define VERSION "1.19"
#define VSTRING "1"
-#define DATE "27 April 2002"
-#define LSMDATE "27Apr02"
+#define DATE "28 April 2002"
+#define LSMDATE "28Apr02"
/* Debug flags */
#define DEBUG 1