From 5f43a8986ca59b11b9424411f2fe232b1a7bef8b Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Mon, 7 Jul 2025 10:30:30 -0700 Subject: [PATCH 1/6] add new iocsh function addReccasterExcludePattern --- client/castApp/src/Makefile | 5 + client/castApp/src/caster.c | 5 + client/castApp/src/caster.h | 11 ++ client/castApp/src/castinit.c | 69 ++++++++ client/castApp/src/dbcb.c | 9 ++ client/castApp/src/testAddExcludePattern.c | 173 +++++++++++++++++++++ client/iocBoot/iocdemo/st.cmd | 3 + 7 files changed, 275 insertions(+) create mode 100644 client/castApp/src/testAddExcludePattern.c diff --git a/client/castApp/src/Makefile b/client/castApp/src/Makefile index 8d95a8e..0cb31e8 100644 --- a/client/castApp/src/Makefile +++ b/client/castApp/src/Makefile @@ -48,6 +48,11 @@ testAddEnvVars_SRCS += testAddEnvVars.c testAddEnvVars_SYS_LIBS_WIN32 = ws2_32 TESTS += testAddEnvVars +TESTPROD_HOST += testAddExcludePattern +testAddExcludePattern_SRCS += testAddExcludePattern.c +testAddExcludePattern_SYS_LIBS_WIN32 = ws2_32 +TESTS += testAddExcludePattern + TESTSCRIPTS_HOST += $(TESTS:%=%.t) ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) TESTPROD = $(TESTPROD_HOST) diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index 7ae2cea..b838797 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -114,6 +114,7 @@ void casterInit(caster_t *self) self->onmsg = &casterShowMsgDefault; self->current = casterStateInit; self->timeout = reccastTimeout; + ellInit(&self->exclude_patterns); if(shSocketPair(self->wakeup)) errlogPrintf("Error: casterInit failed to create shutdown socket: %d\n", SOCKERRNO); @@ -142,6 +143,10 @@ void casterShutdown(caster_t *self) free(self->extra_envs); epicsMutexUnlock(self->lock); + epicsMutexMustLock(self->lock); + ellFree(&self->exclude_patterns); + epicsMutexUnlock(self->lock); + epicsEventDestroy(self->shutdownEvent); self->shutdownEvent = NULL; if (self->wakeup[0] != INVALID_SOCKET) { diff --git a/client/castApp/src/caster.h b/client/castApp/src/caster.h index a4172df..4199f6d 100644 --- a/client/castApp/src/caster.h +++ b/client/castApp/src/caster.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "sockhelpers.h" @@ -35,6 +36,11 @@ typedef enum { casterStateDone, } casterState; +typedef struct { + ELLNODE node; + char *item_str; +} string_list_t; + typedef struct _caster_t { double timeout; @@ -71,6 +77,8 @@ typedef struct _caster_t { char **extra_envs; int num_extra_envs; + ELLLIST exclude_patterns; + } caster_t; epicsShareFunc @@ -101,6 +109,9 @@ int casterPushPDB(void *junk, caster_t *caster); epicsShareFunc void addReccasterEnvVars(caster_t* self, int argc, char **argv); +epicsShareFunc +void addReccasterExcludePattern(caster_t* self, int argc, char **argv); + /* internal */ epicsShareFunc diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 4efe4e7..0b268ca 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -200,6 +200,74 @@ static void addReccasterEnvVarsCallFunc(const iocshArgBuf *args) addReccasterEnvVars(&thecaster, args[0].aval.ac, args[0].aval.av); } +void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { + // size_t i; + argv++; argc--; /* skip function arg */ + if (argc < 1) { + errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterExcludePattern\n"); + return; + } + epicsMutexMustLock(self->lock); + if (self->shutdown) { + /* shutdown in progress, silent no-op */ + epicsMutexUnlock(self->lock); + return; + } + /* error if called after iocInit() */ + if (self->current != casterStateInit) { + errlogSevPrintf(errlogMinor, "addReccasterExcludePattern called after iocInit() when reccaster might already be connected. Not supported\n"); + epicsMutexUnlock(self->lock); + return; + } + + for (int i = 0; i < argc; i++) { + if (argv[i][0] == '\0') { + errlogSevPrintf(errlogMajor, "Arg is empty for addReccasterExcludePattern\n"); + continue; + } + /* check duplicates */ + int dup = 0; + ELLNODE *cur = ellFirst(&self->exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + if (strcmp(argv[i], temp->item_str) == 0) { + dup = 1; + break; + } + cur = ellNext(cur); + } + if (dup) { + errlogSevPrintf(errlogMinor, "Duplicate pattern %s in addReccasterExcludePattern\n", argv[i]); + continue; + } + string_list_t *new = malloc(sizeof(string_list_t)); + if (new == NULL) { + errlogSevPrintf(errlogMajor, "Error in addReccasterExcludePattern - malloc error for creating linked list node"); + break; + } + new->item_str = strdup(argv[i]); + if (new->item_str == NULL) { + errlogSevPrintf(errlogMajor, "Error in addReccasterExcludePattern - strdup error for copying %s to new->item_str from addReccasterExcludePattern\n", argv[i]); + free(new); /* frees if strdup fails */ + break; + } + ellAdd(&self->exclude_patterns, &new->node); + } + epicsMutexUnlock(self->lock); +} + +static const iocshArg addReccasterExcludePatternArg0 = { "excludePattern", iocshArgArgv }; +static const iocshArg * const addReccasterExcludePatternArgs[] = { &addReccasterExcludePatternArg0 }; +static const iocshFuncDef addReccasterExcludePatternFuncDef = { + "addReccasterExcludePattern", + 1, + addReccasterExcludePatternArgs +}; + +static void addReccasterExcludePatternCallFunc(const iocshArgBuf *args) { + addReccasterExcludePattern(&thecaster, args[0].aval.ac, args[0].aval.av); +} + static void reccasterRegistrar(void) { osiSockAttach(); @@ -210,6 +278,7 @@ static void reccasterRegistrar(void) thepriv.laststate=casterStateInit; strcpy(thepriv.lastmsg, "Initializing"); iocshRegister(&addReccasterEnvVarsFuncDef,addReccasterEnvVarsCallFunc); + iocshRegister(&addReccasterExcludePatternFuncDef,addReccasterExcludePatternCallFunc); } static long init_record(void* prec) diff --git a/client/castApp/src/dbcb.c b/client/castApp/src/dbcb.c index 4d9cc04..4f6a846 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -87,12 +87,21 @@ static int pushRecord(caster_t *caster, DBENTRY *pent) { dbCommon *prec = pent->precnode->precord; ssize_t rid; + ELLNODE *cur; int ret = 0; long status; if(dbIsAlias(pent)) return 0; + cur = ellFirst(&caster->exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + if(epicsStrGlobMatch(prec->name, temp->item_str)) + return 0; + cur = ellNext(cur); + } + rid = casterSendRecord(caster, prec->rdes->name, prec->name); if(rid<=0) return rid; diff --git a/client/castApp/src/testAddExcludePattern.c b/client/castApp/src/testAddExcludePattern.c new file mode 100644 index 0000000..8f0a9d6 --- /dev/null +++ b/client/castApp/src/testAddExcludePattern.c @@ -0,0 +1,173 @@ +#include + +#include +#include + +#include "caster.h" + +void* epicsRtemsFSImage; + +static void testLog(void* arg, struct _caster_t* self) +{ + testDiag("ERR %s", self->lastmsg); +} + +static void testAddExcludePatternX(void) +{ + int i = 0; + caster_t caster; + casterInit(&caster); + caster.onmsg = &testLog; + + int argc; + char *argvlist[5]; + argvlist[0] = "addReccasterExcludePattern"; + + char *expectedPatterns[] = + { + "*_", + "*__", + "*:Intrnl:*", + "*_internal", + "*exclude_me" + }; + int expectedNumPatterns = 0; + + testDiag("Testing addReccasterExcludePattern with one good env"); + argvlist[1] = "*_"; + argc = 2; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + expectedNumPatterns++; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + ELLNODE *cur; + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + testDiag("Testing addReccasterExcludePattern with two more patterns"); + argvlist[1] = "*__"; + argvlist[2] = "*:Intrnl:*"; + argc = 3; + i = 0; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + expectedNumPatterns += 2; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + testDiag("Testing addReccasterExcludePattern with a duplicate pattern"); + argvlist[1] = "*_"; + argc = 2; + i = 0; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + testDiag("Testing addReccasterExcludePattern with a new and a duplicate"); + argvlist[1] = "*_internal"; + argvlist[2] = "*__"; + argc = 3; + i = 0; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + expectedNumPatterns++; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + testDiag("Testing addReccasterExcludePattern with two of the same pattern"); + argvlist[1] = "*exclude_me"; + argvlist[2] = "*exclude_me"; + argc = 3; + i = 0; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + expectedNumPatterns++; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + testDiag("Testing addReccasterExcludePattern with duplicates in argv and exclude pattern list"); + argvlist[1] = "*__"; + argvlist[2] = "*__"; + argc = 3; + i = 0; + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + addReccasterExcludePattern(&caster, argc, argvlist); + testOk1(caster.exclude_patterns.count==expectedNumPatterns); + cur = ellFirst(&caster.exclude_patterns); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedPatterns[i]) == 0); + i++; + cur = ellNext(cur); + } + + epicsEventSignal(caster.shutdownEvent); + casterShutdown(&caster); +} + +static void testAddExcludePatternBadInput() +{ + caster_t caster; + casterInit(&caster); + caster.onmsg = &testLog; + + int argc; + char *argvlist[2]; + argvlist[0] = "addReccasterExcludePattern"; + + testDiag("Testing addReccasterExcludePattern with no arguments"); + argc = 1; + testOk1(caster.exclude_patterns.count==0); + addReccasterExcludePattern(&caster, argc, argvlist); + testOk1(caster.exclude_patterns.count==0); + + testDiag("Testing addReccasterExcludePattern with empty string argument"); + argvlist[1] = ""; + argc = 2; + testOk1(caster.exclude_patterns.count==0); + addReccasterExcludePattern(&caster, argc, argvlist); + testOk1(caster.exclude_patterns.count==0); + + epicsEventSignal(caster.shutdownEvent); + casterShutdown(&caster); +} + +MAIN(testAddExcludePattern) +{ + testPlan(37); + osiSockAttach(); + testAddExcludePatternX(); + testAddExcludePatternBadInput(); + osiSockRelease(); + return testDone(); +} diff --git a/client/iocBoot/iocdemo/st.cmd b/client/iocBoot/iocdemo/st.cmd index fe81b08..35c72fa 100755 --- a/client/iocBoot/iocdemo/st.cmd +++ b/client/iocBoot/iocdemo/st.cmd @@ -23,6 +23,9 @@ epicsEnvSet("SECTOR", "mysector") addReccasterEnvVars("CONTACT", "SECTOR") addReccasterEnvVars("BUILDING") +addReccasterExcludePattern("*_", "*__") +addReccasterExcludePattern("*exclude_this") + ## Load record instances dbLoadRecords("../../db/reccaster.db", "P=$(IOCSH_NAME):") dbLoadRecords("../../db/somerecords.db","P=$(IOCSH_NAME):") From f93c0cf4579ba9693fb223e97c1e6849bc047d03 Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Wed, 10 Sep 2025 17:34:04 -0700 Subject: [PATCH 2/6] naming change --- client/castApp/src/castinit.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 0b268ca..406d2fe 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -222,7 +222,7 @@ void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { for (int i = 0; i < argc; i++) { if (argv[i][0] == '\0') { - errlogSevPrintf(errlogMajor, "Arg is empty for addReccasterExcludePattern\n"); + errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterExcludePattern\n"); continue; } /* check duplicates */ @@ -240,18 +240,18 @@ void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { errlogSevPrintf(errlogMinor, "Duplicate pattern %s in addReccasterExcludePattern\n", argv[i]); continue; } - string_list_t *new = malloc(sizeof(string_list_t)); - if (new == NULL) { + string_list_t *new_list = malloc(sizeof(string_list_t)); + if (new_list == NULL) { errlogSevPrintf(errlogMajor, "Error in addReccasterExcludePattern - malloc error for creating linked list node"); break; } - new->item_str = strdup(argv[i]); - if (new->item_str == NULL) { + new_list->item_str = strdup(argv[i]); + if (new_list->item_str == NULL) { errlogSevPrintf(errlogMajor, "Error in addReccasterExcludePattern - strdup error for copying %s to new->item_str from addReccasterExcludePattern\n", argv[i]); - free(new); /* frees if strdup fails */ + free(new_list); /* frees if strdup fails */ break; } - ellAdd(&self->exclude_patterns, &new->node); + ellAdd(&self->exclude_patterns, &new_list->node); } epicsMutexUnlock(self->lock); } From 925515dbfdd9627bedb436125d1f605aee50c4eb Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Thu, 11 Sep 2025 11:07:46 -0700 Subject: [PATCH 3/6] fixed strdup memory leak --- client/castApp/src/caster.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index b838797..c470956 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -120,6 +120,12 @@ void casterInit(caster_t *self) errlogPrintf("Error: casterInit failed to create shutdown socket: %d\n", SOCKERRNO); } +static void nodeFree(void *node) { + string_list_t *temp = (string_list_t *)node; + free(temp->item_str); + free(temp); +} + void casterShutdown(caster_t *self) { int i; @@ -144,7 +150,7 @@ void casterShutdown(caster_t *self) epicsMutexUnlock(self->lock); epicsMutexMustLock(self->lock); - ellFree(&self->exclude_patterns); + ellFree2(&self->exclude_patterns, &nodeFree); epicsMutexUnlock(self->lock); epicsEventDestroy(self->shutdownEvent); From 5836a6d3ce6632f5ed350532e72af790e8e19c60 Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Thu, 11 Sep 2025 12:17:50 -0700 Subject: [PATCH 4/6] fixed loop to be compatible with C89 --- client/castApp/src/castinit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 406d2fe..1014257 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -201,7 +201,7 @@ static void addReccasterEnvVarsCallFunc(const iocshArgBuf *args) } void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { - // size_t i; + size_t i; argv++; argc--; /* skip function arg */ if (argc < 1) { errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterExcludePattern\n"); @@ -220,7 +220,7 @@ void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { return; } - for (int i = 0; i < argc; i++) { + for (i = 0; i < argc; i++) { if (argv[i][0] == '\0') { errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterExcludePattern\n"); continue; From e87e20fe0d5877d1b06a6f2f65bba45990e4252c Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Fri, 12 Sep 2025 10:59:57 -0700 Subject: [PATCH 5/6] switched addReccasterEnvVars to linked list implementation --- client/castApp/src/caster.c | 7 +- client/castApp/src/caster.h | 3 +- client/castApp/src/castinit.c | 116 ++++++++++------------------ client/castApp/src/dbcb.c | 9 ++- client/castApp/src/testAddEnvVars.c | 116 +++++++++++++++------------- 5 files changed, 110 insertions(+), 141 deletions(-) diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index c470956..15da501 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -114,6 +114,7 @@ void casterInit(caster_t *self) self->onmsg = &casterShowMsgDefault; self->current = casterStateInit; self->timeout = reccastTimeout; + ellInit(&self->extra_envs); ellInit(&self->exclude_patterns); if(shSocketPair(self->wakeup)) @@ -128,7 +129,6 @@ static void nodeFree(void *node) { void casterShutdown(caster_t *self) { - int i; epicsUInt32 junk = htonl(0xdeadbeef); epicsMutexMustLock(self->lock); @@ -143,10 +143,7 @@ void casterShutdown(caster_t *self) epicsEventMustWait(self->shutdownEvent); epicsMutexMustLock(self->lock); - for (i = 0; i < self->num_extra_envs; i++) { - free(self->extra_envs[i]); - } - free(self->extra_envs); + ellFree2(&self->extra_envs, &nodeFree); epicsMutexUnlock(self->lock); epicsMutexMustLock(self->lock); diff --git a/client/castApp/src/caster.h b/client/castApp/src/caster.h index 4199f6d..659ff92 100644 --- a/client/castApp/src/caster.h +++ b/client/castApp/src/caster.h @@ -74,8 +74,7 @@ typedef struct _caster_t { int shutdown; char lastmsg[MAX_STRING_SIZE]; - char **extra_envs; - int num_extra_envs; + ELLLIST extra_envs; ELLLIST exclude_patterns; diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 1014257..9326b5e 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -74,7 +74,6 @@ static void casthook(initHookState state) void addReccasterEnvVars(caster_t* self, int argc, char **argv) { size_t i, j; - int ret = 0; argv++; argc--; /* skip function arg */ if(argc < 1) { @@ -95,91 +94,54 @@ void addReccasterEnvVars(caster_t* self, int argc, char **argv) epicsMutexUnlock(self->lock); return; } - int new_extra_envs_size = self->num_extra_envs + argc; - int num_new_extra_envs = self->num_extra_envs; - char **new_extra_envs = calloc(new_extra_envs_size, sizeof(*new_extra_envs)); - if(new_extra_envs == NULL) { - errlogSevPrintf(errlogMajor, "Error in memory allocation of new_extra_envs from addReccasterEnvVars\n"); - epicsMutexUnlock(self->lock); - return; - } - /* copy self->extra_envs into new_extra_envs with room for new envs */ - for(i=0; i < self->num_extra_envs; i++) { - if((new_extra_envs[i] = strdup(self->extra_envs[i])) == NULL) { - errlogSevPrintf(errlogMinor, "strdup error for copying %s to new_extra_envs[%zu] from addReccasterEnvVars\n", self->extra_envs[i], i); - ret = 1; - break; - } - } int found_dup; /* sanitize input - check for dups and empty args */ - if(!ret) { - for(i=0; i < argc; i++) { - if(argv[i] == NULL) { - errlogSevPrintf(errlogMinor, "Arg is NULL for addReccasterEnvVars\n"); - continue; - } - else if(argv[i][0] == '\0') { - errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterEnvVars\n"); - continue; - } - found_dup = 0; - /* check if dup in self->default_envs */ - for(j = 0; default_envs[j]; j++) { - if(strcmp(argv[i], default_envs[j]) == 0) { - found_dup = 1; - errlogSevPrintf(errlogMinor, "Env var %s is already in env list sent by reccaster by default\n", argv[i]); - break; - } - } - if(found_dup) { - continue; - } - /* check if dup in self->extra_envs */ - for(j = 0; j < num_new_extra_envs; j++) { - if(new_extra_envs[j] == NULL) { - continue; - } - if(strcmp(argv[i], new_extra_envs[j]) == 0) { - found_dup = 1; - errlogSevPrintf(errlogMinor, "Env var %s is already in extra_envs list\n", argv[i]); - break; - } - } - if(found_dup) { - continue; + for(i=0; i < argc; i++) { + if(argv[i][0] == '\0') { + errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterEnvVars\n"); + continue; + } + found_dup = 0; + /* check if dup in self->default_envs */ + for(j = 0; default_envs[j]; j++) { + if(strcmp(argv[i], default_envs[j]) == 0) { + found_dup = 1; + break; } - if((new_extra_envs[num_new_extra_envs] = strdup(argv[i])) == NULL) { - errlogSevPrintf(errlogMinor, "strdup error for copying %s to new_extra_envs[%d] from addReccasterEnvVars\n", argv[i], num_new_extra_envs); - ret = 1; + } + if(found_dup) { + errlogSevPrintf(errlogMinor, "Env var %s is already in env list sent by reccaster by default\n", argv[i]); + continue; + } + /* check if dup in self->extra_envs */ + ELLNODE *cur = ellFirst(&self->extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + if (strcmp(argv[i], temp->item_str) == 0) { + found_dup = 1; break; } - /* this is a valid arg and we have added the new env var to our array, increment new_extra_envs count */ - num_new_extra_envs++; + cur = ellNext(cur); } + if(found_dup) { + errlogSevPrintf(errlogMinor, "Env var %s is already in extra_envs list\n", argv[i]); + continue; + } + string_list_t *new_list = malloc(sizeof(string_list_t)); + if (new_list == NULL) { + errlogSevPrintf(errlogMajor, "Error in addReccasterEnvVars - malloc error for creating linked list node"); + break; + } + new_list->item_str = strdup(argv[i]); + if (new_list->item_str == NULL) { + errlogSevPrintf(errlogMajor, "Error in addReccasterEnvVars - strdup error for copying %s to new->item_str from addReccasterEnvVars\n", argv[i]); + free(new_list); /* frees if strdup fails */ + break; + } + ellAdd(&self->extra_envs, &new_list->node); } - /* if we have no allocation issues and have at least one new env var that is valid, add to self->extra_envs */ - if(!ret && num_new_extra_envs > self->num_extra_envs) { - /* from this point, nothing can fail */ - char ** tmp; - tmp = self->extra_envs; /* swap pointers so we can clean up new_extra_envs on success/failure */ - self->extra_envs = new_extra_envs; - new_extra_envs = tmp; - - new_extra_envs_size = self->num_extra_envs; /* with swap of pointers also swap size */ - self->num_extra_envs = num_new_extra_envs; - } - /* cleanup new_extra_envs[] on success or failure */ - for(i = 0; i < new_extra_envs_size; i++) { - free(new_extra_envs[i]); - } - free(new_extra_envs); epicsMutexUnlock(self->lock); - - if(ret) { - errlogSevPrintf(errlogMajor, "Error in addReccasterEnvVars - reccaster might not send the extra env vars specified\n"); - } } static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar", iocshArgArgv }; diff --git a/client/castApp/src/dbcb.c b/client/castApp/src/dbcb.c index 4f6a846..3fb9ee1 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -71,12 +71,13 @@ static int pushEnv(caster_t *caster) } epicsMutexMustLock(caster->lock); - for (i = 0; !ret && i < caster->num_extra_envs; i++) { - const char *val = getenv(caster->extra_envs[i]); + for (i = 0; !ret && i < caster->extra_envs.count; i++) { + string_list_t *envptr = (string_list_t *)ellNth(&caster->extra_envs, i); + const char *val = getenv(envptr->item_str); if (val && val[0] != '\0') - ret = casterSendInfo(caster, 0, caster->extra_envs[i], val); + ret = casterSendInfo(caster, 0, envptr->item_str, val); if (ret) - casterMsg(caster, "Error sending env %s", caster->extra_envs[i]); + casterMsg(caster, "Error sending env %s", envptr->item_str); } epicsMutexUnlock(caster->lock); diff --git a/client/castApp/src/testAddEnvVars.c b/client/castApp/src/testAddEnvVars.c index fb81f12..93ed22d 100644 --- a/client/castApp/src/testAddEnvVars.c +++ b/client/castApp/src/testAddEnvVars.c @@ -14,7 +14,7 @@ static void testLog(void* arg, struct _caster_t* self) static void testAddEnvVarsX(void) { - int i; + int i = 0; caster_t caster; casterInit(&caster); caster.onmsg = &testLog; @@ -29,7 +29,6 @@ static void testAddEnvVarsX(void) "BUILDING", "CONTACT", "DEVICE", - "Field", "FAMILY" }; int expectedNumExtraEnvs = 0; @@ -37,71 +36,84 @@ static void testAddEnvVarsX(void) testDiag("Testing addReccasterEnvVars with one good env"); argvlist[1] = "SECTOR"; argc = 2; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + ELLNODE *cur; + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } testDiag("Testing addReccasterEnvVars with two more good envs"); argvlist[1] = "BUILDING"; argvlist[2] = "CONTACT"; argc = 3; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs += 2; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } testDiag("Testing addReccasterEnvVars with duplicate env"); argvlist[1] = "SECTOR"; argc = 2; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } testDiag("Testing addReccasterEnvVars with one dup and one good env"); argvlist[1] = "CONTACT"; argvlist[2] = "DEVICE"; argc = 3; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); - } - - testDiag("Testing addReccasterEnvVars with NULL argument and then a good env"); - argvlist[1] = NULL; - argvlist[2] = "Field"; - argc = 3; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - addReccasterEnvVars(&caster, argc, argvlist); - expectedNumExtraEnvs++; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } testDiag("Testing addReccasterEnvVars with a good env and a dup of that env"); - argvlist[1] = NULL; + argvlist[1] = "FAMILY"; argvlist[2] = "FAMILY"; - argvlist[3] = "FAMILY"; - argc = 4; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + argc = 3; + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } testDiag("Testing addReccasterEnvVars with a env vars from default list"); @@ -111,11 +123,16 @@ static void testAddEnvVarsX(void) argvlist[4] = "RSRV_SERVER_PORT"; argvlist[5] = "ENGINEER"; argc = 6; - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); + i = 0; + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.num_extra_envs==expectedNumExtraEnvs); - for(i=0; i < expectedNumExtraEnvs; i++) { - testOk1(strcmp(caster.extra_envs[i], expectedExtraEnvs[i]) == 0); + testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.extra_envs); + while (cur != NULL) { + string_list_t *temp = (string_list_t *)cur; + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + i++; + cur = ellNext(cur); } epicsEventSignal(caster.shutdownEvent); @@ -134,23 +151,16 @@ static void testAddEnvVarsBadInput(void) testDiag("Testing addReccasterEnvVars with no arguments"); argc = 1; - testOk1(caster.num_extra_envs==0); + testOk1(caster.extra_envs.count==0); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.num_extra_envs==0); + testOk1(caster.extra_envs.count==0); testDiag("Testing addReccasterEnvVars with empty string argument"); argvlist[1] = ""; argc = 2; - testOk1(caster.num_extra_envs==0); - addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.num_extra_envs==0); - - testDiag("Testing addReccasterEnvVars with NULL argument"); - argvlist[1] = NULL; - argc = 2; - testOk1(caster.num_extra_envs==0); + testOk1(caster.extra_envs.count==0); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.num_extra_envs==0); + testOk1(caster.extra_envs.count==0); epicsEventSignal(caster.shutdownEvent); casterShutdown(&caster); @@ -158,7 +168,7 @@ static void testAddEnvVarsBadInput(void) MAIN(testAddEnvVars) { - testPlan(48); + testPlan(37); osiSockAttach(); testAddEnvVarsX(); testAddEnvVarsBadInput(); From 9bc594a09f4b2dcd9a97c75a5271f132729dc675 Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Fri, 12 Sep 2025 17:09:00 -0700 Subject: [PATCH 6/6] fixed segfault in dbcb --- client/castApp/src/dbcb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/castApp/src/dbcb.c b/client/castApp/src/dbcb.c index 3fb9ee1..e68239e 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -71,13 +71,15 @@ static int pushEnv(caster_t *caster) } epicsMutexMustLock(caster->lock); - for (i = 0; !ret && i < caster->extra_envs.count; i++) { - string_list_t *envptr = (string_list_t *)ellNth(&caster->extra_envs, i); - const char *val = getenv(envptr->item_str); + ELLNODE *env = ellFirst(&caster->extra_envs); + while (!ret && env != NULL) { + string_list_t *temp = (string_list_t *)env; + const char *val = getenv(temp->item_str); if (val && val[0] != '\0') - ret = casterSendInfo(caster, 0, envptr->item_str, val); + ret = casterSendInfo(caster, 0, temp->item_str, val); if (ret) - casterMsg(caster, "Error sending env %s", envptr->item_str); + casterMsg(caster, "Error sending env %s", temp->item_str); + env = ellNext(env); } epicsMutexUnlock(caster->lock);