netcdf-c/libdispatch/dplugins.c
2024-11-15 23:57:47 -05:00

341 lines
9.1 KiB
C

/*
* Copyright 2018, University Corporation for Atmospheric Research
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*/
/**************************************************/
/* Global state plugin path implementation */
/**
* @file
* Functions for working with plugins.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _MSC_VER
#include <io.h>
#endif
#include "netcdf.h"
#include "netcdf_filter.h"
#include "ncdispatch.h"
#include "nc4internal.h"
#include "nclog.h"
#include "ncbytes.h"
#include "ncplugins.h"
#include "netcdf_aux.h"
/*
Unified plugin related code
*/
/**************************************************/
/* Plugin-path API */
/* list of environment variables to check for plugin roots */
#define PLUGIN_ENV "HDF5_PLUGIN_PATH"
/* Control path verification */
#define PLUGINPATHVERIFY "NC_PLUGIN_PATH_VERIFY"
/*Forward*/
static int buildinitialpluginpath(NCPluginList* dirs);
static int NC_plugin_path_initialized = 0;
static int NC_plugin_path_verify = 1;
/**
* This function is called as part of nc_initialize.
* Its purpose is to initialize the plugin paths state.
*
* @return NC_NOERR
*
* @author Dennis Heimbigner
*/
EXTERNL int
nc_plugin_path_initialize(void)
{
int stat = NC_NOERR;
struct NCglobalstate* gs = NULL;
NCPluginList dirs = {0,NULL};
#ifdef USE_HDF5
int hdf5found = 0; /* 1 => we got a legit plugin path set from HDF5 */
#endif
if(!NC_initialized) nc_initialize();
if(NC_plugin_path_initialized != 0) goto done;
NC_plugin_path_initialized = 1;
if(getenv(PLUGINPATHVERIFY) != NULL) NC_plugin_path_verify = 1;
gs = NC_getglobalstate();
/**
* When the netcdf-c library initializes itself (at runtime), it chooses an
* initial global plugin path using the following rules, which are those used
* by the HDF5 library, except as modified for plugin install (which HDF5 does not support).
*/
/* Initialize the implementations */
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
if((stat = NCZ_plugin_path_initialize())) goto done;
#endif
#ifdef USE_HDF5
if((stat = NC4_hdf5_plugin_path_initialize())) goto done;
#endif
/* Compute the initial global plugin path */
assert(dirs.ndirs == 0 && dirs.dirs == NULL);
if((stat = buildinitialpluginpath(&dirs))) goto done; /* Construct a default */
/* Sync to the actual implementations */
#ifdef USE_HDF5
if(!hdf5found)
{if((stat = NC4_hdf5_plugin_path_set(&dirs))) goto done;}
#endif
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
if((stat = NCZ_plugin_path_set(&dirs))) goto done;
#endif
/* Set the global plugin dirs sequence */
assert(gs->pluginpaths == NULL);
gs->pluginpaths = nclistnew();
if(dirs.ndirs > 0) {
size_t i;
char** dst;
nclistsetlength(gs->pluginpaths,dirs.ndirs);
dst = (char**)nclistcontents(gs->pluginpaths);
assert(dst != NULL);
for(i=0;i<dirs.ndirs;i++)
dst[i] = strdup(dirs.dirs[i]);
}
done:
ncaux_plugin_path_clear(&dirs);
return NCTHROW(stat);
}
/**
* This function is called as part of nc_finalize()
* Its purpose is to clean-up plugin path state.
*
* @return NC_NOERR
*
* @author Dennis Heimbigner
*/
int
nc_plugin_path_finalize(void)
{
int stat = NC_NOERR;
struct NCglobalstate* gs = NC_getglobalstate();
if(NC_plugin_path_initialized == 0) goto done;
NC_plugin_path_initialized = 0;
NC_plugin_path_verify = 0;
/* Finalize the actual implementatios */
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
if((stat = NCZ_plugin_path_finalize())) goto done;
#endif
#ifdef USE_HDF5
if((stat = NC4_hdf5_plugin_path_finalize())) goto done;
#endif
nclistfreeall(gs->pluginpaths); gs->pluginpaths = NULL;
done:
return NCTHROW(stat);
}
/**
* Return the length of the current sequence of directories
* in the internal global plugin path list.
* @param ndirsp length is returned here
* @return NC_NOERR | NC_EXXX
*
* @author Dennis Heimbigner
*/
int
nc_plugin_path_ndirs(size_t* ndirsp)
{
int stat = NC_NOERR;
size_t ndirs = 0;
struct NCglobalstate* gs = NC_getglobalstate();
if(gs->pluginpaths == NULL) gs->pluginpaths = nclistnew(); /* suspenders and belt */
ndirs = nclistlength(gs->pluginpaths);
/* Verify that the implementation plugin paths are consistent in length*/
if(NC_plugin_path_verify) {
#ifdef NETCDF_ENABLE_HDF5
{
size_t ndirs5 = 0;
if((stat=NC4_hdf5_plugin_path_ndirs(&ndirs5))) goto done;
assert(ndirs5 == ndirs);
}
#endif /*NETCDF_ENABLE_HDF5*/
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
{
size_t ndirsz = 0;
if((stat=NCZ_plugin_path_ndirs(&ndirsz))) goto done;
assert(ndirsz == ndirs);
}
#endif /*NETCDF_ENABLE_NCZARR_FILTERS*/
}
if(ndirsp) *ndirsp = ndirs;
done:
return NCTHROW(stat);
}
/**
* Return the current sequence of directories in the internal global
* plugin path list. Since this function does not modify the plugin path,
* it can be called at any time.
* @param dirs pointer to an NCPluginList object
* @return NC_NOERR | NC_EXXX
* @author Dennis Heimbigner
*
* WARNING: if dirs->dirs is NULL, then space for the directory
* vector will be allocated. If not NULL, then the specified space will
* be overwritten with the vector.
*
* @author: Dennis Heimbigner
*/
int
nc_plugin_path_get(NCPluginList* dirs)
{
int stat = NC_NOERR;
struct NCglobalstate* gs = NC_getglobalstate();
size_t i;
if(gs->pluginpaths == NULL) gs->pluginpaths = nclistnew(); /* suspenders and belt */
if(dirs == NULL) goto done;
dirs->ndirs = nclistlength(gs->pluginpaths);
if(dirs->ndirs > 0 && dirs->dirs == NULL) {
if((dirs->dirs = (char**)calloc(dirs->ndirs,sizeof(char*)))==NULL)
{stat = NC_ENOMEM; goto done;}
}
for(i=0;i<dirs->ndirs;i++) {
const char* dir = nclistget(gs->pluginpaths,i);
dirs->dirs[i] = nulldup(dir);
}
/* Verify that the implementation plugin paths are consistent */
if(NC_plugin_path_verify) {
#ifdef NETCDF_ENABLE_HDF5
{
size_t i;
NCPluginList l5 = {0,NULL};
if((stat=NC4_hdf5_plugin_path_get(&l5))) goto done;
assert(l5.ndirs == nclistlength(gs->pluginpaths));
for(i=0;i<l5.ndirs;i++) {
assert(strcmp(dirs->dirs[i],l5.dirs[i])==0);
nullfree(l5.dirs[i]);
}
nullfree(l5.dirs);
}
#endif /*NETCDF_ENABLE_HDF5*/
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
{
size_t i;
NCPluginList lz = {0,NULL};
if((stat=NCZ_plugin_path_get(&lz))) goto done;
assert(lz.ndirs == nclistlength(gs->pluginpaths));
for(i=0;i<lz.ndirs;i++) {
assert(strcmp(dirs->dirs[i],lz.dirs[i])==0);
nullfree(lz.dirs[i]);
}
nullfree(lz.dirs);
}
#endif /*NETCDF_ENABLE_NCZARR_FILTERS*/
}
done:
return NCTHROW(stat);
}
/**
* Empty the current internal path sequence
* and replace with the sequence of directories argument.
* Using a dirs->ndirs argument of 0 will clear the set of plugin dirs.
*
* @param dirs to overwrite the current internal dir list
* @return NC_NOERR | NC_EXXX
*
* @author Dennis Heimbigner
*/
int
nc_plugin_path_set(NCPluginList* dirs)
{
int stat = NC_NOERR;
struct NCglobalstate* gs = NC_getglobalstate();
if(dirs == NULL) {stat = NC_EINVAL; goto done;}
/* Clear the current dir list */
nclistfreeall(gs->pluginpaths);
gs->pluginpaths = nclistnew();
if(dirs->ndirs > 0) {
size_t i;
assert(gs->pluginpaths != NULL);
for(i=0;i<dirs->ndirs;i++) {
nclistpush(gs->pluginpaths,nulldup(dirs->dirs[i]));
}
}
/* Sync the global plugin path set to the individual implementations */
#ifdef NETCDF_ENABLE_HDF5
if((stat = NC4_hdf5_plugin_path_set(dirs))) goto done;
#endif
#ifdef NETCDF_ENABLE_NCZARR_FILTERS
if((stat = NCZ_plugin_path_set(dirs))) goto done;
#endif
done:
return NCTHROW(stat);
}
/**
* When the netcdf-c library initializes itself (at runtime), it chooses an
* initial global plugin path using the following rules, which are those used
* by the HDF5 library, except as modified for plugin install (which HDF5 does not support).
*
* Note: In the following, PLATFORMPATH is:
* -- /usr/local/lhdf5/lib/plugin if platform is *nix*
* -- %ALLUSERSPROFILE%/hdf5/lib/plugin if platform is Windows or Mingw
* and in the following, PLATFORMSEP is:
* -- ":" if platform is *nix*
* -- ";" if platform is Windows or Mingw
* and
* NETCDF_PLUGIN_SEARCH_PATH is the value constructed at build-time (see configure.ac)
*
* Table showing the computation of the initial global plugin path
* =================================================
* | HDF5_PLUGIN_PATH | Initial global plugin path |
* =================================================
* | undefined | NETCDF_PLUGIN_SEARCH_PATH |
* -------------------------------------------------
* | <path1;...pathn> | <path1;...pathn> |
* -------------------------------------------------
*/
static int
buildinitialpluginpath(NCPluginList* dirs)
{
int stat = NC_NOERR;
const char* hdf5path = NULL;
/* Find the plugin directory root(s) */
hdf5path = getenv(PLUGIN_ENV); /* HDF5_PLUGIN_PATH */
if(hdf5path == NULL) {
/* Use NETCDF_PLUGIN_SEARCH_PATH */
hdf5path = NETCDF_PLUGIN_SEARCH_PATH;
}
if((stat = ncaux_plugin_path_parse(hdf5path,'\0',dirs))) goto done;
done:
return stat;
}