mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-01-30 16:10:44 +08:00
341 lines
9.1 KiB
C
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;
|
|
}
|