From dbb8530d035ef0012045f3f94090df5ba5da36c3 Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Fri, 12 Sep 2025 10:59:57 -0700 Subject: [PATCH 1/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 b838797a..a21023ec 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)) @@ -122,7 +123,6 @@ void casterInit(caster_t *self) void casterShutdown(caster_t *self) { - int i; epicsUInt32 junk = htonl(0xdeadbeef); epicsMutexMustLock(self->lock); @@ -137,10 +137,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 4199f6db..659ff92f 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 bd601bed..0135fe50 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -82,7 +82,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) { @@ -103,91 +102,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 7559e19b..a4417846 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -72,12 +72,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 fb81f12d..93ed22d8 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 ec912a78c4652fd027475695c38ab9760f817bce Mon Sep 17 00:00:00 2001 From: Madeline Park Date: Fri, 12 Sep 2025 17:09:00 -0700 Subject: [PATCH 2/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 a4417846..0091634d 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -72,13 +72,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); From d978011a1f534c4b226c04349cc0fa329af860ab Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 2 Oct 2025 14:57:30 -0700 Subject: [PATCH 3/6] update addReccasterEnvVars to combine memory allocation and simplify loops --- client/castApp/src/caster.c | 5 +--- client/castApp/src/castinit.c | 51 +++++++++++++++++------------------ client/castApp/src/dbcb.c | 13 +++++---- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index a21023ec..24f1900a 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -137,10 +137,7 @@ void casterShutdown(caster_t *self) epicsEventMustWait(self->shutdownEvent); epicsMutexMustLock(self->lock); - ellFree2(&self->extra_envs, &nodeFree); - epicsMutexUnlock(self->lock); - - epicsMutexMustLock(self->lock); + ellFree(&self->extra_envs); ellFree(&self->exclude_patterns); epicsMutexUnlock(self->lock); diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 0135fe50..46b84e36 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -82,7 +82,8 @@ static void casthook(initHookState state) void addReccasterEnvVars(caster_t* self, int argc, char **argv) { size_t i, j; - + int dup; + ELLNODE *cur; argv++; argc--; /* skip function arg */ if(argc < 1) { errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterEnvVars\n"); @@ -103,52 +104,44 @@ void addReccasterEnvVars(caster_t* self, int argc, char **argv) return; } - int found_dup; /* sanitize input - check for dups and empty args */ - for(i=0; i < argc; i++) { + for (i = 0; i < argc; i++) { + const size_t arg_len = strlen(argv[i]) + 1; if(argv[i][0] == '\0') { errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterEnvVars\n"); continue; } - found_dup = 0; + 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; + dup = 1; break; } } - if(found_dup) { + if(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; + for(cur = ellFirst(&self->extra_envs); cur; cur = ellNext(cur)) { + const string_list_t *penvvar = CONTAINER(cur, string_list_t, node); + if (strcmp(argv[i], penvvar->item_str) == 0) { + dup = 1; break; } - cur = ellNext(cur); } - if(found_dup) { + if(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); + string_list_t *new_node = mallocMustSucceed(sizeof(string_list_t) + arg_len, "addReccasterEnvVars"); + new_node->item_str = (char *)(new_node + 1); + memcpy(new_node->item_str, argv[i], arg_len); + + ellAdd(&self->extra_envs, &new_node->node); } + epicsMutexUnlock(self->lock); } @@ -226,7 +219,13 @@ static const iocshArg * const addReccasterExcludePatternArgs[] = { &addReccaster static const iocshFuncDef addReccasterExcludePatternFuncDef = { "addReccasterExcludePattern", 1, - addReccasterExcludePatternArgs + addReccasterExcludePatternArgs, +#ifdef IOCSHFUNCDEF_HAS_USAGE + "By default, reccaster will send all PVs on IOC startup.\n" + "This function allows you to exclude PVs by specifying patterns to exclude.\n" + "Must be called before iocInit\n" + "Example: addReccasterExcludePattern 'TEST:*' '*_'\n" +#endif }; static void addReccasterExcludePatternCallFunc(const iocshArgBuf *args) { diff --git a/client/castApp/src/dbcb.c b/client/castApp/src/dbcb.c index 0091634d..557b5225 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -47,6 +47,7 @@ const char* default_envs[] = static int pushEnv(caster_t *caster) { size_t i; + ELLNODE *cur; int ret = 0; if(!getenv("HOSTNAME")) { @@ -72,15 +73,13 @@ static int pushEnv(caster_t *caster) } epicsMutexMustLock(caster->lock); - 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); + for(cur = ellFirst(&caster->extra_envs); !ret && cur; cur = ellNext(cur)) { + const string_list_t *penvvar = CONTAINER(cur, string_list_t, node); + const char *val = getenv(penvvar->item_str); if (val && val[0] != '\0') - ret = casterSendInfo(caster, 0, temp->item_str, val); + ret = casterSendInfo(caster, 0, penvvar->item_str, val); if (ret) - casterMsg(caster, "Error sending env %s", temp->item_str); - env = ellNext(env); + casterMsg(caster, "Error sending env %s", penvvar->item_str); } epicsMutexUnlock(caster->lock); From e93ca6ed0949eb7b0e034e4d07b5353f7194bff2 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Mon, 6 Oct 2025 12:13:26 -0700 Subject: [PATCH 4/6] Create helper function to handle both addReccasterExcludePattern and addReccasterEnvVars --- client/castApp/src/castinit.c | 123 ++++++++++++---------------------- 1 file changed, 44 insertions(+), 79 deletions(-) diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 46b84e36..532e8b15 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -75,21 +75,21 @@ static void casthook(initHookState state) epicsAtExit(&castexit, NULL); } -/* - Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING") - Appends the given env variables to the extra_envs list to be sent in addition to the default_envs array -*/ -void addReccasterEnvVars(caster_t* self, int argc, char **argv) +/* Helper function to add items from iocsh calls to internal linked lists + * funcName is the name of the IOC shell function being called (for error messages) + * itemDesc is string to describe what is being added (for error messages) + * defaultArray is an optional arg for a default list to also check for duplicates + */ +static void addToReccasterLinkedList(caster_t* self, int argc, char **argv, ELLLIST* list, const char* funcName, const char* itemDesc, const char** defaultArray) { size_t i, j; int dup; ELLNODE *cur; argv++; argc--; /* skip function arg */ if(argc < 1) { - errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterEnvVars\n"); + errlogSevPrintf(errlogMinor, "At least one argument expected for %s\n", funcName); return; } - epicsMutexMustLock(self->lock); if(self->shutdown) { /* shutdown in progress, silent no-op */ @@ -98,8 +98,8 @@ void addReccasterEnvVars(caster_t* self, int argc, char **argv) } else if(self->current != casterStateInit) { /* Attempt to add after iocInit(), when we may be connected. - To fully support, would need to force reconnect or resend w/ updated envs list. */ - errlogSevPrintf(errlogMinor, "addReccasterEnvVars called after iocInit() when reccaster might already be connected. Not supported\n"); + To fully support, would need to force reconnect or resend w/ updated list. */ + errlogSevPrintf(errlogMinor, "%s called after iocInit() when reccaster might already be connected. Not supported\n", funcName); epicsMutexUnlock(self->lock); return; } @@ -108,43 +108,60 @@ void addReccasterEnvVars(caster_t* self, int argc, char **argv) for (i = 0; i < argc; i++) { const size_t arg_len = strlen(argv[i]) + 1; if(argv[i][0] == '\0') { - errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterEnvVars\n"); + errlogSevPrintf(errlogMinor, "Arg is empty for %s\n", funcName); continue; } dup = 0; - /* check if dup in self->default_envs */ - for(j = 0; default_envs[j]; j++) { - if(strcmp(argv[i], default_envs[j]) == 0) { - dup = 1; - break; + /* if the defaultArray arg is used, check if this is a duplicate */ + if (defaultArray) { + for(j = 0; defaultArray[j]; j++) { + if(strcmp(argv[i], defaultArray[j]) == 0) { + dup = 1; + break; + } + } + if(dup) { + errlogSevPrintf(errlogMinor, "Item %s is already in list sent by reccaster by default\n", argv[i]); + continue; } } - if(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 */ - for(cur = ellFirst(&self->extra_envs); cur; cur = ellNext(cur)) { - const string_list_t *penvvar = CONTAINER(cur, string_list_t, node); - if (strcmp(argv[i], penvvar->item_str) == 0) { + /* check if dup in existing linked list */ + for(cur = ellFirst(list); cur; cur = ellNext(cur)) { + string_list_t *pitem = CONTAINER(cur, string_list_t, node); + if (strcmp(argv[i], pitem->item_str) == 0) { dup = 1; break; } } if(dup) { - errlogSevPrintf(errlogMinor, "Env var %s is already in extra_envs list\n", argv[i]); + errlogSevPrintf(errlogMinor, "%s %s already in list for %s\n", itemDesc, argv[i], funcName); continue; } - string_list_t *new_node = mallocMustSucceed(sizeof(string_list_t) + arg_len, "addReccasterEnvVars"); + string_list_t *new_node = mallocMustSucceed(sizeof(string_list_t) + arg_len, funcName); new_node->item_str = (char *)(new_node + 1); memcpy(new_node->item_str, argv[i], arg_len); - ellAdd(&self->extra_envs, &new_node->node); + ellAdd(list, &new_node->node); } - epicsMutexUnlock(self->lock); } +/* Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING") + * Appends the given env variables to the extra_envs list to be sent in addition to the default_envs array + */ +void addReccasterEnvVars(caster_t* self, int argc, char **argv) +{ + addToReccasterLinkedList(self, argc, argv, &self->extra_envs, "addReccasterEnvVars", "Environment variable", (const char**)default_envs); +} + +/* Example call: addReccasterExcludePattern("TEST:*") or addReccasterExcludePattern("TEST:*", "*_") + * Appends the given patterns to the exclude_patterns list so those PVs and their meta-data are not sent + */ +void addReccasterExcludePattern(caster_t* self, int argc, char **argv) +{ + addToReccasterLinkedList(self, argc, argv, &self->exclude_patterns, "addReccasterExcludePattern", "Exclude pattern", NULL); +} + static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar", iocshArgArgv }; static const iocshArg * const addReccasterEnvVarsArgs[] = { &addReccasterEnvVarsArg0 }; static const iocshFuncDef addReccasterEnvVarsFuncDef = { @@ -163,57 +180,6 @@ 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; - int dup; - ELLNODE *cur; - 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 (i = 0; i < argc; i++) { - const size_t arg_len = strlen(argv[i]) + 1; - if (argv[i][0] == '\0') { - errlogSevPrintf(errlogMinor, "Arg is empty for addReccasterExcludePattern\n"); - continue; - } - /* check duplicates */ - dup = 0; - for(cur = ellFirst(&self->exclude_patterns); cur; cur = ellNext(cur)) { - const string_list_t *ppattern = CONTAINER(cur, string_list_t, node); - if (strcmp(argv[i], ppattern->item_str) == 0) { - dup = 1; - break; - } - } - if (dup) { - errlogSevPrintf(errlogMinor, "Duplicate pattern %s in addReccasterExcludePattern\n", argv[i]); - continue; - } - string_list_t *new_node = mallocMustSucceed(sizeof(string_list_t) + arg_len, "addReccasterExcludePattern"); - new_node->item_str = (char *)(new_node + 1); - memcpy(new_node->item_str, argv[i], arg_len); - - ellAdd(&self->exclude_patterns, &new_node->node); - } - - epicsMutexUnlock(self->lock); -} - static const iocshArg addReccasterExcludePatternArg0 = { "excludePattern", iocshArgArgv }; static const iocshArg * const addReccasterExcludePatternArgs[] = { &addReccasterExcludePatternArg0 }; static const iocshFuncDef addReccasterExcludePatternFuncDef = { @@ -227,7 +193,6 @@ static const iocshFuncDef addReccasterExcludePatternFuncDef = { "Example: addReccasterExcludePattern 'TEST:*' '*_'\n" #endif }; - static void addReccasterExcludePatternCallFunc(const iocshArgBuf *args) { addReccasterExcludePattern(&thecaster, args[0].aval.ac, args[0].aval.av); } From 02d926aa30eacec2c761d26bb159ac4b05b718e2 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Tue, 14 Oct 2025 11:08:49 -0700 Subject: [PATCH 5/6] Combine default_envs and extra_envs into one linked list for addReccasterEnvVars --- client/castApp/src/Makefile | 1 + client/castApp/src/caster.c | 8 +- client/castApp/src/caster.h | 7 +- client/castApp/src/castinit.c | 60 ++++++------ client/castApp/src/dbcb.c | 13 +-- client/castApp/src/testAddEnvVars.c | 101 ++++++++++++++------- client/castApp/src/testAddExcludePattern.c | 2 +- 7 files changed, 113 insertions(+), 79 deletions(-) diff --git a/client/castApp/src/Makefile b/client/castApp/src/Makefile index 0cb31e89..5ecc4316 100644 --- a/client/castApp/src/Makefile +++ b/client/castApp/src/Makefile @@ -45,6 +45,7 @@ TESTS += testtcp TESTPROD_HOST += testAddEnvVars testAddEnvVars_SRCS += testAddEnvVars.c +testAddEnvVars_SRCS += dbcb.c testAddEnvVars_SYS_LIBS_WIN32 = ws2_32 TESTS += testAddEnvVars diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index 24f1900a..63624685 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -7,6 +7,7 @@ #include #include #include +#include #define epicsExportSharedSymbols @@ -114,9 +115,12 @@ void casterInit(caster_t *self) self->onmsg = &casterShowMsgDefault; self->current = casterStateInit; self->timeout = reccastTimeout; - ellInit(&self->extra_envs); + ellInit(&self->envs); ellInit(&self->exclude_patterns); + /* add default_envs to envs list which can be expanded by the user with addReccasterEnvVars iocsh function */ + addToReccasterLinkedList(self, default_envs_count, default_envs, &self->envs, "casterInit", "Default environment variable"); + if(shSocketPair(self->wakeup)) errlogPrintf("Error: casterInit failed to create shutdown socket: %d\n", SOCKERRNO); } @@ -137,7 +141,7 @@ void casterShutdown(caster_t *self) epicsEventMustWait(self->shutdownEvent); epicsMutexMustLock(self->lock); - ellFree(&self->extra_envs); + ellFree(&self->envs); ellFree(&self->exclude_patterns); epicsMutexUnlock(self->lock); diff --git a/client/castApp/src/caster.h b/client/castApp/src/caster.h index 659ff92f..092a8141 100644 --- a/client/castApp/src/caster.h +++ b/client/castApp/src/caster.h @@ -22,6 +22,7 @@ epicsShareExtern double reccastTimeout; epicsShareExtern double reccastMaxHoldoff; extern const char* default_envs[]; +extern const size_t default_envs_count; typedef enum { casterUDPSetup, @@ -74,8 +75,7 @@ typedef struct _caster_t { int shutdown; char lastmsg[MAX_STRING_SIZE]; - ELLLIST extra_envs; - + ELLLIST envs; ELLLIST exclude_patterns; } caster_t; @@ -105,6 +105,9 @@ int casterSendInfo(caster_t *c, ssize_t rid, const char* name, const char* val); epicsShareFunc int casterPushPDB(void *junk, caster_t *caster); +epicsShareFunc +void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc); + epicsShareFunc void addReccasterEnvVars(caster_t* self, int argc, char **argv); diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 532e8b15..6c12ac42 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -76,20 +76,19 @@ static void casthook(initHookState state) } /* Helper function to add items from iocsh calls to internal linked lists + * self is the caster instance + * itemCount is the number of items in the items array + * items is the array of strings to add to the list + * reccastList is the linked list to add the items to * funcName is the name of the IOC shell function being called (for error messages) * itemDesc is string to describe what is being added (for error messages) - * defaultArray is an optional arg for a default list to also check for duplicates */ -static void addToReccasterLinkedList(caster_t* self, int argc, char **argv, ELLLIST* list, const char* funcName, const char* itemDesc, const char** defaultArray) +void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc) { - size_t i, j; + size_t i; int dup; ELLNODE *cur; - argv++; argc--; /* skip function arg */ - if(argc < 1) { - errlogSevPrintf(errlogMinor, "At least one argument expected for %s\n", funcName); - return; - } + epicsMutexMustLock(self->lock); if(self->shutdown) { /* shutdown in progress, silent no-op */ @@ -105,53 +104,45 @@ static void addToReccasterLinkedList(caster_t* self, int argc, char **argv, ELLL } /* sanitize input - check for dups and empty args */ - for (i = 0; i < argc; i++) { - const size_t arg_len = strlen(argv[i]) + 1; - if(argv[i][0] == '\0') { + for (i = 0; i < itemCount; i++) { + const size_t arg_len = strlen(items[i]) + 1; + if(items[i][0] == '\0') { errlogSevPrintf(errlogMinor, "Arg is empty for %s\n", funcName); continue; } dup = 0; - /* if the defaultArray arg is used, check if this is a duplicate */ - if (defaultArray) { - for(j = 0; defaultArray[j]; j++) { - if(strcmp(argv[i], defaultArray[j]) == 0) { - dup = 1; - break; - } - } - if(dup) { - errlogSevPrintf(errlogMinor, "Item %s is already in list sent by reccaster by default\n", argv[i]); - continue; - } - } /* check if dup in existing linked list */ - for(cur = ellFirst(list); cur; cur = ellNext(cur)) { + for(cur = ellFirst(reccastList); cur; cur = ellNext(cur)) { string_list_t *pitem = CONTAINER(cur, string_list_t, node); - if (strcmp(argv[i], pitem->item_str) == 0) { + if (strcmp(items[i], pitem->item_str) == 0) { dup = 1; break; } } if(dup) { - errlogSevPrintf(errlogMinor, "%s %s already in list for %s\n", itemDesc, argv[i], funcName); + errlogSevPrintf(errlogMinor, "%s %s already in list for %s\n", itemDesc, items[i], funcName); continue; } string_list_t *new_node = mallocMustSucceed(sizeof(string_list_t) + arg_len, funcName); new_node->item_str = (char *)(new_node + 1); - memcpy(new_node->item_str, argv[i], arg_len); + memcpy(new_node->item_str, items[i], arg_len); - ellAdd(list, &new_node->node); + ellAdd(reccastList, &new_node->node); } epicsMutexUnlock(self->lock); } /* Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING") - * Appends the given env variables to the extra_envs list to be sent in addition to the default_envs array + * Appends the given env variables to the envs list to be sent. This includes some hard-coded env vars sent by default */ void addReccasterEnvVars(caster_t* self, int argc, char **argv) { - addToReccasterLinkedList(self, argc, argv, &self->extra_envs, "addReccasterEnvVars", "Environment variable", (const char**)default_envs); + argv++; argc--; /* skip function arg */ + if(argc < 1) { + errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterEnvVars\n"); + return; + } + addToReccasterLinkedList(self, argc, (const char **)argv, &self->envs, "addReccasterEnvVars", "Environment variable"); } /* Example call: addReccasterExcludePattern("TEST:*") or addReccasterExcludePattern("TEST:*", "*_") @@ -159,7 +150,12 @@ void addReccasterEnvVars(caster_t* self, int argc, char **argv) */ void addReccasterExcludePattern(caster_t* self, int argc, char **argv) { - addToReccasterLinkedList(self, argc, argv, &self->exclude_patterns, "addReccasterExcludePattern", "Exclude pattern", NULL); + argv++; argc--; /* skip function arg */ + if(argc < 1) { + errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterExcludePattern\n"); + return; + } + addToReccasterLinkedList(self, argc, (const char **)argv, &self->exclude_patterns, "addReccasterExcludePattern", "Exclude pattern"); } static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar", iocshArgArgv }; diff --git a/client/castApp/src/dbcb.c b/client/castApp/src/dbcb.c index 557b5225..7ede0862 100644 --- a/client/castApp/src/dbcb.c +++ b/client/castApp/src/dbcb.c @@ -35,7 +35,6 @@ const char* default_envs[] = "PWD", "EPICS_HOST_ARCH", "IOCNAME", - "HOSTNAME", /* iocStats */ "ENGINEER", @@ -43,10 +42,10 @@ const char* default_envs[] = NULL }; +const size_t default_envs_count = NELEMENTS(default_envs) - 1; /* exclude NULL */ static int pushEnv(caster_t *caster) { - size_t i; ELLNODE *cur; int ret = 0; @@ -64,16 +63,8 @@ static int pushEnv(caster_t *caster) if(ret) ERRRET(ret, caster, "Failed to send epics version"); - for(i=0; !ret && default_envs[i]; i++) { - const char *val = getenv(default_envs[i]); - if(val && val[0]!='\0') - ret = casterSendInfo(caster, 0, default_envs[i], val); - if(ret) - casterMsg(caster, "Error sending env %s", default_envs[i]); - } - epicsMutexMustLock(caster->lock); - for(cur = ellFirst(&caster->extra_envs); !ret && cur; cur = ellNext(cur)) { + for(cur = ellFirst(&caster->envs); !ret && cur; cur = ellNext(cur)) { const string_list_t *penvvar = CONTAINER(cur, string_list_t, node); const char *val = getenv(penvvar->item_str); if (val && val[0] != '\0') diff --git a/client/castApp/src/testAddEnvVars.c b/client/castApp/src/testAddEnvVars.c index 93ed22d8..63b25f44 100644 --- a/client/castApp/src/testAddEnvVars.c +++ b/client/castApp/src/testAddEnvVars.c @@ -31,21 +31,30 @@ static void testAddEnvVarsX(void) "DEVICE", "FAMILY" }; - int expectedNumExtraEnvs = 0; + size_t defaultEnvCount = 0; + while (default_envs[defaultEnvCount]) { + defaultEnvCount++; + } + int expectedNumExtraEnvs = defaultEnvCount; testDiag("Testing addReccasterEnvVars with one good env"); argvlist[1] = "SECTOR"; argc = 2; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); ELLNODE *cur; - cur = ellFirst(&caster.extra_envs); + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -55,14 +64,19 @@ static void testAddEnvVarsX(void) argvlist[2] = "CONTACT"; argc = 3; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs += 2; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); - cur = ellFirst(&caster.extra_envs); + testOk1(caster.envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -71,13 +85,18 @@ static void testAddEnvVarsX(void) argvlist[1] = "SECTOR"; argc = 2; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); - cur = ellFirst(&caster.extra_envs); + testOk1(caster.envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -87,14 +106,19 @@ static void testAddEnvVarsX(void) argvlist[2] = "DEVICE"; argc = 3; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); - cur = ellFirst(&caster.extra_envs); + testOk1(caster.envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -104,14 +128,19 @@ static void testAddEnvVarsX(void) argvlist[2] = "FAMILY"; argc = 3; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); expectedNumExtraEnvs++; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); - cur = ellFirst(&caster.extra_envs); + testOk1(caster.envs.count==expectedNumExtraEnvs); + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -124,13 +153,18 @@ static void testAddEnvVarsX(void) argvlist[5] = "ENGINEER"; argc = 6; i = 0; - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); + testOk1(caster.envs.count==expectedNumExtraEnvs); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.extra_envs.count==expectedNumExtraEnvs); - cur = ellFirst(&caster.extra_envs); + testOk1(caster.envs.count==expectedNumExtraEnvs); /* these are all defaults so the count should not change */ + cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i]) == 0); + if (i < defaultEnvCount) { + testOk1(strcmp(temp->item_str, default_envs[i]) == 0); + } + else { + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + } i++; cur = ellNext(cur); } @@ -145,22 +179,27 @@ static void testAddEnvVarsBadInput(void) casterInit(&caster); caster.onmsg = &testLog; + size_t defaultEnvCount = 0; + while (default_envs[defaultEnvCount]) { + defaultEnvCount++; + } + int argc; - char *argvlist[2]; + char *argvlist[3]; argvlist[0] = "addReccasterEnvVars"; testDiag("Testing addReccasterEnvVars with no arguments"); argc = 1; - testOk1(caster.extra_envs.count==0); + testOk1(caster.envs.count==defaultEnvCount); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.extra_envs.count==0); + testOk1(caster.envs.count==defaultEnvCount); testDiag("Testing addReccasterEnvVars with empty string argument"); argvlist[1] = ""; argc = 2; - testOk1(caster.extra_envs.count==0); + testOk1(caster.envs.count==defaultEnvCount); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.extra_envs.count==0); + testOk1(caster.envs.count==defaultEnvCount); epicsEventSignal(caster.shutdownEvent); casterShutdown(&caster); @@ -168,7 +207,7 @@ static void testAddEnvVarsBadInput(void) MAIN(testAddEnvVars) { - testPlan(37); + testPlan(37 + default_envs_count * 6); osiSockAttach(); testAddEnvVarsX(); testAddEnvVarsBadInput(); diff --git a/client/castApp/src/testAddExcludePattern.c b/client/castApp/src/testAddExcludePattern.c index 8f0a9d67..e55d291d 100644 --- a/client/castApp/src/testAddExcludePattern.c +++ b/client/castApp/src/testAddExcludePattern.c @@ -142,7 +142,7 @@ static void testAddExcludePatternBadInput() caster.onmsg = &testLog; int argc; - char *argvlist[2]; + char *argvlist[3]; argvlist[0] = "addReccasterExcludePattern"; testDiag("Testing addReccasterExcludePattern with no arguments"); From c7d5e9838b4e1b17daf299d689e79d7eb9bb2d44 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 20 Nov 2025 10:20:08 -0800 Subject: [PATCH 6/6] Add return code to addReccasterExcludePattern and addReccasterEnvVars iocsh funcs and some cleanup --- client/castApp/src/caster.c | 1 - client/castApp/src/caster.h | 6 +-- client/castApp/src/castinit.c | 37 +++++++++++++------ client/castApp/src/testAddEnvVars.c | 43 +++++++++------------- client/castApp/src/testAddExcludePattern.c | 2 +- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/client/castApp/src/caster.c b/client/castApp/src/caster.c index 63624685..a84395b0 100644 --- a/client/castApp/src/caster.c +++ b/client/castApp/src/caster.c @@ -7,7 +7,6 @@ #include #include #include -#include #define epicsExportSharedSymbols diff --git a/client/castApp/src/caster.h b/client/castApp/src/caster.h index 092a8141..de5b7514 100644 --- a/client/castApp/src/caster.h +++ b/client/castApp/src/caster.h @@ -106,13 +106,13 @@ epicsShareFunc int casterPushPDB(void *junk, caster_t *caster); epicsShareFunc -void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc); +int addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc); epicsShareFunc -void addReccasterEnvVars(caster_t* self, int argc, char **argv); +int addReccasterEnvVars(caster_t* self, int argc, char **argv); epicsShareFunc -void addReccasterExcludePattern(caster_t* self, int argc, char **argv); +int addReccasterExcludePattern(caster_t* self, int argc, char **argv); /* internal */ diff --git a/client/castApp/src/castinit.c b/client/castApp/src/castinit.c index 6c12ac42..9b539730 100644 --- a/client/castApp/src/castinit.c +++ b/client/castApp/src/castinit.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,16 @@ #include "caster.h" +#ifndef VERSION_INT +# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) +#endif +#ifndef EPICS_VERSION_INT +# define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) +#endif +#if EPICS_VERSION_INT < VERSION_INT(7,0,3,1) +static int iocshSetError(int err) { return err; } +#endif + static caster_t thecaster; typedef struct { @@ -83,7 +94,7 @@ static void casthook(initHookState state) * funcName is the name of the IOC shell function being called (for error messages) * itemDesc is string to describe what is being added (for error messages) */ -void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc) +int addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc) { size_t i; int dup; @@ -93,14 +104,14 @@ void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **ite if(self->shutdown) { /* shutdown in progress, silent no-op */ epicsMutexUnlock(self->lock); - return; + return 0; } else if(self->current != casterStateInit) { /* Attempt to add after iocInit(), when we may be connected. To fully support, would need to force reconnect or resend w/ updated list. */ errlogSevPrintf(errlogMinor, "%s called after iocInit() when reccaster might already be connected. Not supported\n", funcName); epicsMutexUnlock(self->lock); - return; + return -1; } /* sanitize input - check for dups and empty args */ @@ -130,32 +141,33 @@ void addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **ite ellAdd(reccastList, &new_node->node); } epicsMutexUnlock(self->lock); + return 0; } /* Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING") * Appends the given env variables to the envs list to be sent. This includes some hard-coded env vars sent by default */ -void addReccasterEnvVars(caster_t* self, int argc, char **argv) +int addReccasterEnvVars(caster_t* self, int argc, char **argv) { argv++; argc--; /* skip function arg */ if(argc < 1) { errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterEnvVars\n"); - return; + return -1; } - addToReccasterLinkedList(self, argc, (const char **)argv, &self->envs, "addReccasterEnvVars", "Environment variable"); + return addToReccasterLinkedList(self, argc, (const char **)argv, &self->envs, "addReccasterEnvVars", "Environment variable"); } /* Example call: addReccasterExcludePattern("TEST:*") or addReccasterExcludePattern("TEST:*", "*_") * Appends the given patterns to the exclude_patterns list so those PVs and their meta-data are not sent */ -void addReccasterExcludePattern(caster_t* self, int argc, char **argv) +int addReccasterExcludePattern(caster_t* self, int argc, char **argv) { argv++; argc--; /* skip function arg */ if(argc < 1) { errlogSevPrintf(errlogMinor, "At least one argument expected for addReccasterExcludePattern\n"); - return; + return -1; } - addToReccasterLinkedList(self, argc, (const char **)argv, &self->exclude_patterns, "addReccasterExcludePattern", "Exclude pattern"); + return addToReccasterLinkedList(self, argc, (const char **)argv, &self->exclude_patterns, "addReccasterExcludePattern", "Exclude pattern"); } static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar", iocshArgArgv }; @@ -173,7 +185,7 @@ static const iocshFuncDef addReccasterEnvVarsFuncDef = { }; static void addReccasterEnvVarsCallFunc(const iocshArgBuf *args) { - addReccasterEnvVars(&thecaster, args[0].aval.ac, args[0].aval.av); + iocshSetError(addReccasterEnvVars(&thecaster, args[0].aval.ac, args[0].aval.av)); } static const iocshArg addReccasterExcludePatternArg0 = { "excludePattern", iocshArgArgv }; @@ -189,8 +201,9 @@ static const iocshFuncDef addReccasterExcludePatternFuncDef = { "Example: addReccasterExcludePattern 'TEST:*' '*_'\n" #endif }; -static void addReccasterExcludePatternCallFunc(const iocshArgBuf *args) { - addReccasterExcludePattern(&thecaster, args[0].aval.ac, args[0].aval.av); +static void addReccasterExcludePatternCallFunc(const iocshArgBuf *args) +{ + iocshSetError(addReccasterExcludePattern(&thecaster, args[0].aval.ac, args[0].aval.av)); } static void reccasterRegistrar(void) diff --git a/client/castApp/src/testAddEnvVars.c b/client/castApp/src/testAddEnvVars.c index 63b25f44..696bc1ec 100644 --- a/client/castApp/src/testAddEnvVars.c +++ b/client/castApp/src/testAddEnvVars.c @@ -31,11 +31,7 @@ static void testAddEnvVarsX(void) "DEVICE", "FAMILY" }; - size_t defaultEnvCount = 0; - while (default_envs[defaultEnvCount]) { - defaultEnvCount++; - } - int expectedNumExtraEnvs = defaultEnvCount; + int expectedNumExtraEnvs = default_envs_count; testDiag("Testing addReccasterEnvVars with one good env"); argvlist[1] = "SECTOR"; @@ -49,11 +45,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -71,11 +67,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -91,11 +87,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -113,11 +109,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -135,11 +131,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -159,11 +155,11 @@ static void testAddEnvVarsX(void) cur = ellFirst(&caster.envs); while (cur != NULL) { string_list_t *temp = (string_list_t *)cur; - if (i < defaultEnvCount) { + if (i < default_envs_count) { testOk1(strcmp(temp->item_str, default_envs[i]) == 0); } else { - testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - defaultEnvCount]) == 0); + testOk1(strcmp(temp->item_str, expectedExtraEnvs[i - default_envs_count]) == 0); } i++; cur = ellNext(cur); @@ -179,27 +175,22 @@ static void testAddEnvVarsBadInput(void) casterInit(&caster); caster.onmsg = &testLog; - size_t defaultEnvCount = 0; - while (default_envs[defaultEnvCount]) { - defaultEnvCount++; - } - int argc; char *argvlist[3]; argvlist[0] = "addReccasterEnvVars"; testDiag("Testing addReccasterEnvVars with no arguments"); argc = 1; - testOk1(caster.envs.count==defaultEnvCount); + testOk1(caster.envs.count==default_envs_count); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.envs.count==defaultEnvCount); + testOk1(caster.envs.count==default_envs_count); testDiag("Testing addReccasterEnvVars with empty string argument"); argvlist[1] = ""; argc = 2; - testOk1(caster.envs.count==defaultEnvCount); + testOk1(caster.envs.count==default_envs_count); addReccasterEnvVars(&caster, argc, argvlist); - testOk1(caster.envs.count==defaultEnvCount); + testOk1(caster.envs.count==default_envs_count); epicsEventSignal(caster.shutdownEvent); casterShutdown(&caster); diff --git a/client/castApp/src/testAddExcludePattern.c b/client/castApp/src/testAddExcludePattern.c index e55d291d..8f0a9d67 100644 --- a/client/castApp/src/testAddExcludePattern.c +++ b/client/castApp/src/testAddExcludePattern.c @@ -142,7 +142,7 @@ static void testAddExcludePatternBadInput() caster.onmsg = &testLog; int argc; - char *argvlist[3]; + char *argvlist[2]; argvlist[0] = "addReccasterExcludePattern"; testDiag("Testing addReccasterExcludePattern with no arguments");