diff --git a/CMakeLists.txt b/CMakeLists.txt index 78736751a7..39f55b94bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1410,6 +1410,9 @@ if(BUILD_TESTING) add_subdirectory(mdstcpip/testing) add_subdirectory(tditest/testing) add_subdirectory(wfevent/testing) + if(TARGET cts_commands) + add_subdirectory(camshr/testing) + endif() add_subdirectory(mdsobjects/cpp/testing) add_subdirectory(python/MDSplus/tests) diff --git a/Jenkinsfile b/Jenkinsfile index 50d3c6cb87..292dbaadff 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -193,6 +193,30 @@ distributions['MATLAB'] = localTest('MATLAB', 'linux-amd64', { } }) +distributions['CAMSHR SQLite'] = localTest('CAMSHR SQLite', 'linux-amd64', { + stage("Test") { + try { + sh ''' + set -eu + ctest -N --test-dir workspace/build > workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_crate_state_fakehw_test" workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_backend_policy_test" workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_sqlite_schema_test" workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_sqlite_migration_test" workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_sqlite_backend_roundtrip_test" workspace/camshr-sqlite-tests.txt + grep -q "camshr/testing/camshr_autoconfig_sqlite_fakeproc_test" workspace/camshr-sqlite-tests.txt + ''' + sh """ + CAMSHR_DB_BACKEND=sqlite deploy/build.py --workspace=workspace --no-configure --no-build --test \ + --output-junit --junit-suite-name='camshr-sqlite' + """ + } + finally { + junit skipPublishingChecks: true, testResults: "workspace/mdsplus-junit.xml", keepLongStdio: true + } + } +}) + def AdminList = [ 'dgarnier', 'GabrieleManduchi', diff --git a/camshr/CMakeLists.txt b/camshr/CMakeLists.txt index d3a8706d38..4efc5a6006 100644 --- a/camshr/CMakeLists.txt +++ b/camshr/CMakeLists.txt @@ -12,6 +12,9 @@ if(HAVE_SCSI_SG_H AND NOT MSVC) CamShr add_entry.c bisearch.c + camac_db_backend.c + camac_db_sqlite.c + camac_hw_iface.c cam_functions.c check_for_file.c check_sema4.c @@ -60,6 +63,20 @@ if(HAVE_SCSI_SG_H AND NOT MSVC) MdsIpShr ) + find_package(SQLite3) + if(SQLite3_FOUND) + target_compile_definitions( + CamShr + PRIVATE + CAMSHR_HAVE_SQLITE3=1 + ) + target_link_libraries( + CamShr + PRIVATE + SQLite::SQLite3 + ) + endif() + set_target_properties( CamShr PROPERTIES @@ -107,4 +124,4 @@ if(HAVE_SCSI_SG_H AND NOT MSVC) PERMISSIONS ${MODE_755} ) -endif() \ No newline at end of file +endif() diff --git a/camshr/Makefile.bak b/camshr/Makefile.bak index 288874eb73..f5666ddb09 100644 --- a/camshr/Makefile.bak +++ b/camshr/Makefile.bak @@ -13,6 +13,9 @@ SHLIB_BUILD = $(top_srcdir)/lib64/$(SHLIB) SOURCES = \ add_entry.c \ bisearch.c \ + camac_db_backend.c \ + camac_db_sqlite.c \ + camac_hw_iface.c \ cam_functions.c \ check_for_file.c \ check_sema4.c \ @@ -94,4 +97,3 @@ $(SHLIB_BUILD) $(IMPLIB): $(OBJECTS) $(LINK.c) -shared -nostartfiles -Wl,-soname=$(SHLIB) -o $@.$(MAJOR).$(MINOR) $^ -L$(top_srcdir)/lib64/ -lMdsShr $(MAKE_IMPLIB) ln -sf $(SHLIB).$(MAJOR).$(MINOR) $@.$(MAJOR) ln -sf $(SHLIB).$(MAJOR) $@ - diff --git a/camshr/Makefile.in b/camshr/Makefile.in index 72a0d97030..78e1ee356a 100644 --- a/camshr/Makefile.in +++ b/camshr/Makefile.in @@ -18,6 +18,9 @@ SHLIB_BUILD = @MAKESHLIBDIR@$(SHLIB) SOURCES = \ add_entry.c \ bisearch.c \ + camac_db_backend.c \ + camac_db_sqlite.c \ + camac_hw_iface.c \ cam_functions.c \ check_for_file.c \ check_sema4.c \ @@ -95,4 +98,3 @@ $(SHLIB_BUILD) $(IMPLIB): $(OBJECTS) $(LINK.c) @LINKSHARED@ -nostartfiles -Wl,-soname=$(SHLIB) -o $@.$(MAJOR).$(MINOR) $^ -L@MAKESHLIBDIR@ -lMdsShr -lMdsIpShr $(MAKE_IMPLIB) ln -sf $(SHLIB).$(MAJOR).$(MINOR) $@.$(MAJOR) ln -sf $(SHLIB).$(MAJOR) $@ - diff --git a/camshr/QueryHighwayType.c b/camshr/QueryHighwayType.c index dbd7055788..e2af62fc38 100644 --- a/camshr/QueryHighwayType.c +++ b/camshr/QueryHighwayType.c @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "camac_hw_iface.h" #include "common.h" #include "prototypes.h" @@ -87,7 +88,7 @@ int QueryHighwayType(char *serial_hwy_driver) int status = SUCCESS; // optimistic static int channels[MAX_SCSI_BUSES] [MAX_SCSI_IDS]; // persistant, highway types - FILE *fp, *fopen(); + FILE *fp; if (MSGLVL(FUNCTION_NAME)) printf("QHT('%s')\n", serial_hwy_driver); @@ -95,10 +96,11 @@ int QueryHighwayType(char *serial_hwy_driver) host_adapter = toupper(*(serial_hwy_driver + 2)) - 'A'; scsi_id = NUMERIC(*(serial_hwy_driver + 3)); - if ((fp = fopen(PROC_FILE, "r")) == NULL) + if ((fp = camac_hw_open_proc_scsi()) == NULL) { if (MSGLVL(ALWAYS)) - fprintf(stderr, "could *NOT* open '%s' for reading\n", PROC_FILE); + fprintf(stderr, "could *NOT* open '%s' for reading\n", + camac_hw_get_proc_file()); status = FAILURE; goto QueryHighwayType_Exit; diff --git a/camshr/README.sqlite-backend.md b/camshr/README.sqlite-backend.md new file mode 100644 index 0000000000..c98e0b3ed0 --- /dev/null +++ b/camshr/README.sqlite-backend.md @@ -0,0 +1,33 @@ +# CAMSHR DB Backend Policy + +`CAMSHR_DB_BACKEND` controls the CAMSHR database backend. + +Default behavior: +- If `CAMSHR_DB_BACKEND` is unset or empty, CAMSHR uses the `sqlite` backend. + +Supported values: +- `sqlite` / `sql` / `auto`: use sqlite backend. +- `mmap` / `legacy` / `file`: force legacy memory-mapped flat-file backend. + +Notes: +- Legacy `mmap` mode is kept as a fallback compatibility path. +- When forcing legacy mode, CAMSHR prints a one-time warning to `stderr`. +- Unknown `CAMSHR_DB_BACKEND` values fall back to `sqlite` and print a one-time warning. + +Testing guidance: +- Sqlite path tests: + - `camshr/testing/camshr_backend_policy_test` + - `camshr/testing/camshr_sqlite_schema_test` + - `camshr/testing/camshr_sqlite_migration_test` + - `camshr/testing/camshr_sqlite_backend_roundtrip_test` + - `camshr/testing/camshr_autoconfig_sqlite_fakeproc_test` +- Legacy fallback coverage: + - `camshr/testing/camshr_crate_state_fakehw_test` (forces `CAMSHR_DB_BACKEND=mmap`) + +Native full-test note: +- In full native `ctest` runs, `tditest/testing/test-dev-py` may be skipped if + `libMitDevices` is not present in `MDSPLUS_LIBRARY_PATH`. + +Hardware-less CTS note: +- `show/crate` now lists crates from the database even when live SCSI is down, + and displays cached DB status in that case. diff --git a/camshr/ScsiSystemStatus.c b/camshr/ScsiSystemStatus.c index 3621346cb3..1e24cb4127 100644 --- a/camshr/ScsiSystemStatus.c +++ b/camshr/ScsiSystemStatus.c @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "camac_hw_iface.h" #include "common.h" #include "prototypes.h" @@ -56,14 +57,14 @@ int ScsiSystemStatus(void) { char line[80], *pline; int scsiSystemStatus = 0; // assume the worst :( - FILE *fp, *fopen(); + FILE *fp; if (MSGLVL(FUNCTION_NAME)) printf("ScsiSystemStatus()\n"); - if ((fp = fopen(PROC_FILE, "r")) == NULL) + if ((fp = camac_hw_open_proc_scsi()) == NULL) { - fprintf(stderr, "can't open '%s' for read\n", PROC_FILE); + fprintf(stderr, "can't open '%s' for read\n", camac_hw_get_proc_file()); scsiSystemStatus = 0; goto ScsiSystemStatus_Exit; } diff --git a/camshr/camac_db_backend.c b/camshr/camac_db_backend.c new file mode 100644 index 0000000000..017ddc4fbf --- /dev/null +++ b/camshr/camac_db_backend.c @@ -0,0 +1,502 @@ +#include "camac_db_backend.h" + +#include "camac_db_sqlite.h" +#include "common.h" +#include "crate.h" +#include "module.h" +#include "prototypes.h" + +#include +#include +#include +#include +#include + +extern int CTSdbFileIsMapped; +extern int CRATEdbFileIsMapped; +extern struct MODULE *CTSdb; +extern struct CRATE *CRATEdb; + +#ifdef CAMSHR_HAVE_SQLITE3 + +static sqlite3 *g_db = 0; +static int g_cts_capacity = 0; +static int g_crate_capacity = 0; +static int g_cts_owned = FALSE; +static int g_crate_owned = FALSE; +static int g_warned_mmap_fallback = FALSE; +static int g_warned_unknown_backend = FALSE; + +static int round_capacity(int count, int incr) +{ + if (incr <= 0) + incr = 1; + if (count < 0) + count = 0; + return ((count / incr) + 1) * incr; +} + +static int decode_hwy_char(char c) +{ + if (c == '.') + return TYPE_UNKNOWN; + if (isdigit((unsigned char)c)) + return c - '0'; + return (unsigned char)c; +} + +static char encode_hwy_char(int type) +{ + if (type >= 0 && type <= 9) + return (char)('0' + type); + if (type == TYPE_UNKNOWN) + return '.'; + return (char)type; +} + +static int snapshot_count(int dbType) +{ + int i; + int capacity; + int entry_size; + char *p; + + switch (dbType) + { + case CTS_DB: + p = (char *)CTSdb; + capacity = g_cts_capacity; + entry_size = MODULE_ENTRY; + break; + case CRATE_DB: + p = (char *)CRATEdb; + capacity = g_crate_capacity; + entry_size = CRATE_ENTRY; + break; + default: + return 0; + } + if (!p || capacity <= 0) + return 0; + for (i = 0; i < capacity; ++i) + if (*(p + (i * entry_size)) == ' ') + return i; + return capacity; +} + +static int ensure_open(void) +{ + const char *db_dir; + int cts_count = 0; + int crate_count = 0; + + if (g_db) + return SUCCESS; + + if (camac_db_sqlite_open(get_file_name("camac.db"), &g_db) != SUCCESS) + return FILE_ERROR; + if (camac_db_sqlite_init(g_db) != SUCCESS) + return ERROR; + + if (camac_db_sqlite_table_count(g_db, "cts_modules", &cts_count) != SUCCESS) + return ERROR; + if (camac_db_sqlite_table_count(g_db, "crate_map", &crate_count) != SUCCESS) + return ERROR; + + if (cts_count == 0 && crate_count == 0) + { + db_dir = getenv(DB_DIR); + if (camac_db_sqlite_import_legacy(g_db, db_dir ? db_dir : ".") != SUCCESS) + return ERROR; + } + + return SUCCESS; +} + +static int load_cts_snapshot(void) +{ + sqlite3_stmt *count_stmt = 0; + sqlite3_stmt *stmt = 0; + struct MODULE *buf = 0; + int count = 0; + int idx = 0; + int cap; + + if (sqlite3_prepare_v2(g_db, "SELECT COUNT(*) FROM cts_modules", -1, &count_stmt, + 0) != SQLITE_OK) + return ERROR; + if (sqlite3_step(count_stmt) == SQLITE_ROW) + count = sqlite3_column_int(count_stmt, 0); + sqlite3_finalize(count_stmt); + + cap = round_capacity(count, CTS_DB_INCREMENT); + buf = malloc((size_t)cap * sizeof(struct MODULE)); + if (!buf) + return NO_MEMORY; + memset(buf, ' ', (size_t)cap * sizeof(struct MODULE)); + + if (sqlite3_prepare_v2( + g_db, + "SELECT logical_name,adapter,scsi_id,crate,slot,comment " + "FROM cts_modules ORDER BY logical_name COLLATE NOCASE", + -1, &stmt, 0) != SQLITE_OK) + { + free(buf); + return ERROR; + } + + while (sqlite3_step(stmt) == SQLITE_ROW && idx < count) + { + const char *name = (const char *)sqlite3_column_text(stmt, 0); + int adapter = sqlite3_column_int(stmt, 1); + int scsi_id = sqlite3_column_int(stmt, 2); + int crate = sqlite3_column_int(stmt, 3); + int slot = sqlite3_column_int(stmt, 4); + const char *comment = (const char *)sqlite3_column_text(stmt, 5); + char line[MODULE_ENTRY + 1]; + char phys[16]; + + snprintf(phys, sizeof(phys), "GK%c%d%02d:N%d", 'A' + adapter, scsi_id, crate, + slot); + memset(line, ' ', sizeof(line)); + snprintf(line, sizeof(line), "%-32s %-10s %-40s\n", name ? name : "", + phys, comment ? comment : ""); + memcpy(&buf[idx], line, MODULE_ENTRY); + idx++; + } + sqlite3_finalize(stmt); + + if (g_cts_owned && CTSdb) + free(CTSdb); + CTSdb = buf; + g_cts_capacity = cap; + g_cts_owned = TRUE; + CTSdbFileIsMapped = TRUE; + return SUCCESS; +} + +static int load_crate_snapshot(void) +{ + sqlite3_stmt *count_stmt = 0; + sqlite3_stmt *stmt = 0; + struct CRATE *buf = 0; + int count = 0; + int idx = 0; + int cap; + + if (sqlite3_prepare_v2(g_db, "SELECT COUNT(*) FROM crate_map", -1, &count_stmt, + 0) != SQLITE_OK) + return ERROR; + if (sqlite3_step(count_stmt) == SQLITE_ROW) + count = sqlite3_column_int(count_stmt, 0); + sqlite3_finalize(count_stmt); + + cap = round_capacity(count, CRATE_DB_INCREMENT); + buf = malloc((size_t)cap * sizeof(struct CRATE)); + if (!buf) + return NO_MEMORY; + memset(buf, ' ', (size_t)cap * sizeof(struct CRATE)); + + if (sqlite3_prepare_v2( + g_db, + "SELECT crate_name,device_num,highway_type,enhanced,online " + "FROM crate_map ORDER BY crate_name COLLATE NOCASE", + -1, &stmt, 0) != SQLITE_OK) + { + free(buf); + return ERROR; + } + + while (sqlite3_step(stmt) == SQLITE_ROW && idx < count) + { + const char *crate_name = (const char *)sqlite3_column_text(stmt, 0); + int device_num = sqlite3_column_int(stmt, 1); + int highway_type = sqlite3_column_int(stmt, 2); + int enhanced = sqlite3_column_int(stmt, 3); + int online = sqlite3_column_int(stmt, 4); + char line[CRATE_ENTRY + 1]; + char dsf[4]; + char hwy_char = encode_hwy_char(highway_type); + + if (device_num >= 0) + snprintf(dsf, sizeof(dsf), "%03d", device_num); + else + snprintf(dsf, sizeof(dsf), "..."); + memset(line, ' ', sizeof(line)); + snprintf(line, sizeof(line), "%-.6s:%3s:%c:%c:%c\n", + crate_name ? crate_name : "", dsf, hwy_char, + enhanced ? '1' : '0', online ? '1' : '0'); + memcpy(&buf[idx], line, CRATE_ENTRY); + idx++; + } + sqlite3_finalize(stmt); + + if (g_crate_owned && CRATEdb) + free(CRATEdb); + CRATEdb = buf; + g_crate_capacity = cap; + g_crate_owned = TRUE; + CRATEdbFileIsMapped = TRUE; + return SUCCESS; +} + +static int commit_cts(void) +{ + sqlite3_stmt *stmt = 0; + int i; + int count = snapshot_count(CTS_DB); + + if (sqlite3_exec(g_db, "DELETE FROM cts_modules", 0, 0, 0) != SQLITE_OK) + return ERROR; + + if (sqlite3_prepare_v2( + g_db, + "INSERT INTO cts_modules" + "(logical_name,adapter,scsi_id,crate,slot,comment) VALUES(?,?,?,?,?,?)", + -1, &stmt, 0) != SQLITE_OK) + return ERROR; + + for (i = 0; i < count; ++i) + { + struct Module_ mod; + parse_cts_db(CTSdb + i, &mod); + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_bind_text(stmt, 1, mod.name, -1, SQLITE_TRANSIENT); + sqlite3_bind_int(stmt, 2, mod.adapter); + sqlite3_bind_int(stmt, 3, mod.id); + sqlite3_bind_int(stmt, 4, mod.crate); + sqlite3_bind_int(stmt, 5, mod.slot); + sqlite3_bind_text(stmt, 6, mod.comment, -1, SQLITE_TRANSIENT); + if (sqlite3_step(stmt) != SQLITE_DONE) + { + sqlite3_finalize(stmt); + return ERROR; + } + } + sqlite3_finalize(stmt); + return SUCCESS; +} + +static int commit_crate(void) +{ + sqlite3_stmt *stmt = 0; + int i; + int count = snapshot_count(CRATE_DB); + + if (sqlite3_exec(g_db, "DELETE FROM crate_map", 0, 0, 0) != SQLITE_OK) + return ERROR; + + if (sqlite3_prepare_v2( + g_db, + "INSERT INTO crate_map" + "(crate_name,device_num,highway_type,enhanced,online) VALUES(?,?,?,?,?)", + -1, &stmt, 0) != SQLITE_OK) + return ERROR; + + for (i = 0; i < count; ++i) + { + struct Crate_ crate; + parse_crate_db(CRATEdb + i, &crate); + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_bind_text(stmt, 1, crate.name, -1, SQLITE_TRANSIENT); + sqlite3_bind_int(stmt, 2, crate.device); + sqlite3_bind_int(stmt, 3, decode_hwy_char(CRATEdb[i].HwyType)); + sqlite3_bind_int(stmt, 4, crate.enhanced); + sqlite3_bind_int(stmt, 5, crate.online); + if (sqlite3_step(stmt) != SQLITE_DONE) + { + sqlite3_finalize(stmt); + return ERROR; + } + } + sqlite3_finalize(stmt); + return SUCCESS; +} + +int camac_db_backend_enabled(void) +{ + const char *v = getenv("CAMSHR_DB_BACKEND"); + if (!v || *v == '\0') + return TRUE; // sqlite is the default backend + + if ((strcasecmp(v, "mmap") == 0) || (strcasecmp(v, "legacy") == 0) || + (strcasecmp(v, "file") == 0)) + { + if (!g_warned_mmap_fallback) + { + fprintf(stderr, + "camshr: CAMSHR_DB_BACKEND=%s enables legacy mmap backend " + "(sqlite is default)\n", + v); + g_warned_mmap_fallback = TRUE; + } + return FALSE; + } + + if ((strcasecmp(v, "sqlite") == 0) || (strcasecmp(v, "sql") == 0) || + (strcasecmp(v, "auto") == 0)) + return TRUE; + + if (!g_warned_unknown_backend) + { + fprintf(stderr, + "camshr: unknown CAMSHR_DB_BACKEND=%s, defaulting to sqlite\n", v); + g_warned_unknown_backend = TRUE; + } + + return TRUE; +} + +int camac_db_backend_map(int dbType) +{ + if (ensure_open() != SUCCESS) + return MAP_ERROR; + + switch (dbType) + { + case CTS_DB: + return load_cts_snapshot(); + case CRATE_DB: + return load_crate_snapshot(); + default: + return ERROR; + } +} + +int camac_db_backend_commit(int dbType) +{ + int rc = ERROR; + if (ensure_open() != SUCCESS) + return COMMIT_ERROR; + + if (sqlite3_exec(g_db, "BEGIN IMMEDIATE TRANSACTION", 0, 0, 0) != SQLITE_OK) + return COMMIT_ERROR; + + switch (dbType) + { + case CTS_DB: + rc = commit_cts(); + break; + case CRATE_DB: + rc = commit_crate(); + break; + default: + rc = ERROR; + break; + } + + if (rc == SUCCESS) + { + if (sqlite3_exec(g_db, "COMMIT", 0, 0, 0) != SQLITE_OK) + rc = ERROR; + } + else + sqlite3_exec(g_db, "ROLLBACK", 0, 0, 0); + + return rc == SUCCESS ? SUCCESS : COMMIT_ERROR; +} + +int camac_db_backend_get_size_bytes(const char *FileName) +{ + if (!FileName) + return ERROR; + if (strcmp(FileName, CTS_DB_FILE) == 0) + { + if (!CTSdbFileIsMapped && camac_db_backend_map(CTS_DB) != SUCCESS) + return ERROR; + return g_cts_capacity * MODULE_ENTRY; + } + if (strcmp(FileName, CRATE_DB_FILE) == 0) + { + if (!CRATEdbFileIsMapped && camac_db_backend_map(CRATE_DB) != SUCCESS) + return ERROR; + return g_crate_capacity * CRATE_ENTRY; + } + return ERROR; +} + +int camac_db_backend_expand(int dbType, int numOfEntries) +{ + int newcap; + void *p; + int oldcap; + int entry; + + switch (dbType) + { + case CTS_DB: + oldcap = g_cts_capacity; + entry = MODULE_ENTRY; + newcap = round_capacity(numOfEntries, CTS_DB_INCREMENT); + if (newcap <= oldcap) + return SUCCESS; + p = realloc(CTSdb, (size_t)newcap * entry); + if (!p) + return NO_MEMORY; + memset((char *)p + ((size_t)oldcap * entry), ' ', + (size_t)(newcap - oldcap) * entry); + CTSdb = (struct MODULE *)p; + g_cts_capacity = newcap; + g_cts_owned = TRUE; + return SUCCESS; + case CRATE_DB: + oldcap = g_crate_capacity; + entry = CRATE_ENTRY; + newcap = round_capacity(numOfEntries, CRATE_DB_INCREMENT); + if (newcap <= oldcap) + return SUCCESS; + p = realloc(CRATEdb, (size_t)newcap * entry); + if (!p) + return NO_MEMORY; + memset((char *)p + ((size_t)oldcap * entry), ' ', + (size_t)(newcap - oldcap) * entry); + CRATEdb = (struct CRATE *)p; + g_crate_capacity = newcap; + g_crate_owned = TRUE; + return SUCCESS; + default: + return ERROR; + } +} + +int camac_db_backend_contract(int dbType, int numOfEntries) +{ + (void)dbType; + (void)numOfEntries; + return SUCCESS; +} + +#else + +int camac_db_backend_enabled(void) { return FALSE; } +int camac_db_backend_map(int dbType) +{ + (void)dbType; + return MAP_ERROR; +} +int camac_db_backend_commit(int dbType) +{ + (void)dbType; + return COMMIT_ERROR; +} +int camac_db_backend_get_size_bytes(const char *FileName) +{ + (void)FileName; + return ERROR; +} +int camac_db_backend_expand(int dbType, int numOfEntries) +{ + (void)dbType; + (void)numOfEntries; + return ERROR; +} +int camac_db_backend_contract(int dbType, int numOfEntries) +{ + (void)dbType; + (void)numOfEntries; + return ERROR; +} + +#endif diff --git a/camshr/camac_db_backend.h b/camshr/camac_db_backend.h new file mode 100644 index 0000000000..1e2c825529 --- /dev/null +++ b/camshr/camac_db_backend.h @@ -0,0 +1,13 @@ +#ifndef CAMAC_DB_BACKEND_H +#define CAMAC_DB_BACKEND_H + +#include + +extern EXPORT int camac_db_backend_enabled(void); +extern EXPORT int camac_db_backend_map(int dbType); +extern EXPORT int camac_db_backend_commit(int dbType); +extern EXPORT int camac_db_backend_get_size_bytes(const char *FileName); +extern EXPORT int camac_db_backend_expand(int dbType, int numOfEntries); +extern EXPORT int camac_db_backend_contract(int dbType, int numOfEntries); + +#endif diff --git a/camshr/camac_db_sqlite.c b/camshr/camac_db_sqlite.c new file mode 100644 index 0000000000..d6fd831945 --- /dev/null +++ b/camshr/camac_db_sqlite.c @@ -0,0 +1,261 @@ +#include "camac_db_sqlite.h" + +#include "common.h" +#include "crate.h" +#include "module.h" +#include "prototypes.h" + +#ifdef CAMSHR_HAVE_SQLITE3 + +#include +#include +#include +#include + +static int exec_sql(sqlite3 *db, const char *sql) +{ + int rc; + char *errmsg = 0; + rc = sqlite3_exec(db, sql, 0, 0, &errmsg); + if (rc != SQLITE_OK) + { + if (errmsg) + sqlite3_free(errmsg); + return ERROR; + } + return SUCCESS; +} + +static int import_cts(sqlite3 *db, const char *path) +{ + FILE *fp; + sqlite3_stmt *stmt = 0; + int status = SUCCESS; + + fp = fopen(path, "rb"); + if (!fp) + return SUCCESS; + + if (sqlite3_prepare_v2( + db, + "INSERT OR REPLACE INTO cts_modules" + "(logical_name,adapter,scsi_id,crate,slot,comment) " + "VALUES(?,?,?,?,?,?)", + -1, &stmt, 0) != SQLITE_OK) + { + fclose(fp); + return ERROR; + } + + for (;;) + { + struct MODULE rec; + struct Module_ mod; + size_t got = fread(&rec, 1, sizeof(rec), fp); + if (got != sizeof(rec)) + break; + if (rec.Name[0] == ' ') + continue; + memset(&mod, 0, sizeof(mod)); + parse_cts_db(&rec, &mod); + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_bind_text(stmt, 1, mod.name, -1, SQLITE_TRANSIENT); + sqlite3_bind_int(stmt, 2, mod.adapter); + sqlite3_bind_int(stmt, 3, mod.id); + sqlite3_bind_int(stmt, 4, mod.crate); + sqlite3_bind_int(stmt, 5, mod.slot); + sqlite3_bind_text(stmt, 6, mod.comment, -1, SQLITE_TRANSIENT); + if (sqlite3_step(stmt) != SQLITE_DONE) + { + status = ERROR; + break; + } + } + + sqlite3_finalize(stmt); + fclose(fp); + return status; +} + +static int decode_hwy_type(char c) +{ + if (c == '.') + return TYPE_UNKNOWN; + if (isdigit((unsigned char)c)) + return c - '0'; + return (unsigned char)c; +} + +static int import_crate(sqlite3 *db, const char *path) +{ + FILE *fp; + sqlite3_stmt *stmt = 0; + int status = SUCCESS; + + fp = fopen(path, "rb"); + if (!fp) + return SUCCESS; + + if (sqlite3_prepare_v2( + db, + "INSERT OR REPLACE INTO crate_map" + "(crate_name,device_num,highway_type,enhanced,online) " + "VALUES(?,?,?,?,?)", + -1, &stmt, 0) != SQLITE_OK) + { + fclose(fp); + return ERROR; + } + + for (;;) + { + struct CRATE rec; + struct Crate_ crate; + size_t got = fread(&rec, 1, sizeof(rec), fp); + if (got != sizeof(rec)) + break; + if (rec.Phys_Name.prefix[0] == ' ') + continue; + memset(&crate, 0, sizeof(crate)); + parse_crate_db(&rec, &crate); + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_bind_text(stmt, 1, crate.name, -1, SQLITE_TRANSIENT); + sqlite3_bind_int(stmt, 2, crate.device); + sqlite3_bind_int(stmt, 3, decode_hwy_type(rec.HwyType)); + sqlite3_bind_int(stmt, 4, crate.enhanced); + sqlite3_bind_int(stmt, 5, crate.online); + if (sqlite3_step(stmt) != SQLITE_DONE) + { + status = ERROR; + break; + } + } + + sqlite3_finalize(stmt); + fclose(fp); + return status; +} + +int camac_db_sqlite_open(const char *path, sqlite3 **db) +{ + if (!path || !db) + return ERROR; + if (sqlite3_open(path, db) != SQLITE_OK) + return FILE_ERROR; + return SUCCESS; +} + +int camac_db_sqlite_init(sqlite3 *db) +{ + static const char *schema_sql = + "CREATE TABLE IF NOT EXISTS cts_modules (" + " logical_name TEXT PRIMARY KEY COLLATE NOCASE," + " adapter INTEGER NOT NULL," + " scsi_id INTEGER NOT NULL," + " crate INTEGER NOT NULL," + " slot INTEGER NOT NULL," + " comment TEXT NOT NULL DEFAULT ''" + ");" + "CREATE TABLE IF NOT EXISTS crate_map (" + " crate_name TEXT PRIMARY KEY COLLATE NOCASE," + " device_num INTEGER NOT NULL DEFAULT -1," + " highway_type INTEGER NOT NULL DEFAULT 0," + " enhanced INTEGER NOT NULL DEFAULT 0," + " online INTEGER NOT NULL DEFAULT 0" + ");" + "CREATE INDEX IF NOT EXISTS idx_cts_phy " + "ON cts_modules(adapter,scsi_id,crate,slot);"; + + if (!db) + return ERROR; + if (exec_sql(db, "BEGIN IMMEDIATE TRANSACTION;") != SUCCESS) + return ERROR; + if (exec_sql(db, schema_sql) != SUCCESS) + { + exec_sql(db, "ROLLBACK;"); + return ERROR; + } + if (exec_sql(db, "COMMIT;") != SUCCESS) + return ERROR; + return SUCCESS; +} + +int camac_db_sqlite_import_legacy(sqlite3 *db, const char *db_dir) +{ + char cts_path[1024]; + char crate_path[1024]; + const char *dir = (db_dir && *db_dir) ? db_dir : "."; + + if (!db) + return ERROR; + + snprintf(cts_path, sizeof(cts_path), "%s/%s", dir, CTS_DB_FILE); + snprintf(crate_path, sizeof(crate_path), "%s/%s", dir, CRATE_DB_FILE); + + if (exec_sql(db, "BEGIN IMMEDIATE TRANSACTION;") != SUCCESS) + return ERROR; + if (import_cts(db, cts_path) != SUCCESS || import_crate(db, crate_path) != SUCCESS) + { + exec_sql(db, "ROLLBACK;"); + return ERROR; + } + if (exec_sql(db, "COMMIT;") != SUCCESS) + return ERROR; + return SUCCESS; +} + +int camac_db_sqlite_table_count(sqlite3 *db, const char *table, int *count) +{ + char sql[128]; + sqlite3_stmt *stmt = 0; + int rc; + if (!db || !table || !count) + return ERROR; + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s", table); + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + if (rc != SQLITE_OK) + return ERROR; + rc = sqlite3_step(stmt); + if (rc != SQLITE_ROW) + { + sqlite3_finalize(stmt); + return ERROR; + } + *count = sqlite3_column_int(stmt, 0); + sqlite3_finalize(stmt); + return SUCCESS; +} + +#else + +int camac_db_sqlite_open(const char *path, sqlite3 **db) +{ + (void)path; + (void)db; + return FILE_ERROR; +} + +int camac_db_sqlite_init(sqlite3 *db) +{ + (void)db; + return FILE_ERROR; +} + +int camac_db_sqlite_import_legacy(sqlite3 *db, const char *db_dir) +{ + (void)db; + (void)db_dir; + return FILE_ERROR; +} + +int camac_db_sqlite_table_count(sqlite3 *db, const char *table, int *count) +{ + (void)db; + (void)table; + (void)count; + return FILE_ERROR; +} + +#endif diff --git a/camshr/camac_db_sqlite.h b/camshr/camac_db_sqlite.h new file mode 100644 index 0000000000..1bc71e377d --- /dev/null +++ b/camshr/camac_db_sqlite.h @@ -0,0 +1,18 @@ +#ifndef CAMAC_DB_SQLITE_H +#define CAMAC_DB_SQLITE_H + +#include + +#ifdef CAMSHR_HAVE_SQLITE3 +#include +#else +typedef struct sqlite3 sqlite3; +#endif + +extern EXPORT int camac_db_sqlite_open(const char *path, sqlite3 **db); +extern EXPORT int camac_db_sqlite_init(sqlite3 *db); +extern EXPORT int camac_db_sqlite_import_legacy(sqlite3 *db, const char *db_dir); +extern EXPORT int camac_db_sqlite_table_count(sqlite3 *db, const char *table, + int *count); + +#endif diff --git a/camshr/camac_hw_iface.c b/camshr/camac_hw_iface.c new file mode 100644 index 0000000000..90012d19f5 --- /dev/null +++ b/camshr/camac_hw_iface.c @@ -0,0 +1,46 @@ +#include "camac_hw_iface.h" + +#include "common.h" +#include "prototypes.h" + +#include + +static camac_cam_piow_fn_t g_cam_piow = 0; +static char g_proc_file_path[1024]; + +void camac_hw_set_cam_piow(camac_cam_piow_fn_t fn) { g_cam_piow = fn; } + +void camac_hw_set_proc_file(const char *path) +{ + if (path && *path) + snprintf(g_proc_file_path, sizeof(g_proc_file_path), "%s", path); + else + g_proc_file_path[0] = '\0'; +} + +const char *camac_hw_get_proc_file(void) +{ + const char *env_path; + if (g_proc_file_path[0] != '\0') + return g_proc_file_path; + env_path = getenv("CAMSHR_PROC_FILE"); + if (env_path && *env_path) + return env_path; + return PROC_FILE; +} + +FILE *camac_hw_open_proc_scsi(void) { return fopen(camac_hw_get_proc_file(), "r"); } + +int camac_hw_cam_piow(char *Name, BYTE A, BYTE F, void *Data, BYTE Mem, + TranslatedIosb *iosb) +{ + if (g_cam_piow) + return g_cam_piow(Name, A, F, Data, Mem, iosb); + return CamPiow(Name, A, F, Data, Mem, iosb); +} + +void camac_hw_reset(void) +{ + g_cam_piow = 0; + g_proc_file_path[0] = '\0'; +} diff --git a/camshr/camac_hw_iface.h b/camshr/camac_hw_iface.h new file mode 100644 index 0000000000..7508765dbc --- /dev/null +++ b/camshr/camac_hw_iface.h @@ -0,0 +1,28 @@ +#ifndef CAMAC_HW_IFACE_H +#define CAMAC_HW_IFACE_H + +#include +#include "mytypes.h" +#include "ScsiCamac.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*camac_cam_piow_fn_t)(char *Name, BYTE A, BYTE F, void *Data, + BYTE Mem, TranslatedIosb *iosb); + +extern EXPORT int camac_hw_cam_piow(char *Name, BYTE A, BYTE F, void *Data, + BYTE Mem, TranslatedIosb *iosb); +extern EXPORT void camac_hw_set_cam_piow(camac_cam_piow_fn_t fn); +extern EXPORT void camac_hw_set_proc_file(const char *path); +extern EXPORT const char *camac_hw_get_proc_file(void); +extern EXPORT FILE *camac_hw_open_proc_scsi(void); +extern EXPORT void camac_hw_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/camshr/check_for_file.c b/camshr/check_for_file.c index 9e55782a8c..55ee86bf58 100644 --- a/camshr/check_for_file.c +++ b/camshr/check_for_file.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "prototypes.h" //------------------------------------------------------------------------- @@ -71,6 +72,11 @@ int check_for_file(char *FileName) if (MSGLVL(FUNCTION_NAME)) printf("check_for_file('%s')\n", FileName); + if (camac_db_backend_enabled() && + ((strcmp(FileName, CTS_DB_FILE) == 0) || + (strcmp(FileName, CRATE_DB_FILE) == 0))) + return SUCCESS; + if ((fd = Open(FileName, O_RDONLY)) < 0) { // file does not exist, yet status = FILE_ERROR; // :< diff --git a/camshr/check_sema4.c b/camshr/check_sema4.c index 80e19d4dd2..3295174cac 100644 --- a/camshr/check_sema4.c +++ b/camshr/check_sema4.c @@ -54,7 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "common.h" #include "prototypes.h" -#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +#if defined(__APPLE__) || \ + (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) // union semun is defined by including #else // according to X/OPEN we have to define it ourselves diff --git a/camshr/commit_entry.c b/camshr/commit_entry.c index 678ca780d4..50a4ddbbad 100644 --- a/camshr/commit_entry.c +++ b/camshr/commit_entry.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "crate.h" #include "module.h" #include "prototypes.h" @@ -75,6 +76,9 @@ int commit_entry(int dbType) if (MSGLVL(FUNCTION_NAME)) printf("commit_entry()\n"); + if (camac_db_backend_enabled()) + return camac_db_backend_commit(dbType); + switch (dbType) { case CTS_DB: diff --git a/camshr/contract_db.c b/camshr/contract_db.c index 8ec4474d50..bcb2115e8d 100644 --- a/camshr/contract_db.c +++ b/camshr/contract_db.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "prototypes.h" //------------------------------------------------------------------------- @@ -75,6 +76,9 @@ int contract_db(int dbType, int numOfEntries) if (MSGLVL(FUNCTION_NAME)) printf("contract_db()\n"); + if (camac_db_backend_enabled()) + return camac_db_backend_contract(dbType, numOfEntries); + // assimilate db specific information ... switch (dbType) { diff --git a/camshr/create_sema4.c b/camshr/create_sema4.c index 74d0cbba0c..987d83cc57 100644 --- a/camshr/create_sema4.c +++ b/camshr/create_sema4.c @@ -54,7 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "common.h" #include "prototypes.h" -#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +#if defined(__APPLE__) || \ + (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) // union semun is defined by including #else // according to X/OPEN we have to define it ourselves diff --git a/camshr/expand_db.c b/camshr/expand_db.c index 51d44e181f..c4f5c60413 100644 --- a/camshr/expand_db.c +++ b/camshr/expand_db.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "prototypes.h" //------------------------------------------------------------------------- @@ -75,6 +76,9 @@ int expand_db(int dbType, int numOfEntries) if (MSGLVL(FUNCTION_NAME)) printf("expand_db()\n"); + if (camac_db_backend_enabled()) + return camac_db_backend_expand(dbType, numOfEntries); + // assimilate db specific information ... switch (dbType) { diff --git a/camshr/get_crate_status.c b/camshr/get_crate_status.c index 4cdfcd9526..35304ac658 100644 --- a/camshr/get_crate_status.c +++ b/camshr/get_crate_status.c @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include "camac_hw_iface.h" #include "common.h" #include "crate.h" #include "prototypes.h" @@ -68,12 +69,12 @@ int get_crate_status(char *crate_name, int *ptr_crate_status) // get crate status SCCdata = 0; - status = CamPiow(controller, // serial crate controller name - 0, // A --\__ read status register - 1, // F --/ - &SCCdata, // returned status - 16, // mem == 16-bit data - &iosb // *iosb + status = camac_hw_cam_piow(controller, // serial crate controller name + 0, // A --\__ read status register + 1, // F --/ + &SCCdata, // returned status + 16, // mem == 16-bit data + &iosb // *iosb ); *ptr_crate_status = (short)((STATUS_OK) ? SCCdata : 0) & 0x0ffff; diff --git a/camshr/get_db_file_size.c b/camshr/get_db_file_size.c index 536cf2b549..d513118567 100644 --- a/camshr/get_db_file_size.c +++ b/camshr/get_db_file_size.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "prototypes.h" //------------------------------------------------------------------------- @@ -72,6 +73,13 @@ int get_db_file_size(char *FileName) if (MSGLVL(FUNCTION_NAME)) printf("get_db_file_size('%s')\n", FileName); + if (camac_db_backend_enabled()) + { + retval = camac_db_backend_get_size_bytes(FileName); + if (retval >= 0) + return retval; + } + if (Stat(FileName, &sbuf) == ERROR) { perror("stat()"); diff --git a/camshr/map_data_file.c b/camshr/map_data_file.c index aec5078b13..52fa45491e 100644 --- a/camshr/map_data_file.c +++ b/camshr/map_data_file.c @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "crate.h" #include "module.h" #include "prototypes.h" @@ -97,6 +98,13 @@ int map_data_file(int dbType) if (MSGLVL(FUNCTION_NAME)) printf("map_data_file('%s')\n", FileName); + if (camac_db_backend_enabled()) + { + status = camac_db_backend_map(dbType); + *FileIsMapped = (status == SUCCESS) ? TRUE : FALSE; + goto MapData_Exit; + } + // check to see if db file exists if (check_for_file(FileName) != SUCCESS) { diff --git a/camshr/map_scsi_device.c b/camshr/map_scsi_device.c index 46730a4e5b..489dcef4fd 100644 --- a/camshr/map_scsi_device.c +++ b/camshr/map_scsi_device.c @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "camac_hw_iface.h" #include "common.h" #include "prototypes.h" @@ -74,17 +75,17 @@ int map_scsi_device(char *highway_name) int adapter, i, numOfEntries, scsi_id, sg_number; int status = SUCCESS; // optimistic int found = FALSE; - FILE *fp, *fopen(); + FILE *fp; extern struct CRATE *CRATEdb; // pointer to in-memory copy of data file if (MSGLVL(FUNCTION_NAME)) printf("map_scsi_device('%s')\n", highway_name); // open '/proc' filesystem scsi info - if ((fp = fopen(PROC_FILE, "r")) == NULL) + if ((fp = camac_hw_open_proc_scsi()) == NULL) { if (MSGLVL(ALWAYS)) - fprintf(stderr, "failure to open '%s'\n", PROC_FILE); + fprintf(stderr, "failure to open '%s'\n", camac_hw_get_proc_file()); status = FILE_ERROR; // serious error !!! no scsi devices to check goto MapScsiDevice_Exit; diff --git a/camshr/testing/CMakeLists.txt b/camshr/testing/CMakeLists.txt new file mode 100644 index 0000000000..398cbb1d41 --- /dev/null +++ b/camshr/testing/CMakeLists.txt @@ -0,0 +1,93 @@ +set(_test_source_list + camshr_crate_state_fakehw_test.c +) + +foreach(_test_source ${_test_source_list}) + + cmake_path(GET _test_source STEM _test_name) + + add_executable( + ${_test_name} + ${_test_source} + ) + + target_link_libraries( + ${_test_name} + PRIVATE + CamShr + MdsTestShr + ) + + mdsplus_add_test( + NAME "${_test_name}" + COMMAND $ + ) + +endforeach() + +find_path(CAMSHR_SQLITE3_INCLUDE_DIR sqlite3.h) +find_library(CAMSHR_SQLITE3_LIBRARY sqlite3) + +if(CAMSHR_SQLITE3_INCLUDE_DIR AND CAMSHR_SQLITE3_LIBRARY AND TARGET cts_commands) + set(_sqlite_test_source_list + camshr_backend_policy_test.c + camshr_sqlite_schema_test.c + camshr_sqlite_migration_test.c + camshr_sqlite_backend_roundtrip_test.c + camshr_autoconfig_sqlite_fakeproc_test.c + ) + + foreach(_test_source ${_sqlite_test_source_list}) + + cmake_path(GET _test_source STEM _test_name) + + add_executable( + ${_test_name} + ${_test_source} + ) + + target_include_directories( + ${_test_name} + PRIVATE + ${CAMSHR_SQLITE3_INCLUDE_DIR} + ) + + target_compile_definitions( + ${_test_name} + PRIVATE + CAMSHR_HAVE_SQLITE3=1 + ) + + target_link_libraries( + ${_test_name} + PRIVATE + CamShr + MdsTestShr + ${CAMSHR_SQLITE3_LIBRARY} + ) + + if(_test_name STREQUAL "camshr_autoconfig_sqlite_fakeproc_test") + target_link_libraries( + ${_test_name} + PRIVATE + cts_commands + ) + mdsplus_add_test( + NAME "${_test_name}" + COMMAND $ + ENVIRONMENT_MODIFICATION + "CAMSHR_PROC_FILE=set:${CMAKE_CURRENT_SOURCE_DIR}/fixtures/proc_scsi_scsi.txt" + ) + else() + mdsplus_add_test( + NAME "${_test_name}" + COMMAND $ + ) + endif() + + endforeach() +elseif(NOT CAMSHR_SQLITE3_INCLUDE_DIR OR NOT CAMSHR_SQLITE3_LIBRARY) + message(STATUS "Skipping camshr sqlite tests: sqlite3 not found") +else() + message(STATUS "Skipping camshr sqlite tests: full CAMSHR build unavailable (cts_commands target missing)") +endif() diff --git a/camshr/testing/camshr_autoconfig_sqlite_fakeproc_test.c b/camshr/testing/camshr_autoconfig_sqlite_fakeproc_test.c new file mode 100644 index 0000000000..ae5c16ac77 --- /dev/null +++ b/camshr/testing/camshr_autoconfig_sqlite_fakeproc_test.c @@ -0,0 +1,68 @@ +#include "testing.h" + +#include "../common.h" +#include "../crate.h" +#include "../prototypes.h" + +#include +#include +#include +#include + +extern int CRATEdbFileIsMapped; +extern struct CRATE *CRATEdb; + +extern int Autoconfig(void *ctx, char **error, char **output); + +static void make_path(char *out, size_t out_len, const char *dir, const char *name) +{ + snprintf(out, out_len, "%s/%s", dir, name); +} + +int main() +{ + char tmpdir[] = "/tmp/camshr-autoconfig-XXXXXX"; + char sqlite_path[1024]; + char line[CRATE_ENTRY + 1]; + int idx; + struct Crate_ crate; + char *error = 0; + char *output = 0; + + BEGIN_TESTING(CamShrAutoconfigSqliteFakeProc); + + TEST1(mkdtemp(tmpdir) != 0); + TEST1(setenv(DB_DIR, tmpdir, 1) == 0); + TEST1(setenv("CAMSHR_DB_BACKEND", "sqlite", 1) == 0); + + CRATEdbFileIsMapped = FALSE; + TEST1(map_data_file(CRATE_DB) == SUCCESS); + TEST1(get_file_count(CRATE_DB) == 0); + + snprintf(line, sizeof(line), "%-.6s:%3s:%c:%c:%c\n", "GKA100", "...", '.', '0', + '0'); + line[CRATE_ENTRY - 1] = '\n'; + TEST1(add_entry(CRATE_DB, line) == SUCCESS); + TEST1(get_file_count(CRATE_DB) == 1); + + TEST1(Autoconfig(0, &error, &output) == SUCCESS); + TEST1(error == 0); + + idx = lookup_entry(CRATE_DB, "GKA100"); + TEST1(idx >= 0); + memset(&crate, 0, sizeof(crate)); + parse_crate_db(CRATEdb + idx, &crate); + TEST1(crate.device == 0); + TEST1(CRATEdb[idx].HwyType == '2'); + + free(error); + free(output); + unsetenv("CAMSHR_DB_BACKEND"); + unsetenv(DB_DIR); + make_path(sqlite_path, sizeof(sqlite_path), tmpdir, "camac.db"); + unlink(sqlite_path); + rmdir(tmpdir); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/camshr_backend_policy_test.c b/camshr/testing/camshr_backend_policy_test.c new file mode 100644 index 0000000000..c06f904b96 --- /dev/null +++ b/camshr/testing/camshr_backend_policy_test.c @@ -0,0 +1,42 @@ +#include "testing.h" + +#include "../camac_db_backend.h" + +#include + +int main() +{ + BEGIN_TESTING(CamShrBackendPolicy); + + TEST1(unsetenv("CAMSHR_DB_BACKEND") == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "", 1) == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "sqlite", 1) == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "sql", 1) == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "auto", 1) == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "mmap", 1) == 0); + TEST1(camac_db_backend_enabled() == 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "legacy", 1) == 0); + TEST1(camac_db_backend_enabled() == 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "file", 1) == 0); + TEST1(camac_db_backend_enabled() == 0); + + TEST1(setenv("CAMSHR_DB_BACKEND", "something-unknown", 1) == 0); + TEST1(camac_db_backend_enabled() != 0); + + TEST1(unsetenv("CAMSHR_DB_BACKEND") == 0); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/camshr_crate_state_fakehw_test.c b/camshr/testing/camshr_crate_state_fakehw_test.c new file mode 100644 index 0000000000..9868e044de --- /dev/null +++ b/camshr/testing/camshr_crate_state_fakehw_test.c @@ -0,0 +1,99 @@ +#include "testing.h" + +#include "../camac_hw_iface.h" +#include "../common.h" +#include "../crate.h" +#include "../prototypes.h" + +#include +#include +#include +#include + +extern int CRATEdbFileIsMapped; +extern struct CRATE *CRATEdb; + +static short g_fake_status_word = 0; +static int g_fake_piow_calls = 0; + +static int fake_cam_piow(char *Name, BYTE A, BYTE F, void *Data, BYTE Mem, + TranslatedIosb *iosb) +{ + (void)Name; + (void)A; + (void)Mem; + (void)iosb; + ++g_fake_piow_calls; + if (F == 1 && Data) + *(short *)Data = g_fake_status_word; + return SUCCESS; +} + +static void make_path(char *out, size_t out_len, const char *dir, const char *name) +{ + snprintf(out, out_len, "%s/%s", dir, name); +} + +int main() +{ + char tmpdir[] = "/tmp/camshr-fakehw-XXXXXX"; + char crate_path[1024]; + char rec[CRATE_ENTRY]; + FILE *fp; + int idx; + char crate_on[] = "gka100"; + char crate_off[] = "GKA100"; + + BEGIN_TESTING(CamShrFakeCrateState); + + TEST1(mkdtemp(tmpdir) != 0); + make_path(crate_path, sizeof(crate_path), tmpdir, CRATE_DB_FILE); + + memset(rec, ' ', sizeof(rec)); + snprintf(rec, sizeof(rec), "%-.6s:%3s:%c:%c:%c\n", "GKA100", "001", '2', '0', + '0'); + { + size_t i; + for (i = 0; i < sizeof(rec); ++i) + if (rec[i] == '\0') + rec[i] = ' '; + } + rec[sizeof(rec) - 1] = '\n'; + + fp = fopen(crate_path, "wb"); + TEST1(fp != 0); + TEST1(fwrite(rec, 1, sizeof(rec), fp) == sizeof(rec)); + fclose(fp); + + TEST1(setenv(DB_DIR, tmpdir, 1) == 0); + TEST1(setenv("CAMSHR_DB_BACKEND", "mmap", 1) == 0); + + CRATEdbFileIsMapped = FALSE; + camac_hw_reset(); + camac_hw_set_cam_piow(fake_cam_piow); + + TEST1(map_data_file(CRATE_DB) == SUCCESS); + idx = lookup_entry(CRATE_DB, "GKA100"); + TEST1(idx >= 0); + + g_fake_status_word = 0x4000; + TEST1(turn_crate_on_off_line(crate_on, ON) == SUCCESS); + TEST1(CRATEdb[idx].online == '1'); + TEST1(CRATEdb[idx].enhanced == '1'); + + g_fake_status_word = 0x1000; + TEST1(turn_crate_on_off_line(crate_off, OFF) == SUCCESS); + TEST1(CRATEdb[idx].online == '0'); + TEST1(CRATEdb[idx].enhanced == '0'); + + TEST1(g_fake_piow_calls >= 6); + + camac_hw_reset(); + unsetenv("CAMSHR_DB_BACKEND"); + unsetenv(DB_DIR); + unlink(crate_path); + rmdir(tmpdir); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/camshr_sqlite_backend_roundtrip_test.c b/camshr/testing/camshr_sqlite_backend_roundtrip_test.c new file mode 100644 index 0000000000..353936eaba --- /dev/null +++ b/camshr/testing/camshr_sqlite_backend_roundtrip_test.c @@ -0,0 +1,70 @@ +#include "testing.h" + +#include "../common.h" +#include "../cts_p.h" +#include "../module.h" +#include "../prototypes.h" + +#include +#include +#include +#include + +extern int CTSdbFileIsMapped; +extern struct MODULE *CTSdb; + +static void make_path(char *out, size_t out_len, const char *dir, const char *name) +{ + snprintf(out, out_len, "%s/%s", dir, name); +} + +int main() +{ + char tmpdir[] = "/tmp/camshr-sqlite-backend-XXXXXX"; + char sqlite_path[1024]; + char line[MODULE_ENTRY + 1]; + struct Module_ mod; + int idx; + + BEGIN_TESTING(CamShrSqliteBackendRoundtrip); + + TEST1(mkdtemp(tmpdir) != 0); + TEST1(setenv(DB_DIR, tmpdir, 1) == 0); + + CTSdbFileIsMapped = FALSE; + TEST1(map_data_file(CTS_DB) == SUCCESS); + TEST1(get_file_count(CTS_DB) == 0); + + snprintf(line, sizeof(line), "%-32s %-10s %-40s\n", "ALPHA01", "GKA100:N01", + "sqlite backend"); + line[MODULE_ENTRY - 1] = '\n'; + + TEST1(add_entry(CTS_DB, line) == SUCCESS); + TEST1(get_file_count(CTS_DB) == 1); + + idx = lookup_entry(CTS_DB, "ALPHA01"); + TEST1(idx >= 0); + memset(&mod, 0, sizeof(mod)); + parse_cts_db(CTSdb + idx, &mod); + TEST0(strcmp(mod.name, "ALPHA01")); + TEST1(mod.adapter == 0); + TEST1(mod.id == 1); + TEST1(mod.crate == 0); + TEST1(mod.slot == 1); + + CTSdbFileIsMapped = FALSE; + TEST1(map_data_file(CTS_DB) == SUCCESS); + TEST1(get_file_count(CTS_DB) == 1); + TEST1(lookup_entry(CTS_DB, "ALPHA01") >= 0); + + TEST1(remove_entry(CTS_DB, 0) == SUCCESS); + TEST1(get_file_count(CTS_DB) == 0); + + unsetenv(DB_DIR); + make_path(sqlite_path, sizeof(sqlite_path), tmpdir, "camac.db"); + unlink(sqlite_path); + rmdir(tmpdir); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/camshr_sqlite_migration_test.c b/camshr/testing/camshr_sqlite_migration_test.c new file mode 100644 index 0000000000..d3ad7f7a4f --- /dev/null +++ b/camshr/testing/camshr_sqlite_migration_test.c @@ -0,0 +1,118 @@ +#include "testing.h" + +#include "../camac_db_sqlite.h" +#include "../common.h" +#include "../crate.h" +#include "../module.h" + +#include +#include +#include +#include +#include + +static void make_path(char *out, size_t out_len, const char *dir, const char *name) +{ + snprintf(out, out_len, "%s/%s", dir, name); +} + +static int write_record(const char *path, const char *rec, size_t rec_size) +{ + FILE *fp = fopen(path, "wb"); + if (!fp) + return ERROR; + if (fwrite(rec, 1, rec_size, fp) != rec_size) + { + fclose(fp); + return ERROR; + } + fclose(fp); + return SUCCESS; +} + +int main() +{ + sqlite3 *db = 0; + char tmpdir[] = "/tmp/camshr-sqlite-migration-XXXXXX"; + char cts_path[1024]; + char crate_path[1024]; + char sqlite_path[1024]; + char cts_rec[MODULE_ENTRY]; + char crate_rec[CRATE_ENTRY]; + int cts_count = -1; + int crate_count = -1; + sqlite3_stmt *stmt = 0; + + BEGIN_TESTING(CamShrSqliteMigration); + + TEST1(mkdtemp(tmpdir) != 0); + + make_path(cts_path, sizeof(cts_path), tmpdir, CTS_DB_FILE); + make_path(crate_path, sizeof(crate_path), tmpdir, CRATE_DB_FILE); + make_path(sqlite_path, sizeof(sqlite_path), tmpdir, "camac.db"); + + memset(cts_rec, ' ', sizeof(cts_rec)); + snprintf(cts_rec, sizeof(cts_rec), "%-32s %-10s %-40s\n", "ALPHA01", + "GKA100:N01", "First migration record"); + { + size_t i; + for (i = 0; i < sizeof(cts_rec); ++i) + if (cts_rec[i] == '\0') + cts_rec[i] = ' '; + } + cts_rec[sizeof(cts_rec) - 1] = '\n'; + + memset(crate_rec, ' ', sizeof(crate_rec)); + snprintf(crate_rec, sizeof(crate_rec), "%-.6s:%3s:%c:%c:%c\n", "GKA100", + "001", '2', '1', '1'); + { + size_t i; + for (i = 0; i < sizeof(crate_rec); ++i) + if (crate_rec[i] == '\0') + crate_rec[i] = ' '; + } + crate_rec[sizeof(crate_rec) - 1] = '\n'; + + TEST1(write_record(cts_path, cts_rec, sizeof(cts_rec)) == SUCCESS); + TEST1(write_record(crate_path, crate_rec, sizeof(crate_rec)) == SUCCESS); + + TEST1(camac_db_sqlite_open(sqlite_path, &db) == SUCCESS); + TEST1(camac_db_sqlite_init(db) == SUCCESS); + TEST1(camac_db_sqlite_import_legacy(db, tmpdir) == SUCCESS); + + TEST1(camac_db_sqlite_table_count(db, "cts_modules", &cts_count) == SUCCESS); + TEST1(cts_count == 1); + TEST1(camac_db_sqlite_table_count(db, "crate_map", &crate_count) == SUCCESS); + TEST1(crate_count == 1); + + TEST1(sqlite3_prepare_v2( + db, "SELECT logical_name,crate,slot FROM cts_modules", -1, &stmt, + 0) == SQLITE_OK); + TEST1(sqlite3_step(stmt) == SQLITE_ROW); + TEST0(strcmp((const char *)sqlite3_column_text(stmt, 0), "ALPHA01")); + TEST1(sqlite3_column_int(stmt, 1) == 0); + TEST1(sqlite3_column_int(stmt, 2) == 1); + sqlite3_finalize(stmt); + stmt = 0; + + TEST1(sqlite3_prepare_v2( + db, "SELECT crate_name,device_num,enhanced,online FROM crate_map", + -1, &stmt, 0) == SQLITE_OK); + TEST1(sqlite3_step(stmt) == SQLITE_ROW); + TEST0(strcmp((const char *)sqlite3_column_text(stmt, 0), "GKA100")); + TEST1(sqlite3_column_int(stmt, 1) == 1); + TEST1(sqlite3_column_int(stmt, 2) == 1); + TEST1(sqlite3_column_int(stmt, 3) == 1); + sqlite3_finalize(stmt); + stmt = 0; + + if (db) + sqlite3_close(db); + unlink(sqlite_path); + unlink(cts_path); + unlink(crate_path); + rmdir(tmpdir); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/camshr_sqlite_schema_test.c b/camshr/testing/camshr_sqlite_schema_test.c new file mode 100644 index 0000000000..373c8787f3 --- /dev/null +++ b/camshr/testing/camshr_sqlite_schema_test.c @@ -0,0 +1,29 @@ +#include "testing.h" + +#include "../camac_db_sqlite.h" +#include "../common.h" + +#include +#include + +int main() +{ + sqlite3 *db = 0; + int cts_count = -1; + int crate_count = -1; + + BEGIN_TESTING(CamShrSqliteSchema); + + TEST1(camac_db_sqlite_open(":memory:", &db) == SUCCESS); + TEST1(camac_db_sqlite_init(db) == SUCCESS); + TEST1(camac_db_sqlite_table_count(db, "cts_modules", &cts_count) == SUCCESS); + TEST1(cts_count == 0); + TEST1(camac_db_sqlite_table_count(db, "crate_map", &crate_count) == SUCCESS); + TEST1(crate_count == 0); + + if (db) + sqlite3_close(db); + + END_TESTING; + return 0; +} diff --git a/camshr/testing/fixtures/proc_scsi_scsi.txt b/camshr/testing/fixtures/proc_scsi_scsi.txt new file mode 100644 index 0000000000..23b54c76f1 --- /dev/null +++ b/camshr/testing/fixtures/proc_scsi_scsi.txt @@ -0,0 +1,4 @@ +Attached devices: +Host: scsi0 Channel: 00 Id: 1 Lun: 00 + Vendor: KINSYSCO Model: 2145 Rev: 12 + Type: Processor ANSI SCSI revision: 02 diff --git a/camshr/turn_crate_on_off_line.c b/camshr/turn_crate_on_off_line.c index 512108d4c6..fcbba1863e 100644 --- a/camshr/turn_crate_on_off_line.c +++ b/camshr/turn_crate_on_off_line.c @@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "camac_hw_iface.h" #include "common.h" #include "crate.h" #include "prototypes.h" @@ -99,21 +100,21 @@ int turn_crate_on_off_line(char *crate_name, int state) if (CRATEdb[idx].HwyType != ('0' + JORWAY_73A)) { SCCdata = 1; // initiates Dataway Z - status = CamPiow(pController, // serial crate controller name - 0, // A --\__ write status register - 17, // F --/ - &SCCdata, // data value - 16, // mem == 16-bit data - &iosb // *iosb + status = camac_hw_cam_piow(pController, // serial crate controller name + 0, // A --\__ write status register + 17, // F --/ + &SCCdata, // data value + 16, // mem == 16-bit data + &iosb // *iosb ); SCCdata = (state == ON) ? 0 : 0x1000; // clear status register - status = CamPiow(pController, // serial crate controller name - 0, // A --\__ write status register - 17, // F --/ - &SCCdata, // data value - 16, // mem == 16-bit data - &iosb // *iosb + status = camac_hw_cam_piow(pController, // serial crate controller name + 0, // A --\__ write status register + 17, // F --/ + &SCCdata, // data value + 16, // mem == 16-bit data + &iosb // *iosb ); if (STATUS_OK) { @@ -133,6 +134,9 @@ int turn_crate_on_off_line(char *crate_name, int state) status = 1; } + if (STATUS_OK) + commit_entry(CRATE_DB); + //----------------------------------------------------------- TurnCrateOnOffLine_Exit: if (MSGLVL(DETAILS)) diff --git a/camshr/verbs.c b/camshr/verbs.c index d0f82da06e..6ad34635bd 100644 --- a/camshr/verbs.c +++ b/camshr/verbs.c @@ -77,6 +77,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "common.h" +#include "camac_db_backend.h" #include "cts_p.h" #include "prototypes.h" @@ -118,6 +119,9 @@ EXPORT int Assign(void *ctx, char **error, char *output __attribute__((unused))) { char line[MODULE_ENTRY + 1]; + char crate_name[CRATE_NAME_SIZE + 1]; + char phy_adapter_ch; + int phy_adapter, phy_id, phy_crate, phy_slot; int dbFileSize, fd, nullMask, numOfEntries; size_t i; int status = SUCCESS; // assume the best @@ -131,6 +135,16 @@ EXPORT int Assign(void *ctx, char **error, cli_get_value(ctx, "LOG_NAME", &log_name); str_upcase(log_name); cli_get_value(ctx, "COMMENT", &comment); + sprintf(crate_name, "%.6s", phy_name); + if (sscanf(phy_name, "GK%c%1d%2d:N%d", &phy_adapter_ch, &phy_id, &phy_crate, + &phy_slot) != 4) + { + *error = malloc(strlen(phy_name) + 100); + sprintf(*error, "Error: invalid physical name '%s'\n", phy_name); + status = FAILURE; + goto Assign_Exit; + } + phy_adapter = phy_adapter_ch - 'A'; // check to see if db file exists if (check_for_file(CTS_DB_FILE) != SUCCESS) @@ -156,6 +170,24 @@ EXPORT int Assign(void *ctx, char **error, goto Assign_Exit; } } + if (CRATEdbFileIsMapped == FALSE) + { // is not, so try + if (map_data_file(CRATE_DB) != SUCCESS) + { + *error = strdup("Error: problem mapping crate db file\n"); + status = FAILURE; + goto Assign_Exit; + } + } + if (lookup_entry(CRATE_DB, crate_name) < 0) + { + *error = malloc(strlen(crate_name) + 120); + sprintf(*error, + "Error: crate '%s' not defined in crate db; use ADDCRATE first\n", + crate_name); + status = FAILURE; + goto Assign_Exit; + } // get current db file count if ((numOfEntries = get_file_count(CTS_DB)) < 0) { @@ -176,6 +208,22 @@ EXPORT int Assign(void *ctx, char **error, status = FAILURE; // DUPLICATE; [2001.07.12] goto Assign_Exit; } + + for (i = 0; i < (size_t)numOfEntries; ++i) + { + struct Module_ mod; + parse_cts_db(CTSdb + i, &mod); + if (mod.adapter == phy_adapter && mod.id == phy_id && + mod.crate == phy_crate && mod.slot == phy_slot) + { + *error = malloc(strlen(phy_name) + strlen(mod.name) + 120); + sprintf(*error, + "Error: physical module '%s' already assigned to '%s'\n", + phy_name, mod.name); + status = FAILURE; + goto Assign_Exit; + } + } } // get db file size if ((dbFileSize = get_db_file_size(CTS_DB_FILE)) == ERROR) @@ -256,10 +304,9 @@ EXPORT int Autoconfig(void *ctx __attribute__((unused)), char **error, char **output __attribute__((unused))) { char highway_name[CRATE_NAME_SIZE + 1], *pHighwayName; - char line[CRATE_ENTRY]; int i, numOfEntries; int status = SUCCESS; // optimistic - FILE *fp; + FILE *fp = 0; int j; @@ -279,23 +326,16 @@ EXPORT int Autoconfig(void *ctx __attribute__((unused)), char **error, status = FILE_ERROR; goto AutoConfig_Exit; // we're done :< } - // open file for read-only - if ((fp = Fopen(CRATE_DB_FILE, "r")) == NULL) - { - *error = strdup("Error: crate.db does not exist\n"); - - status = FILE_ERROR; - goto AutoConfig_Exit; - } - pHighwayName = highway_name; // point to real memory ... - // loop thru list - for (i = 0; i < numOfEntries; ++i) + if (camac_db_backend_enabled()) { - if (fscanf(fp, "%s", line) == 1) - { // get a crate.db entry - sprintf(pHighwayName, "%.6s", line); // trim it + struct Crate_ Cr8; + // loop thru list + for (i = 0; i < numOfEntries; ++i) + { + parse_crate_db(CRATEdb + i, &Cr8); + sprintf(pHighwayName, "%.6s", Cr8.name); // trim it // NB! this is a work-around -- seems necessary for the moment for (j = 0; j < 2; j++) @@ -311,9 +351,45 @@ EXPORT int Autoconfig(void *ctx __attribute__((unused)), char **error, } } } - // end of for()... + else + { + char line[CRATE_ENTRY]; + // open file for read-only + if ((fp = Fopen(CRATE_DB_FILE, "r")) == NULL) + { + *error = strdup("Error: crate.db does not exist\n"); + + status = FILE_ERROR; + goto AutoConfig_Exit; + } + + // loop thru list + for (i = 0; i < numOfEntries; ++i) + { + if (fscanf(fp, "%s", line) == 1) + { // get a crate.db entry + sprintf(pHighwayName, "%.6s", line); // trim it + + // NB! this is a work-around -- seems necessary for the moment + for (j = 0; j < 2; j++) + { + if (map_scsi_device(pHighwayName) != SUCCESS) + { // map it if possible + *error = malloc(strlen(pHighwayName) + 100); + sprintf(*error, "Error: problem mapping scsi device '%s'\n", + pHighwayName); + status = FILE_ERROR; + goto AutoConfig_Exit; + } + } + } + } + // end of for()... + } AutoConfig_Exit: + if (fp) + fclose(fp); status = SUCCESS; return status; @@ -488,21 +564,16 @@ EXPORT int SetCrate(void *ctx, char **error, EXPORT int ShowCrate(void *ctx, char **error, char **output) { char colorENH[9], colorON[9]; - int enhanced, i, online, moduleFound, numOfCrates, numOfModules; + int enhanced, i, online, numOfCrates; int crateStatus; + int scsi_up; int status; struct Crate_ Cr8, *pCr8; char *wild = 0; struct descriptor wild_d = {0, DTYPE_T, CLASS_S, 0}; struct descriptor crate_d = {0, DTYPE_T, CLASS_S, 0}; - if (ScsiSystemStatus() == 0) - { - status = SUCCESS; // this is the function's status - *output = malloc(100); - sprintf(*output, "scsi system is %sdown!%s\n", RED, NORMAL); - goto ShowCrate_Exit; - } + scsi_up = ScsiSystemStatus(); // user input cli_get_value(ctx, "MODULE", &wild); @@ -521,100 +592,91 @@ EXPORT int ShowCrate(void *ctx, char **error, char **output) goto ShowCrate_Exit; } } - // check to see if module db file memory mapped - if (CTSdbFileIsMapped == FALSE) - { // is not, so try - if (map_data_file(CTS_DB) != SUCCESS) - { // we're dead in the water - *error = strdup("Error: error memory mapping cts.db file\n"); - - status = FAILURE; // MAP_ERROR; [2001.07.12] - goto ShowCrate_Exit; - } - } *output = strdup(" CRATE ONL LAM PRV ENH\n======= === === === ===\n"); + if (!scsi_up) + { + *output = realloc(*output, strlen(*output) + 120); + sprintf(*output + strlen(*output), + "scsi system is %sdown%s, showing cached db status\n", RED, NORMAL); + } pCr8 = &Cr8; // point to some actual storage // get number of crates in db file - if ((numOfCrates = get_file_count(CRATE_DB)) > - 0) + if ((numOfCrates = get_file_count(CRATE_DB)) > 0) { // possibly something to show - if ((numOfModules = get_file_count(CTS_DB)) > - 0) - { // maybe some crates controllers .. - for (i = 0; i < numOfCrates; i++) + for (i = 0; i < numOfCrates; i++) + { + parse_crate_db(CRATEdb + i, pCr8); + crate_d.length = strlen(pCr8->name); + crate_d.pointer = pCr8->name; + if (StrMatchWild(&crate_d, &wild_d) & 1) { - parse_crate_db(CRATEdb + i, pCr8); - crate_d.length = strlen(pCr8->name); - crate_d.pointer = pCr8->name; - if (StrMatchWild(&crate_d, &wild_d) & 1) + if (scsi_up) { - moduleFound = TRUE; - if (moduleFound) + crateStatus = 0; + status = get_crate_status(pCr8->name, &crateStatus); + if (status == SUCCESS) { - crateStatus = 0; - status = get_crate_status(pCr8->name, &crateStatus); - if (status == SUCCESS) - { - // online = - // !(crateStatus - // & - // 0x3c00) - // ? TRUE - // : FALSE; - // // - // [2002.12.09] - // online = - // !(crateStatus - // & - // 0x1000) - // ? TRUE - // : FALSE; - // // - // [2002.12.09] - online = ((crateStatus & 0x1000) != 0x1000) + // online = + // !(crateStatus + // & + // 0x3c00) + // ? TRUE + // : FALSE; + // // + // [2002.12.09] + // online = + // !(crateStatus + // & + // 0x1000) + // ? TRUE + // : FALSE; + // // + // [2002.12.09] + online = ((crateStatus & 0x1000) != 0x1000) + ? TRUE + : FALSE; // [2002.12.09] + if (!crateStatus || + crateStatus == + 0x3) // [2001.09.10] // [2002.12.09] + online = FALSE; // [2002.12.09] + + // enhanced + // = + // (online + // && + // (crateStatus + // & + // 0x4030)) + // ? TRUE + // : FALSE; + // // + // [2002.12.09] + enhanced = (online && (crateStatus & 0x4000)) ? TRUE : FALSE; // [2002.12.09] - if (!crateStatus || - crateStatus == - 0x3) // [2001.09.10] // [2002.12.09] - online = FALSE; // [2002.12.09] - sprintf(colorON, "%s", (online) ? GREEN : RED); - - // enhanced - // = - // (online - // && - // (crateStatus - // & - // 0x4030)) - // ? TRUE - // : FALSE; - // // - // [2002.12.09] - enhanced = (online && (crateStatus & 0x4000)) - ? TRUE - : FALSE; // [2002.12.09] - sprintf(colorENH, "%s", (enhanced) ? GREEN : RED); - *output = - realloc(*output, strlen(*output) + strlen(pCr8->name) + 100); - sprintf(*output + strlen(*output), - "%s: %s%c%s . . %s%c%s\n", pCr8->name, colorON, - (online) ? '*' : 'X', NORMAL, colorENH, - (enhanced) ? '*' : '-', NORMAL); - } - } // end of if(moduleFound) ... + } else { - *output = - realloc(*output, strlen(*output) + strlen(pCr8->name) + 100); - sprintf(*output + strlen(*output), "%.6s: . . . .\n", - pCr8->name); + online = pCr8->online; + enhanced = pCr8->enhanced; } - } // end of if(wildcard) ... - } // end of for(crates) ... - } // crates, but no modules (ie no controllers) + } + else + { + online = pCr8->online; + enhanced = pCr8->enhanced; + } + sprintf(colorON, "%s", (online) ? GREEN : RED); + sprintf(colorENH, "%s", (enhanced) ? GREEN : RED); + *output = realloc(*output, strlen(*output) + strlen(pCr8->name) + 100); + sprintf(*output + strlen(*output), + "%s: %s%c%s . . %s%c%s\n", pCr8->name, colorON, + (online) ? '*' : 'X', NORMAL, colorENH, + (enhanced) ? '*' : '-', NORMAL); + } // end of if(wildcard) ... + } // end of for(crates) ... } *output = realloc(*output, strlen(*output) + 100); sprintf(*output + strlen(*output), "======= === === === ===\n"); // header diff --git a/tditest/testing/CMakeLists.txt b/tditest/testing/CMakeLists.txt index a5ca6c163c..5930b1cf80 100644 --- a/tditest/testing/CMakeLists.txt +++ b/tditest/testing/CMakeLists.txt @@ -32,4 +32,14 @@ foreach(_test_script IN LISTS _test_script_list) NO_WINE ) + if(_target STREQUAL "test-dev-py") + # do_tditests.sh exits 77 when MitDevices is not available in the runtime + # library path; mark that outcome as skipped, not failed. + set_tests_properties( + "tditest/testing/${_target}" + PROPERTIES + SKIP_RETURN_CODE 77 + ) + endif() + endforeach()