Skip to content
Snippets Groups Projects
Commit 8bcd70d2 authored by zimoch's avatar zimoch
Browse files

Merged with require version for Linux.

Should work now on all operating systems.
parent 8894a058
No related branches found
No related tags found
1 merge request!7Submodule merge
#include <vxWorks.h>
#include <symLib.h>
#include <sysSymTbl.h>
#include <sysLib.h>
#include <symLib.h>
#include <loadLib.h>
#include <shellLib.h>
#include <usrLib.h>
#include <taskLib.h>
#include <stat.h>
/*
* ld - load code dynamically
*
* $Author: zimoch $
* $ID$
* $Date: 2011/07/21 14:57:25 $
*
* DISCLAIMER: Use at your own risc and so on. No warranty, no refund.
*/
#include <sys/stat.h>
#include <stdio.h>
#include <ioLib.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <require.h>
#include <epicsVersion.h>
#ifdef BASE_VERSION
#define EPICS_3_13
int dbLoadDatabase(char *filename, char *path, char *substitutions);
extern volatile int interruptAccept;
#else
#define EPICS_3_14
#include <iocsh.h>
extern int iocshCmd (const char *cmd);
#include <dbAccess.h>
extern int iocshCmd (const char *cmd);
#include <epicsExit.h>
#include <epicsExport.h>
#endif
static int validate(char* version, char* loaded)
#include "require.h"
int requireDebug=0;
#define DIRSEP "/"
#define PATHSEP ":"
#define PREFIX
#define INFIX
#if defined (__vxworks)
#include <symLib.h>
#include <sysSymTbl.h>
#include <sysLib.h>
#include <symLib.h>
#include <loadLib.h>
#include <shellLib.h>
#include <usrLib.h>
#include <taskLib.h>
#include <ioLib.h>
#include <errno.h>
#define HMODULE MODULE_ID
#undef INFIX
#define INFIX "Lib"
#define EXT ".munch"
#elif defined (UNIX)
#include <dlfcn.h>
#define HMODULE void *
#ifdef CYGWIN32
#define EXT ".dll"
#else
#undef PREFIX
#define PREFIX "lib"
#define EXT ".so"
#endif
#elif defined (_WIN32)
#include <windows.h>
#undef DIRSEP
#define DIRSEP "\\"
#undef PATHSEP
#define PATHSEP ";"
#define EXT ".dll"
#else
#error unknwn OS
#endif
/* loadlib (library)
Find a loadable library by name and load it.
*/
static HMODULE loadlib(const char* libname)
{
HMODULE libhandle = NULL;
if (!libname)
{
fprintf (stderr, "missing library name\n");
return NULL;
}
#if defined (UNIX)
if (!(libhandle = dlopen(libname, RTLD_NOW|RTLD_GLOBAL)))
{
fprintf (stderr, "Loading %s library failed: %s\n",
libname, dlerror());
}
#elif defined (_WIN32)
if (!(libhandle = LoadLibrary(libname)))
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
fprintf (stderr, "Loading %s library failed: %s\n",
libname, lpMsgBuf);
LocalFree(lpMsgBuf);
}
#elif defined (__vxworks)
{
int fd, loaderror;
fd = open(libname, O_RDONLY, 0);
loaderror = errno;
if (fd >= 0)
{
errno = 0;
libhandle = loadModule(fd, LOAD_GLOBAL_SYMBOLS);
if (errno == S_symLib_SYMBOL_NOT_FOUND)
{
libhandle = NULL;
}
loaderror = errno;
close (fd);
}
if (libhandle == NULL)
{
fprintf(stderr, "Loading %s library failed: %s\n",
libname, strerror(loaderror));
}
}
#else
fprintf (stderr, "cannot load libraries on this OS.\n");
#endif
return libhandle;
}
typedef struct moduleitem
{
struct moduleitem* next;
char name[100];
char version[20];
} moduleitem;
moduleitem* loadedModules = NULL;
const char* getLibVersion(const char* libname)
{
moduleitem* m;
for (m = loadedModules; m; m=m->next)
{
if (strncmp(m->name, libname, sizeof(m->name)) == 0)
{
return m->version;
}
}
return NULL;
}
static int validate(const char* version, const char* loaded)
{
int lmajor, lminor, lpatch, lmatches;
int major, minor, patch, matches;
......@@ -34,14 +182,14 @@ static int validate(char* version, char* loaded)
if (!version || !*version || strcmp(loaded, version) == 0)
{
/* no version requested or exact match */
return OK;
return 0;
}
if (strcmp(loaded, "test") == 0)
{
/* test version already loaded */
printf("Warning: version is test where %s was requested\n",
version);
return OK;
return 0;
}
/* non-numerical versions must match exactly
numerical versions must have exact match in major version and
......@@ -56,44 +204,109 @@ static int validate(char* version, char* loaded)
|| (matches >= 2 && minor > lminor)
|| (matches > 2 && minor == lminor && patch > lpatch))
{
return ERROR;
return -1;
}
return OK;
return 0;
}
int require(char* lib, char* vers)
/* require (module)
Look if module is already loaded.
If module is already loaded check for version mismatch.
If module is not yet loaded load the library with ld,
load <module>.dbd with dbLoadDatabase (if file exists)
and call <module>_registerRecordDeviceDriver function.
If require is called from the iocsh before iocInit and fails,
it calls epicsExit to abort the application.
*/
#ifdef __vxworks
/* wrapper to abort statup script */
static int require_priv(const char* module, const char* ver);
int require(const char* module, const char* ver)
{
char** path;
char* loaded;
SYM_TYPE type;
struct stat filestat;
char version[20];
int fd;
MODULE_ID libhandle = NULL;
if (symFindByName(sysSymTbl, "LIB", (char**)&path, &type) != OK)
if (require_priv(module, ver) != 0 && !interruptAccept)
{
static char* here = ".";
path = &here;
/* require failed in startup script before iocInit */
fprintf(stderr, "Aborting startup script\n");
shellScriptAbort();
return -1;
}
if (!lib)
return 0;
}
#define require require_priv
static
#endif
int require(const char* module, const char* vers)
{
char* driverpath = ".";
char version[20];
const char* loaded;
moduleitem* m;
struct stat filestat;
HMODULE libhandle;
char* p;
char *end; /* end of string */
const char sep[1] = PATHSEP;
#ifdef __vxworks
SYM_TYPE type;
#endif
if (requireDebug)
printf("require: checking module %s version %s\n",
module, vers);
driverpath = getenv("EPICS_DRIVER_PATH");
if (requireDebug)
printf("require: searchpath=%s\n",
driverpath);
if (!module)
{
printf("Usage: require \"<libname>\" [, \"<version>\"]\n");
printf("Loads <libname>Lib[-<version>] and dbd/<libname>[-<version>].dbd\n");
printf("Directory is LIB = %s\n", *path);
return ERROR;
printf("Usage: require \"<module>\" [, \"<version>\"]\n");
printf("Loads " PREFIX "<module>" INFIX "[-<version>]" EXT " and dbd/<libname>[-<version>].dbd\n");
#ifdef EPICS_3_14
printf("And calls <module>_registerRecordDeviceDriver\n");
#endif
printf("Search path is %s\n", driverpath);
return -1;
}
bzero(version, sizeof(version));
if (vers) strncpy(version, vers, sizeof(version));
loaded = getLibVersion(lib);
if (!loaded)
loaded = getLibVersion(module);
if (requireDebug)
printf("require: loaded version of %s is %s\n",
module, loaded);
if (loaded)
{
/* Library already loaded. Check Version. */
if (validate(version, loaded) != 0)
{
printf("Conflict between requested %s version %s\n"
"and already loaded version %s.\n",
module, version, loaded);
return -1;
}
/* Loaded version is ok */
printf ("%s %s already loaded\n", module, loaded);
return 0;
}
else
{
char libname[256];
char dbdname[256];
char depname[256];
char libdir[256];
char fulllibname[256];
char fulldbdname[256];
char fulldepname[256];
char symbolname[256];
/* user may give a minimal version (e.g. "1.2.4+")
load highest matching version (here "1.2") and check later
*/
if (version[strlen(version)-1] == '+')
{
char* p = strrchr(version, '.');
......@@ -101,202 +314,243 @@ int require(char* lib, char* vers)
*p = 0;
}
/* try to find module in local /bin directory first, then in path
prefer *Lib.munch file over *Lib file
check for dependencies in *.dep file
load *.dbd file if it exists
*/
/* first try local library */
if (version && *version)
/* make filenames with or without version string */
if (version[0])
{
sprintf(libname, "bin/%sLib-%s.munch", lib, version);
sprintf(depname, "bin/%s-%s.dep", lib, version);
sprintf(dbdname, "dbd/%s-%s.dbd", lib, version);
sprintf(libname, PREFIX "%s" INFIX "-%s" EXT, module, version);
sprintf(depname, "%s-%s.dep", module, version);
sprintf(dbdname, "%s-%s.dbd", module, version);
}
else
{
sprintf(libname, "bin/%sLib.munch", lib);
sprintf(depname, "bin/%s.dep", lib);
sprintf(dbdname, "dbd/%s.dbd", lib);
sprintf(libname, PREFIX "%s" INFIX EXT, module);
sprintf(depname, "%s.dep", module);
sprintf(dbdname, "%s.dbd", module);
}
if (stat(libname, &filestat) == ERROR)
if (requireDebug)
{
/* no munched local lib */
libname[strlen(libname)-6]=0; /* skip ".munch" */
printf("require: libname is %s\n", libname);
printf("require: depname is %s\n", depname);
printf("require: dbdname is %s\n", dbdname);
}
if (stat(libname, &filestat) == ERROR)
{
/* no local lib at all */
libname[strlen(libname)-6]=0; /* skip ".munch" */
if (version && *version)
/* search for library in driverpath */
for (p = driverpath; p != NULL; p = end)
{
end = strchr(p, sep[0]);
if (end)
{
sprintf(libname, "%s/%sLib-%s.munch", *path, lib, version);
sprintf(depname, "%s/%s-%s.dep", *path, lib, version);
sprintf(dbdname, "%s/dbd/%s-%s.dbd", *path, lib, version);
sprintf (libdir, "%.*s", end-p, p);
end++;
}
else
{
sprintf(libname, "%s/%sLib.munch", *path, lib);
sprintf(depname, "%s/%s.dep", *path, lib);
sprintf(dbdname, "%s/dbd/%s.dbd", *path, lib);
}
if (stat(libname, &filestat) == ERROR)
{
/* no munched lib */
libname[strlen(libname)-6]=0; /* skip ".munch" */
}
if (stat(libname, &filestat) == ERROR &&
/* allow alias without library */
stat(depname, &filestat) == ERROR)
{
/* still no library found */
printf("Library %s not found\n", libname);
printf("Aborting startup stript.\n");
shellScriptAbort();
return ERROR;
sprintf (libdir, "%s", p);
}
/* ignore empty driverpath elements */
if (libdir[0] == 0) continue;
sprintf (fulllibname, "%s" DIRSEP "%s", libdir, libname);
sprintf (fulldepname, "%s" DIRSEP "%s", libdir, depname);
if (requireDebug)
printf("require: looking for %s\n", fulllibname);
if (stat(fulllibname, &filestat) == 0) break;
#ifdef __vxworks
/* now without the .munch */
fulllibname[strlen(fulllibname)-6] = 0;
if (requireDebug)
printf("require: looking for %s\n", fulllibname);
if (stat(fulllibname, &filestat) == 0) break;
#endif
/* allow dependency without library for aliasing */
if (requireDebug)
printf("require: looking for %s\n", fulldepname);
if (stat(fulldepname, &filestat) == 0) break;
}
if (requireDebug)
printf("require: found in %s\n", p);
if (!p)
{
fprintf(stderr, "Library %s not found in EPICS_DRIVER_PATH=%s\n",
libname, driverpath);
return -1;
}
errno = 0;
/* check dependencies */
if (stat(depname, &filestat) != ERROR)
/* parse dependency file if exists */
if (stat(fulldepname, &filestat) == 0)
{
FILE* depfile;
char buffer[40];
char *l; /* required library */
char *v; /* required version */
char *e; /* end */
char *rmodule; /* required module */
char *rversion; /* required version */
depfile = fopen(depname, "r");
if (requireDebug)
printf("require: parsing dependency file %s\n", fulldepname);
depfile = fopen(fulldepname, "r");
while (fgets(buffer, sizeof(buffer), depfile))
{
l = buffer;
while (isspace((int)*l)) l++;
if (*l == 0 || *l == '#') continue;
v = l;
while (*v && !isspace((int)*v)) v++;
*v++ = 0;
while (isspace((int)*v)) v++;
e = v;
while (*e && !isspace((int)*e)) e++;
*e++ = '+';
*e = 0;
printf ("%s depends on %s %s\n", lib, l, v);
if (require(l, v) != OK)
rmodule = buffer;
/* ignore leading spaces */
while (isspace((int)*rmodule)) rmodule++;
/* ignore empty lines and comment lines */
if (*rmodule == 0 || *rmodule == '#') continue;
/* rmodule at start of module name */
rversion = rmodule;
/* find end of module name */
while (*rversion && !isspace((int)*rversion)) rversion++;
/* terminate module name */
*rversion++ = 0;
/* ignore spaces */
while (isspace((int)*rversion)) rversion++;
/* rversion at start of version */
end = rversion;
/* find end of version */
while (*end && !isspace((int)*end)) end++;
/* append + to version to allow newer compaible versions */
*end++ = '+';
/* terminate version */
*end = 0;
printf("%s depends on %s %s\n", module, rmodule, rversion);
if (require(rmodule, rversion) != 0)
{
fclose(depfile);
return ERROR;
return -1;
}
}
fclose(depfile);
}
if (stat(libname, &filestat) == ERROR)
if (stat(fulllibname, &filestat) != 0)
{
/* no library, dep file was an alias */
if (requireDebug)
printf("require: no library to load\n");
return 0;
}
/* load library */
printf("Loading %s\n", libname);
fd = open(libname, O_RDONLY, 0);
if (fd >= 0)
if (requireDebug)
printf("require: loading library %s\n", fulllibname);
if (!(libhandle = loadlib(fulllibname)))
{
errno = 0;
libhandle = loadModule(fd, LOAD_GLOBAL_SYMBOLS);
close (fd);
if (requireDebug)
printf("require: loading failed\n");
return -1;
}
/* now check if we got what we wanted (with original version number) */
sprintf (symbolname, "_%sLibRelease", module);
#if defined (UNIX)
loaded = (char*) dlsym(libhandle, symbolname);
#elif defined (_WIN32)
loaded = (char*) GetProcAddress(libhandle, symbolname);
#elif defined (__vxworks)
loaded = NULL;
symFindByName(sysSymTbl, symbolname, (char**)&loaded, &type);
#endif
if (loaded)
{
printf("Loading %s (version %s)\n", fulllibname, loaded);
}
if (libhandle == NULL || errno == S_symLib_SYMBOL_NOT_FOUND)
else
{
printf("Loading %s library failed: %s\n", lib, strerror(errno));
printf("Aborting startup stript.\n");
shellScriptAbort();
return ERROR;
printf("Loading %s (no version)\n", fulllibname);
loaded = "(no version)";
}
loaded = getLibVersion(lib);
/* load dbd file */
if (stat(dbdname, &filestat) != ERROR && filestat.st_size > 0)
if (validate(vers, loaded) != 0)
{
fprintf(stderr, "Requested %s version %s not available, found only %s.\n",
module, vers, loaded);
return -1;
}
/* look for dbd in . ./dbd ../dbd ../../dbd (relative to lib dir) */
p = PATHSEP DIRSEP "dbd"
PATHSEP DIRSEP ".." DIRSEP "dbd"
PATHSEP DIRSEP ".." DIRSEP ".." DIRSEP "dbd";
while (p)
{
/* If file exists and is not empty */
printf("Loading %s\n", dbdname);
if (dbLoadDatabase(dbdname, NULL, NULL) != OK)
end = strchr(p, sep[0]);
if (end)
{
taskDelay(sysClkRateGet());
printf ("Aborting startup stript.\n");
shellScriptAbort();
return ERROR;
sprintf(fulldbdname, "%s%.*s" DIRSEP "%s",
libdir, end-p, p, dbdname);
end++;
}
#ifdef EPICS_3_14
/* call register function for R3.14 */
else
{
char initfunc[256];
sprintf (initfunc, "%s_registerRecordDeviceDriver", lib);
printf("calling %s\n", initfunc);
iocshCmd (initfunc);
sprintf(fulldbdname, "%s%s" DIRSEP "%s",
libdir, p, dbdname);
}
if (requireDebug)
printf("require: Looking for %s\n", fulldbdname);
if (stat(fulldbdname, &filestat) == 0) break;
p=end;
}
/* if dbd file exists and is not empty load it */
if (p && filestat.st_size > 0)
{
printf("Loading %s\n", fulldbdname);
if (dbLoadDatabase(fulldbdname, NULL, NULL) != 0)
{
fprintf (stderr, "require: can't load %s\n", fulldbdname);
return -1;
}
#endif
}
if (validate(vers, loaded) == ERROR)
else
{
printf("Requested %s version %s not available, found only %s.\n"
"Aborting startup stript.\n",
lib, vers, loaded);
shellScriptAbort();
return ERROR;
/* no dbd file, but that might be OK */
printf("no dbd file %s\n", dbdname);
}
if (loaded) printf("%s version is %s\n", lib, loaded);
return OK;
}
else
{
/* Library already loaded. Check Version. */
if (validate(version, loaded) == ERROR)
/* register module */
m = (moduleitem*) calloc(sizeof (moduleitem),1);
if (!m)
{
printf("Conflict between requested %s version %s\n"
"and already loaded version %s.\n"
"Aborting startup stript.\n",
lib, version, loaded);
shellScriptAbort();
return ERROR;
printf ("require: out of memory\n");
}
/* Loaded version is ok */
printf("%sLib-%s already loaded\n", lib, loaded);
return OK;
else
{
strncpy (m->name, module, sizeof(m->name));
strncpy (m->version, loaded, sizeof(m->version));
m->next = loadedModules;
loadedModules = m;
}
#ifdef EPICS_3_14
/* call register function for R3.14 */
/* call register function */
sprintf (symbolname, "%s_registerRecordDeviceDriver", module);
printf ("Calling %s function\n", symbolname);
#ifdef __vxworks
{
FUNCPTR f;
if (symFindByName(sysSymTbl, symbolname, (char**)&f, &type) == 0)
f(pdbbase);
else
fprintf (stderr, "require: can't find %s function\n", symbolname);
}
#else
iocshCmd(symbolname);
#endif
#endif
return 0;
}
}
char* getLibVersion(char* lib)
int libversionShow(const char* pattern)
{
char symbol[256];
char* loaded;
SYM_TYPE type;
sprintf(symbol, "_%sLibRelease", lib);
if (symFindByName(sysSymTbl, symbol, &loaded, &type) != OK) return NULL;
return loaded;
}
moduleitem* m;
static BOOL printIfLibversion(char* name, int val,
SYM_TYPE type, int arg, UINT16 group)
{
int l;
char* pattern = (char*) arg;
l = strlen(name);
if (l > 10 && strcmp(name+l-10, "LibRelease") == 0)
for (m = loadedModules; m; m=m->next)
{
if (pattern && !strstr(name, pattern)) return TRUE;
printf("%15.*s %s\n", l-11, name+1, (char*)val);
if (pattern && !strstr(m->name, pattern)) return 0;
printf("%15s %s\n", m->name, m->version);
}
return TRUE;
}
int libversionShow(char* pattern)
{
symEach(sysSymTbl, (FUNCPTR)printIfLibversion, (int)pattern);
return OK;
return 0;
}
#ifdef EPICS_3_14
......@@ -306,24 +560,36 @@ static const iocshArg * const requireArgs[2] = { &requireArg0, &requireArg1 };
static const iocshFuncDef requireDef = { "require", 2, requireArgs };
static void requireFunc (const iocshArgBuf *args)
{
if (require (args[0].sval, args[1].sval) != 0
&& !interruptAccept)
{
/* require failed in startup script before iocInit */
fprintf (stderr, "Aborting startup script\n");
epicsExit (1);
}
require(args[0].sval, args[1].sval);
}
static const iocshArg libversionShowArg0 = { "pattern", iocshArgString };
static const iocshArg * const libversionArgs[1] = { &libversionShowArg0 };
static const iocshFuncDef libversionShowDef = { "libversionShow", 1, libversionArgs };
static void libversionShowFunc (const iocshArgBuf *args)
{
libversionShow(args[0].sval);
}
static const iocshArg ldArg0 = { "library", iocshArgString };
static const iocshArg * const ldArgs[1] = { &ldArg0 };
static const iocshFuncDef ldDef = { "ld", 1, ldArgs };
static void ldFunc (const iocshArgBuf *args)
{
loadlib(args[0].sval);
}
static void requireRegister(void)
{
static int firstTime = 1;
if (firstTime) {
iocshRegister (&ldDef, ldFunc);
iocshRegister (&libversionShowDef, libversionShowFunc);
iocshRegister (&requireDef, requireFunc);
firstTime = 0;
}
}
epicsExportRegistrar(requireRegister);
epicsExportAddress(int, requireDebug);
#endif
#ifndef require_h
#define require_h
int require(char* lib, char* version);
char* getLibVersion(char* lib);
int libversionShow(char* pattern);
int require(const char* libname, const char* version);
const char* getLibVersion(const char* libname);
int libversionShow(const char* pattern);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment