From: Radosław Korzeniewski Date: Tue, 8 Jun 2021 13:55:11 +0000 (+0200) Subject: Fix for plugin obects to properly decode object. X-Git-Tag: Release-11.3.2~516 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=643e4b09f15a79018ab175bf1c4ae7d8d2392433;p=thirdparty%2Fbacula.git Fix for plugin obects to properly decode object. Move get_next_tag() to lib/edit.c and add unittest for it. --- diff --git a/.gitignore b/.gitignore index 287efbf01..d91a5207d 100644 --- a/.gitignore +++ b/.gitignore @@ -318,6 +318,7 @@ bacula/src/lib/bsnprintf_test bacula/src/lib/bsock_test bacula/src/lib/bsockcore_test bacula/src/lib/crc32_test +bacula/src/lib/edit_test bacula/src/lib/flist_test bacula/src/lib/output_test bacula/src/lib/sellist_test diff --git a/bacula/src/cats/Makefile.in b/bacula/src/cats/Makefile.in index 4955436e8..57be6a2ec 100644 --- a/bacula/src/cats/Makefile.in +++ b/bacula/src/cats/Makefile.in @@ -125,7 +125,7 @@ libbaccats.a: $(LIBBACCATS_OBJS) $(RANLIB) $@ libbacsql.la: Makefile $(LIBBACSQL_LOBJS) - @echo "Making $@ ..." + @echo "Making $@ ..." $(LIBTOOL_LINK) $(CXX) $(DEFS) $(DEBUG) $(LDFLAGS) -o $@ $(LIBBACSQL_LOBJS) -export-dynamic -rpath $(libdir) -release $(LIBBACSQL_LT_RELEASE) $(DB_LIBS) libbaccats.la: Makefile cats_null.lo @@ -294,7 +294,7 @@ uninstall: @LIBTOOL_UNINSTALL_TARGET@ @INCLUDE_UNINSTALL_TARGET@ # and it also includes system headers. # `semi'-automatic since dependencies are generated at distribution time. -depend: +depend: @$(MV) Makefile Makefile.bak @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile diff --git a/bacula/src/cats/cats.c b/bacula/src/cats/cats.c index 975bcba20..3c40dcdc2 100644 --- a/bacula/src/cats/cats.c +++ b/bacula/src/cats/cats.c @@ -1,4 +1,4 @@ -/* +/* Bacula(R) - The Network Backup Solution Copyright (C) 2000-2020 Kern Sibbald @@ -14,26 +14,26 @@ This notice must be preserved when any source code is conveyed and/or propagated. - Bacula(R) is a registered trademark of Kern Sibbald. -*/ -/* - * Generic catalog class methods. - * - * Note: at one point, this file was assembled from parts of other files - * by a programmer, and other than "wrapping" in a class, which is a trivial - * change for a C++ programmer, nothing substantial was done, yet all the - * code was recommitted under this programmer's name. Consequently, we - * undo those changes here. - */ - -#include "bacula.h" - -#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL - -#include "cats.h" + Bacula(R) is a registered trademark of Kern Sibbald. +*/ +/* + * Generic catalog class methods. + * + * Note: at one point, this file was assembled from parts of other files + * by a programmer, and other than "wrapping" in a class, which is a trivial + * change for a C++ programmer, nothing substantial was done, yet all the + * code was recommitted under this programmer's name. Consequently, we + * undo those changes here. + */ + +#include "bacula.h" + +#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL + +#include "cats.h" static int dbglvl=100; - + void append_filter(POOLMEM **buf, char *cond) { if (*buf[0] != '\0') { @@ -45,144 +45,122 @@ void append_filter(POOLMEM **buf, char *cond) pm_strcat(buf, cond); } -bool BDB::bdb_match_database(const char *db_driver, const char *db_name, - const char *db_address, int db_port) -{ - BDB *mdb = this; - bool match; - - if (db_driver) { - match = strcasecmp(mdb->m_db_driver, db_driver) == 0 && - bstrcmp(mdb->m_db_name, db_name) && - bstrcmp(mdb->m_db_address, db_address) && - mdb->m_db_port == db_port && - mdb->m_dedicated == false; - } else { - match = bstrcmp(mdb->m_db_name, db_name) && - bstrcmp(mdb->m_db_address, db_address) && - mdb->m_db_port == db_port && - mdb->m_dedicated == false; - } - return match; -} - -BDB *BDB::bdb_clone_database_connection(JCR *jcr, bool mult_db_connections) -{ - BDB *mdb = this; - /* - * See if its a simple clone e.g. with mult_db_connections set to false - * then we just return the calling class pointer. - */ - if (!mult_db_connections) { - mdb->m_ref_count++; - return mdb; - } - - /* - * A bit more to do here just open a new session to the database. - */ - return db_init_database(jcr, mdb->m_db_driver, mdb->m_db_name, +bool BDB::bdb_match_database(const char *db_driver, const char *db_name, + const char *db_address, int db_port) +{ + BDB *mdb = this; + bool match; + + if (db_driver) { + match = strcasecmp(mdb->m_db_driver, db_driver) == 0 && + bstrcmp(mdb->m_db_name, db_name) && + bstrcmp(mdb->m_db_address, db_address) && + mdb->m_db_port == db_port && + mdb->m_dedicated == false; + } else { + match = bstrcmp(mdb->m_db_name, db_name) && + bstrcmp(mdb->m_db_address, db_address) && + mdb->m_db_port == db_port && + mdb->m_dedicated == false; + } + return match; +} + +BDB *BDB::bdb_clone_database_connection(JCR *jcr, bool mult_db_connections) +{ + BDB *mdb = this; + /* + * See if its a simple clone e.g. with mult_db_connections set to false + * then we just return the calling class pointer. + */ + if (!mult_db_connections) { + mdb->m_ref_count++; + return mdb; + } + + /* + * A bit more to do here just open a new session to the database. + */ + return db_init_database(jcr, mdb->m_db_driver, mdb->m_db_name, mdb->m_db_user, mdb->m_db_password, mdb->m_db_address, mdb->m_db_port, mdb->m_db_socket, mdb->m_db_ssl_mode, mdb->m_db_ssl_key, mdb->m_db_ssl_cert, mdb->m_db_ssl_ca, mdb->m_db_ssl_capath, mdb->m_db_ssl_cipher, true, mdb->m_disabled_batch_insert); -} - -const char *BDB::bdb_get_engine_name(void) -{ - BDB *mdb = this; - switch (mdb->m_db_driver_type) { - case SQL_DRIVER_TYPE_MYSQL: - return "MySQL"; - case SQL_DRIVER_TYPE_POSTGRESQL: - return "PostgreSQL"; - case SQL_DRIVER_TYPE_SQLITE3: - return "SQLite3"; - default: - return "Unknown"; - } -} - -/* - * Lock database, this can be called multiple times by the same - * thread without blocking, but must be unlocked the number of - * times it was locked using db_unlock(). - */ -void BDB::bdb_lock(const char *file, int line) -{ - int errstat; - BDB *mdb = this; - - if ((errstat = rwl_writelock_p(&mdb->m_lock, file, line)) != 0) { - berrno be; - e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n", - errstat, be.bstrerror(errstat)); - } -} - -/* - * Unlock the database. This can be called multiple times by the - * same thread up to the number of times that thread called - * db_lock()/ - */ -void BDB::bdb_unlock(const char *file, int line) -{ - int errstat; - BDB *mdb = this; - - if ((errstat = rwl_writeunlock(&mdb->m_lock)) != 0) { - berrno be; - e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n", - errstat, be.bstrerror(errstat)); - } -} - -bool BDB::bdb_sql_query(const char *query, int flags) -{ - bool retval; - BDB *mdb = this; - - bdb_lock(); - retval = sql_query(query, flags); - if (!retval) { - Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror()); - } - bdb_unlock(); - return retval; -} - -void BDB::print_lock_info(FILE *fp) -{ - BDB *mdb = this; - if (mdb->m_lock.valid == RWLOCK_VALID) { - fprintf(fp, "\tRWLOCK=%p w_active=%i w_wait=%i\n", - &mdb->m_lock, mdb->m_lock.w_active, mdb->m_lock.w_wait); - } -} - -/* Parse stream of tags, return next one from the stream (it will be null terminated, - * original buffer will be changed) */ -static char *get_next_tag(char **buf) +} + +const char *BDB::bdb_get_engine_name(void) { - char *p = *buf; - char *tmp = p; - skip_nonspaces(&p); - skip_spaces(&p); - char *c = strpbrk(tmp, " "); - if (c) { - *c = '\0'; - } else { - Dmsg0(dbglvl, "No tag found!\n"); - return NULL; + BDB *mdb = this; + switch (mdb->m_db_driver_type) { + case SQL_DRIVER_TYPE_MYSQL: + return "MySQL"; + case SQL_DRIVER_TYPE_POSTGRESQL: + return "PostgreSQL"; + case SQL_DRIVER_TYPE_SQLITE3: + return "SQLite3"; + default: + return "Unknown"; } - *buf = p; +} + +/* + * Lock database, this can be called multiple times by the same + * thread without blocking, but must be unlocked the number of + * times it was locked using db_unlock(). + */ +void BDB::bdb_lock(const char *file, int line) +{ + int errstat; + BDB *mdb = this; - Dmsg1(dbglvl, "Found tag: %s\n", tmp); - return tmp; + if ((errstat = rwl_writelock_p(&mdb->m_lock, file, line)) != 0) { + berrno be; + e_msg(file, line, M_FATAL, 0, "rwl_writelock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } +} + +/* + * Unlock the database. This can be called multiple times by the + * same thread up to the number of times that thread called + * db_lock()/ + */ +void BDB::bdb_unlock(const char *file, int line) +{ + int errstat; + BDB *mdb = this; + + if ((errstat = rwl_writeunlock(&mdb->m_lock)) != 0) { + berrno be; + e_msg(file, line, M_FATAL, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } } +bool BDB::bdb_sql_query(const char *query, int flags) +{ + bool retval; + BDB *mdb = this; + + bdb_lock(); + retval = sql_query(query, flags); + if (!retval) { + Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror()); + } + bdb_unlock(); + return retval; +} + +void BDB::print_lock_info(FILE *fp) +{ + BDB *mdb = this; + if (mdb->m_lock.valid == RWLOCK_VALID) { + fprintf(fp, "\tRWLOCK=%p w_active=%i w_wait=%i\n", + &mdb->m_lock, mdb->m_lock.w_active, mdb->m_lock.w_wait); + } +} bool OBJECT_DBR::parse_plugin_object_string(char **obj_str) { @@ -391,4 +369,4 @@ void parse_restore_object_string(char **r_obj_str, ROBJECT_DBR *robj_r) robj_r->object_len, robj_r->object); } -#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */ +#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */ diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 76248e7bb..b9c3d07d0 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -172,6 +172,14 @@ base64_test: Makefile libbac.la base64.c unittests.o $(RMF) base64.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) base64.c +edit_test: Makefile libbac.la edit.c unittests.o + $(RMF) edit.o + $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) edit.c + $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L. -o $@ edit.o unittests.o $(DLIB) -lbac -lm $(LIBS) $(OPENSSL_LIBS) + $(LIBTOOL_INSTALL) $(INSTALL_PROGRAM) $@ $(DESTDIR)$(sbindir)/ + $(RMF) edit.o + $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) edit.c + flist_test: Makefile libbac.la flist.c unittests.o $(RMF) flist.o $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) flist.c @@ -260,7 +268,6 @@ crc32_test: Makefile libbac.la org_lib_crc32.c unittests.o $(RMF) org_lib_crc32.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) org_lib_crc32.c - bee_crc32_test: Makefile libbac.la bee_lib_crc32.c unittests.o $(RMF) bee_lib_crc32.o $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) bee_lib_crc32.c @@ -318,7 +325,7 @@ sha1_test: Makefile libbac.la sha1.c unittests.o bsnprintf_test: Makefile libbac.la bsnprintf.c unittests.o $(RMF) bsnprintf.o - $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) -Wno-format-truncation bsnprintf.c + $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) -Wno-format-truncation bsnprintf.c $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L. -o $@ bsnprintf.o unittests.o $(DLIB) -lbac -lm $(LIBS) $(OPENSSL_LIBS) $(LIBTOOL_INSTALL) $(INSTALL_PROGRAM) $@ $(DESTDIR)$(sbindir)/ $(RMF) bsnprintf.o diff --git a/bacula/src/lib/edit.c b/bacula/src/lib/edit.c index 9cd90d2ed..b76e98fe1 100644 --- a/bacula/src/lib/edit.c +++ b/bacula/src/lib/edit.c @@ -505,7 +505,7 @@ bool is_name_valid(const char *name, POOLMEM **msg) * Check if Bacula Resoure Name is valid */ /* - * Check if the Volume/resource name has legal characters + * Check if the Volume name has legal characters * If ua is non-NULL send the message */ bool is_name_valid(const char *name, POOLMEM **msg, const char *accept) @@ -539,7 +539,7 @@ bool is_name_valid(const char *name, POOLMEM **msg, const char *accept) } if (len == 0) { if (msg) { - Mmsg(msg, _("Name must be at least one character long.\n")); + Mmsg(msg, _("Volume name must be at least one character long.\n")); } return false; } @@ -578,24 +578,142 @@ char *add_commas(char *val, char *buf) return buf; } +/* Parse stream of tags, return next one from the stream (it will be null terminated, + * original buffer will be changed) */ +char *get_next_tag(char **buf) +{ + char *tmp = NULL; + + if (**buf != '\0') { + char *p = *buf; + tmp = p; + p = strchr(*buf, ' '); + if (p != NULL){ + *p++ = '\0'; + *buf = p; + } else { + *buf += strlen(tmp); + } + Dmsg1(900, "Found tag: %s\n", tmp); + } else { + Dmsg0(900, "No tag found!\n"); + } + + return tmp; +} + +// #define TEST_PROGRAM + #ifdef TEST_PROGRAM +#include "unittests.h" + void d_msg(const char*, int, int, const char*, ...) {} -int main(int argc, char *argv[]) + +// this is a test vector +// /@kubernetes/ kubernetes:^Ans=plugintest^Adebug^Averify_ssl=0 Container PVCs Kubernetes^APersistent^AVolume^AClaim 5368709120 U 5 +char __po_log1[] = { + 0x2f, 0x40, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, + 0x2f, 0x20, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, + 0x3a, 0x01, 0x6e, 0x73, 0x3d, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x74, + 0x65, 0x73, 0x74, 0x01, 0x64, 0x65, 0x62, 0x75, 0x67, 0x01, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x5f, 0x73, 0x73, 0x6c, 0x3d, 0x30, 0x20, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x50, 0x56, 0x43, + 0x73, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, + 0x01, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x01, + 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x01, 0x43, 0x6c, 0x61, 0x69, 0x6d, + 0x20, 0x20, 0x20, 0x35, 0x33, 0x36, 0x38, 0x37, 0x30, 0x39, 0x31, 0x32, + 0x30, 0x20, 0x55, 0x20, 0x35, 0x00 +}; +unsigned int __po_log1_len = sizeof(__po_log1); +int __po_log1_nr = 10; + +// ASD 123 +char __po_log2[] = {0x41, 0x53, 0x44, 0x20, 0x20, 0x31, 0x32, 0x33, 0x00, 0x00}; +unsigned int __po_log2_len = sizeof(__po_log2); + +struct _edit_utime_vect { - char *str[] = {"3", "3n", "3 hours", "3.5 day", "3 week", "3 m", "3 q", "3 years"}; - utime_t val; - char buf[100]; - char outval[100]; - - for (int i=0; i<8; i++) { - strcpy(buf, str[i]); - if (!duration_to_utime(buf, &val)) { - printf("Error return from duration_to_utime for in=%s\n", str[i]); - continue; + const char *in; + const utime_t val; + const char *outval; +}; + +_edit_utime_vect __testvect1[] = +{ + { "3", 3, "3 secs"}, + { "3n", 180, "3 mins "}, + { "3 hours", 10800, "3 hours "}, + { "3.5 day", 302400, "3 days 12 hours "}, + { "3 week", 1814400, "21 days "}, + { "3 m", 7776000, "3 months "}, + { "3 q", 23587200, "9 months 3 days "}, + { "3 years", 94608000, "3 years "}, + { "23587201", 23587201, "9 months 3 days 1 sec"}, + { NULL, 0, NULL}, +}; + +int main() +{ + Unittests unittest("text_edit_tests"); + + { + utime_t val; + char buf[100]; + char outval[100]; + + for (int i=0; __testvect1[i].in != NULL; i++) { + strcpy(buf, __testvect1[i].in); + POOL_MEM label; + Mmsg(label, "duration_to_utime %s", __testvect1[i].in); + bool status = duration_to_utime(buf, &val); + ok(status, label.c_str()); + if (status){ + edit_utime(val, outval, sizeof(outval)); + ok(val == __testvect1[i].val, "checking val"); + ok(strcmp(outval, __testvect1[i].outval) == 0, "checking outval"); + } + // printf("outval='%s'\n", outval); + } + } + + { + char *testvect = __po_log2; + char **obj_str = &testvect; + + char *fname = get_next_tag(obj_str); + ok(fname != NULL, "checking first tag"); + ok(strcmp(fname, "ASD") == 0, "checking first tag value"); + + char *empty = get_next_tag(obj_str); + ok(empty != NULL, "checking empty tag"); + ok(strlen(empty) == 0, "checking empty value tag"); + + char *last = get_next_tag(obj_str); + ok(last != NULL, "checking last tag"); + ok(strcmp(last, "123") == 0, "checking last tag value"); + ok(obj_str != NULL, "checking obj_str"); + ok(*obj_str != NULL, "checking obj_str ptr"); + ok(**obj_str == 0, "checking obj_str char"); + + char *afterlast = get_next_tag(obj_str); + ok(afterlast == NULL, "checking no tags"); + } + + { + char *testvect = __po_log1; + char **obj_str = &testvect; + + for (int a = 0; a < __po_log1_nr; a++){ + char *tag = get_next_tag(obj_str); + POOL_MEM label; + Mmsg(label, "checking tag %d", a); + ok(tag != NULL, label.c_str()); } - edit_utime(val, outval); - printf("in=%s val=%" lld " outval=%s\n", str[i], val, outval); + ok(get_next_tag(obj_str) == NULL, "checking the last"); } + + return report(); } + #endif diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 50fcd999b..b5f77049c 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -239,6 +239,7 @@ bool is_an_integer (const char *n); #define EXTRA_VALID_RESOURCE_CHAR_GLOB EXTRA_VALID_RESOURCE_CHAR "[]*?" bool is_name_valid (const char *name, POOLMEM **msg); bool is_name_valid (const char *name, POOLMEM **msg, const char *accept); +char *get_next_tag(char **buf); /* jcr.c (most definitions are in src/jcr.h) */ void init_last_jobs_list(); diff --git a/regress/tests/edit-unittest b/regress/tests/edit-unittest new file mode 100755 index 000000000..5d224b1ec --- /dev/null +++ b/regress/tests/edit-unittest @@ -0,0 +1,9 @@ +#!/bin/sh +# +# Copyright (C) 2000-2015 Kern Sibbald +# License: BSD 2-Clause; see file LICENSE-FOSS +# +# This is an alist unit test +# +. scripts/regress-utils.sh +do_regress_unittest "edit_test" "src/lib"