From 31e3d236a0fcaf7a0624d4683e785c3d40503817 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 5 Aug 2004 21:02:51 +0000 Subject: [PATCH] Implement user friendly time duration input editing Add buf len argument to edit_utime git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1509 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 4 +- bacula/src/dird/dird_conf.c | 8 +- bacula/src/dird/ua_cmds.c | 18 ++--- bacula/src/dird/ua_select.c | 4 +- bacula/src/lib/edit.c | 130 +++++++++++++++++++------------- bacula/src/lib/protos.h | 6 +- bacula/src/stored/stored_conf.c | 2 +- 7 files changed, 98 insertions(+), 74 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index ade42c86c4..f8e30d4a67 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -29,9 +29,10 @@ Version 1.35 Kern (see below) - Document a get out of jail procedure if everything breaks if you lost/broke the Catalog -- do the same for "I know my file is there how do I get it back?". -- Test Tape Alerts +- Test/doc Tape Alerts - Doc update AllFromVol - Doc dbcheck eliminate orphaned clients. +- Doc new duration time input editing. Documentation to do: (any release a little bit at a time) @@ -1166,4 +1167,3 @@ Block Position: 0 - When passwords do not match, print message that points the user to the doc. - Do tape alerts -- see tapealert.txt - diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index fcbeca3385..36a31ae4d7 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -471,8 +471,8 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm res->res_client.hdr.name, res->res_client.address, res->res_client.FDport, res->res_client.MaxConcurrentJobs); sendit(sock, " JobRetention=%s FileRetention=%s AutoPrune=%d\n", - edit_utime(res->res_client.JobRetention, ed1), - edit_utime(res->res_client.FileRetention, ed2), + edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)), + edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)), res->res_client.AutoPrune); if (res->res_client.catalog) { sendit(sock, " --> "); @@ -697,9 +697,9 @@ next_run: res->res_pool.accept_any_volume, res->res_pool.catalog_files); sendit(sock, " max_vols=%d auto_prune=%d VolRetention=%s\n", res->res_pool.max_volumes, res->res_pool.AutoPrune, - edit_utime(res->res_pool.VolRetention, ed1)); + edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1))); sendit(sock, " VolUse=%s recycle=%d LabelFormat=%s\n", - edit_utime(res->res_pool.VolUseDuration, ed1), + edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)), res->res_pool.Recycle, NPRT(res->res_pool.label_format)); sendit(sock, " CleaningPrefix=%s\n", diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 173ba60490..f2dbbdc430 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -695,7 +695,7 @@ static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr) static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr) { - char ed1[50]; + char ed1[150]; POOLMEM *query; if (!duration_to_utime(val, &mr->VolRetention)) { bsendmsg(ua, _("Invalid retention period specified: %s\n"), val); @@ -707,15 +707,15 @@ static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr) if (!db_sql_query(ua->db, query, NULL, NULL)) { bsendmsg(ua, "%s", db_strerror(ua->db)); } else { - bsendmsg(ua, _("New retention seconds is: %s\n"), - edit_utime(mr->VolRetention, ed1)); + bsendmsg(ua, _("New retention period is: %s\n"), + edit_utime(mr->VolRetention, ed1, sizeof(ed1))); } free_pool_memory(query); } static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr) { - char ed1[50]; + char ed1[150]; POOLMEM *query; if (!duration_to_utime(val, &mr->VolUseDuration)) { @@ -729,7 +729,7 @@ static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr) bsendmsg(ua, "%s", db_strerror(ua->db)); } else { bsendmsg(ua, _("New use duration is: %s\n"), - edit_utime(mr->VolUseDuration, ed1)); + edit_utime(mr->VolUseDuration, ed1, sizeof(ed1))); } free_pool_memory(query); } @@ -896,7 +896,7 @@ static int update_volume(UAContext *ua) MEDIA_DBR mr; POOL_DBR pr; POOLMEM *query; - char ed1[30]; + char ed1[130]; bool done = false; const char *kw[] = { N_("VolStatus"), /* 0 */ @@ -998,8 +998,8 @@ static int update_volume(UAContext *ua) update_volstatus(ua, ua->cmd, &mr); break; case 1: /* Retention */ - bsendmsg(ua, _("Current retention seconds is: %s\n"), - edit_utime(mr.VolRetention, ed1)); + bsendmsg(ua, _("Current retention period is: %s\n"), + edit_utime(mr.VolRetention, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Retention period: "))) { return 0; } @@ -1008,7 +1008,7 @@ static int update_volume(UAContext *ua) case 2: /* Use Duration */ bsendmsg(ua, _("Current use duration is: %s\n"), - edit_utime(mr.VolUseDuration, ed1)); + edit_utime(mr.VolUseDuration, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Use Duration: "))) { return 0; } diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index 2330de5784..c8dd2a7711 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -39,11 +39,11 @@ extern struct s_jl joblevels[]; */ int confirm_retention(UAContext *ua, utime_t *ret, const char *msg) { - char ed1[30]; + char ed1[100]; for ( ;; ) { bsendmsg(ua, _("The current %s retention period is: %s\n"), - msg, edit_utime(*ret, ed1)); + msg, edit_utime(*ret, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) { return 0; } diff --git a/bacula/src/lib/edit.c b/bacula/src/lib/edit.c index a420656eb4..d988f46dbc 100644 --- a/bacula/src/lib/edit.c +++ b/bacula/src/lib/edit.c @@ -131,9 +131,10 @@ char *edit_uint64(uint64_t val, char *buf) * Given a string "str", separate the integer part into * str, and the modifier into mod. */ -static bool get_modifier(char *str, char *mod, int mod_len) +static bool get_modifier(char *str, char *num, int num_len, char *mod, int mod_len) { - int i, len; + int i, len, num_begin, num_end, mod_begin, mod_end; + /* * Look for modifier by walking back looking for the first * space or digit. @@ -141,36 +142,50 @@ static bool get_modifier(char *str, char *mod, int mod_len) strip_trailing_junk(str); len = strlen(str); - /* Find beginning of the modifier */ - for (i=len; i > 0; i--) { - if (!B_ISALPHA(str[i-1])) { + for (i=0; i (num_end - num_begin + 1)) { + num_len = num_end - num_begin + 1; + } + if (num_len == 0) { return false; } - - /* Move modifier to its location */ - bstrncpy(mod, &str[i], mod_len); - Dmsg2(900, "in=%s mod=%s:\n", str, mod); - - /* Backup over any spaces in front of modifier */ - for ( ; i > 0; i--) { - if (B_ISSPACE(str[i-1])) { - continue; + for ( ; i (mod_end - mod_begin + 1)) { + mod_len = mod_end - mod_begin + 1; + } + Dmsg5(900, "str=%s: num_beg=%d num_end=%d mod_beg=%d mod_end=%d\n", + str, num_begin, num_end, mod_begin, mod_end); + bstrncpy(num, &str[num_begin], num_len); + bstrncpy(mod, &str[mod_begin], mod_len); + if (!is_a_number(num)) { return false; } + bstrncpy(str, &str[mod_end], len); + return true; } @@ -182,8 +197,9 @@ static bool get_modifier(char *str, char *mod, int mod_len) int duration_to_utime(char *str, utime_t *value) { int i, mod_len; - double val; + double val, total = 0.0; char mod_str[20]; + char num_str[50]; /* * The "n" = mins and months appears before minutes so that m maps * to months. These "kludges" make it compatible with pre 1.31 @@ -194,35 +210,42 @@ int duration_to_utime(char *str, utime_t *value) static const int32_t mult[] = {60, 1, 60*60*24*30, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*91, 60*60*24*365}; - if (!get_modifier(str, mod_str, sizeof(mod_str))) { - return 0; - } - /* Now find the multiplier corresponding to the modifier */ - mod_len = strlen(mod_str); - for (i=0; mod[i]; i++) { - if (strncasecmp(mod_str, mod[i], mod_len) == 0) { - break; + while (*str) { + if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) { + return 0; } + /* Now find the multiplier corresponding to the modifier */ + mod_len = strlen(mod_str); + if (mod_len == 0) { + i = 1; /* assume seconds */ + } else { + for (i=0; mod[i]; i++) { + if (strncasecmp(mod_str, mod[i], mod_len) == 0) { + break; + } + } + if (mod[i] == NULL) { + i = 1; /* no modifier, assume secs */ + } + } + Dmsg2(900, "str=%s: mult=%d\n", num_str, mult[i]); + errno = 0; + val = strtod(num_str, NULL); + if (errno != 0 || val < 0) { + return 0; + } + total += val * mult[i]; } - if (mod[i] == NULL) { - i = 1; /* no modifier, assume 1 */ - } - Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]); - errno = 0; - val = strtod(str, NULL); - if (errno != 0 || val < 0) { - return 0; - } - *value = (utime_t)(val * mult[i]); + *value = (utime_t)total; return 1; } /* * Edit a utime "duration" into ASCII */ -char *edit_utime(utime_t val, char *buf) +char *edit_utime(utime_t val, char *buf, int buf_len) { - char mybuf[30]; + char mybuf[200]; static const int32_t mult[] = {60*60*24*365, 60*60*24*30, 60*60*24, 60*60, 60}; static const char *mod[] = {"year", "month", "day", "hour", "min"}; int i; @@ -233,21 +256,21 @@ char *edit_utime(utime_t val, char *buf) times = (uint32_t)(val / mult[i]); if (times > 0) { val = val - (utime_t)times * mult[i]; - sprintf(mybuf, "%d %s%s ", times, mod[i], times>1?"s":""); - strcat(buf, mybuf); + bsnprintf(mybuf, sizeof(mybuf), "%d %s%s ", times, mod[i], times>1?"s":""); + bstrncat(buf, mybuf, buf_len); } } if (val == 0 && strlen(buf) == 0) { - strcat(buf, "0 secs"); + bstrncat(buf, "0 secs", buf_len); } else if (val != 0) { - sprintf(mybuf, "%d sec%s", (uint32_t)val, val>1?"s":""); - strcat(buf, mybuf); + bsnprintf(mybuf, sizeof(mybuf), "%d sec%s", (uint32_t)val, val>1?"s":""); + bstrncat(buf, mybuf, buf_len); } return buf; } /* - * Convert a size size in bytes to uint64_t + * Convert a size in bytes to uint64_t * Returns 0: if error 1: if OK, and value stored in value */ @@ -256,6 +279,7 @@ int size_to_uint64(char *str, int str_len, uint64_t *value) int i, mod_len; double val; char mod_str[20]; + char num_str[50]; static const char *mod[] = {"*", "k", "kb", "m", "mb", "g", "gb", NULL}; /* first item * not used */ const int64_t mult[] = {1, /* byte */ 1024, /* kilobyte */ @@ -265,7 +289,7 @@ int size_to_uint64(char *str, int str_len, uint64_t *value) 1073741824, /* gigabyte */ 1000000000}; /* gb gigabyte */ - if (!get_modifier(str, mod_str, sizeof(mod_str))) { + if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) { return 0; } /* Now find the multiplier corresponding to the modifier */ @@ -280,7 +304,7 @@ int size_to_uint64(char *str, int str_len, uint64_t *value) } Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]); errno = 0; - val = strtod(str, NULL); + val = strtod(num_str, NULL); if (errno != 0 || val < 0) { return 0; } @@ -292,7 +316,7 @@ int size_to_uint64(char *str, int str_len, uint64_t *value) * Check if specified string is a number or not. * Taken from SQLite, cool, thanks. */ -int is_a_number(const char *n) +bool is_a_number(const char *n) { bool digit_seen = false; @@ -318,7 +342,7 @@ int is_a_number(const char *n) /* * Check if the specified string is an integer */ -int is_an_integer(const char *n) +bool is_an_integer(const char *n) { bool digit_seen = false; while (B_ISDIGIT(*n)) { diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 63d9a8d09a..dbf6828e49 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -117,9 +117,9 @@ char * add_commas (char *val, char *buf); char * edit_uint64 (uint64_t val, char *buf); int duration_to_utime (char *str, utime_t *value); int size_to_uint64(char *str, int str_len, uint64_t *rtn_value); -char *edit_utime (utime_t val, char *buf); -int is_a_number (const char *num); -int is_an_integer (const char *n); +char *edit_utime (utime_t val, char *buf, int buf_len); +bool is_a_number (const char *num); +bool is_an_integer (const char *n); bool is_name_valid (char *name, POOLMEM **msg); /* jcr.c (most definitions are in src/jcr.h) */ diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 0e557ebcc3..61e3323524 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -168,7 +168,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))), get_first_port(res->res_store.sdaddrs), get_first_port(res->res_store.sddaddrs), - edit_utime(res->res_store.heartbeat_interval, buf)); + edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf))); foreach_dlist(p, res->res_store.sdaddrs) { sendit(sock, " SDaddr=%s SDport=%d\n", p->get_address(buf, sizeof(buf)), p->get_port()); -- 2.39.5