diff --git a/modules/libcom/src/osi/os/Darwin/osdgetexec.c b/modules/libcom/src/osi/os/Darwin/osdgetexec.c new file mode 100644 index 000000000..4e4961c59 --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdgetexec.c @@ -0,0 +1,50 @@ + +#include +#include + +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + uint32_t max = 64u; + char *ret = NULL; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + /* cf. "man 3 dyld" */ + if(_NSGetExecutablePath(ret, &max)==0) { + /* max left unchanged */ + ret[max-1] = '\0'; + break; + } + /* max has been updated with required size */ + } + + /* TODO: _NSGetExecutablePath() doesn't follow symlinks */ + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/Linux/osdgetexec.c b/modules/libcom/src/osi/os/Linux/osdgetexec.c index 2ea8ca4ae..cba5d78a8 100644 --- a/modules/libcom/src/osi/os/Linux/osdgetexec.c +++ b/modules/libcom/src/osi/os/Linux/osdgetexec.c @@ -24,7 +24,11 @@ char *epicsGetExecName(void) ret = temp; n = readlink("/proc/self/exe", ret, max); - if(n < max) { + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { /* readlink() never adds a nil */ ret[n] = '\0'; break; diff --git a/modules/libcom/src/osi/os/WIN32/osdgetexec.c b/modules/libcom/src/osi/os/WIN32/osdgetexec.c new file mode 100644 index 000000000..a46ce50cd --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdgetexec.c @@ -0,0 +1,52 @@ + +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = 128; + char *ret = NULL; + DWORD n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = GetModuleFileName(NULL, ret, max); + if(n == 0) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + ret[n] = '\0'; + break; + } + + max += 64; + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '\\'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/freebsd/osdgetexec.c b/modules/libcom/src/osi/os/freebsd/osdgetexec.c new file mode 100644 index 000000000..39c0a163d --- /dev/null +++ b/modules/libcom/src/osi/os/freebsd/osdgetexec.c @@ -0,0 +1,68 @@ + +#include +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = PATH_MAX; + char *ret = NULL; + ssize_t n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = readlink("/proc/curproc/file", ret, max); + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + /* readlink() never adds a nil */ + ret[n] = '\0'; + break; + } + + max += 64; + } + + if(!ret) { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + ret = malloc(max); + if(ret) { + sysctl(mib, 4, ret, &cb, NULL, 0); + /* TODO: error check */ + } + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/solaris/osdgetexec.c b/modules/libcom/src/osi/os/solaris/osdgetexec.c new file mode 100644 index 000000000..ff9739ca9 --- /dev/null +++ b/modules/libcom/src/osi/os/solaris/osdgetexec.c @@ -0,0 +1,30 @@ + +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + const char *raw = getexecname(); + char *ret = NULL; + /* manpage says getexecname() might return a relative path. we treat this as an error */ + if(raw[0]=='/') { + ret = strdup(raw); + } + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 1c26c44b7..7e1ff1abc 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -232,6 +232,11 @@ osiSockTest_SRCS += osiSockTest.c testHarness_SRCS += osiSockTest.c TESTS += osiSockTest +TESTPROD_HOST += testexecname +testexecname_SRCS += testexecname.c +# no point in including in testHarness. Not implemented for RTEMS/vxWorks. +TESTS += testexecname + ifeq ($(BUILD_CLASS),HOST) ifneq ($(OS_CLASS),WIN32) # This test can only be run on a build host, and is broken on Windows diff --git a/modules/libcom/test/testexecname.c b/modules/libcom/test/testexecname.c new file mode 100644 index 000000000..87be847a0 --- /dev/null +++ b/modules/libcom/test/testexecname.c @@ -0,0 +1,24 @@ + +#include + +#include +#include + +#include + +MAIN(testexecname) +{ + testPlan(1); + + { + char *buf = epicsGetExecName(); + if(!buf) { + testSkip(1, "epicsGetExecName() not available for this target"); + } else { + char *loc = strstr(buf, "testexecname"); + testOk(!!loc, "Find \"testexecname\" in \"%s\"", buf); + } + } + + return testDone(); +}