File: dudfplugins.c

package info (click to toggle)
netcdf 1%3A4.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 116,236 kB
  • sloc: ansic: 281,201; sh: 14,777; cpp: 6,000; yacc: 2,612; makefile: 2,025; lex: 1,218; javascript: 280; xml: 173; awk: 2
file content (272 lines) | stat: -rw-r--r-- 8,314 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/* Copyright 2026, UCAR/Unidata.
   See the COPYRIGHT file for more information. */

/**
 * @file
 * @internal This file contains functions for loading UDF plugins from RC files.
 *
 * @author Ed Hartnett
 * @date 2/2/26
 */

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "netcdf.h"
#include "netcdf_dispatch.h"
#include "nclog.h"
#include "ncrc.h"
#include "ncudfplugins.h"

/* Platform-specific dynamic loading headers */
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

/**
 * Load a dynamic library (platform-specific).
 *
 * @param path Full path to the library file.
 * @return Handle to the loaded library, or NULL on failure.
 *
 * @author Edward Hartnett
 * @date 2/2/26
 */
static void*
load_library(const char* path)
{
    void* handle = NULL;
    
#ifdef _WIN32
    handle = (void*)LoadLibraryA(path);
    if (!handle) {
        DWORD err = GetLastError();
        nclog(NCLOGERR, "LoadLibrary failed for %s: error %lu", path, err);
    }
#else
    handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
    if (!handle) {
        nclog(NCLOGERR, "dlopen failed for %s: %s", path, dlerror());
    }
#endif
    
    return handle;
}

/**
 * Get a symbol from a loaded library (platform-specific).
 *
 * @param handle Handle to the loaded library.
 * @param symbol Name of the symbol to retrieve.
 * @return Pointer to the symbol, or NULL on failure.
 *
 * @author Edward Hartnett
 * @date 2/2/26
 */
static void*
get_symbol(void* handle, const char* symbol)
{
    void* sym = NULL;
    
#ifdef _WIN32
    sym = (void*)GetProcAddress((HMODULE)handle, symbol);
    if (!sym) {
        DWORD err = GetLastError();
        nclog(NCLOGERR, "GetProcAddress failed for %s: error %lu", symbol, err);
    }
#else
    sym = dlsym(handle, symbol);
    if (!sym) {
        nclog(NCLOGERR, "dlsym failed for %s: %s", symbol, dlerror());
    }
#endif
    
    return sym;
}

/**
 * Load a single UDF plugin library and call its initialization function.
 *
 * @param udf_number UDF slot number (0-9).
 * @param library_path Full path to the plugin library.
 * @param init_func Name of the initialization function.
 * @param magic Optional magic number string (can be NULL).
 * @return NC_NOERR on success, error code on failure.
 *
 * @author Edward Hartnett
 * @date 2/2/26
 */
static int
load_udf_plugin(int udf_number, const char* library_path,
                const char* init_func, const char* magic)
{
    int stat = NC_NOERR;
    void* handle = NULL;
    int mode_flag;
#ifndef HAVE_NETCDF_UDF_SELF_REGISTRATION
    NC_Dispatch* dispatch_table = NULL;
    char magic_check[NC_MAX_MAGIC_NUMBER_LEN + 1];
#endif
    
    /* Determine mode flag from UDF number */
    if (udf_number == 0)
        mode_flag = NC_UDF0;
    else if (udf_number == 1)
        mode_flag = NC_UDF1;
    else
        mode_flag = NC_UDF2 << (udf_number - 2);
    
    /* Load the library */
    handle = load_library(library_path);
    if (!handle) {
        stat = NC_ENOTNC;
        goto done;
    }
    
#ifdef HAVE_NETCDF_UDF_SELF_REGISTRATION
    /* Self-registration mode: init function returns NC_Dispatch* */
    {
        NC_Dispatch* (*init_function)(void) = NULL;
        NC_Dispatch* table = NULL;
        
        /* Get the initialization function */
        init_function = (NC_Dispatch* (*)(void))get_symbol(handle, init_func);
        if (!init_function) {
            stat = NC_ENOTNC;
            goto done;
        }
        
        /* Call the initialization function to get the dispatch table */
        table = init_function();
        if (!table) {
            nclog(NCLOGERR, "Plugin init function %s returned NULL", init_func);
            stat = NC_ENOTNC;
            goto done;
        }
        
        /* Verify dispatch ABI version */
        if (table->dispatch_version != NC_DISPATCH_VERSION) {
            nclog(NCLOGERR, "Plugin dispatch ABI mismatch for UDF%d: expected %d, got %d",
                  udf_number, NC_DISPATCH_VERSION, table->dispatch_version);
            stat = NC_EINVAL;
            goto done;
        }
        
        /* Register the dispatch table returned by the plugin */
        if ((stat = nc_def_user_format(mode_flag, table, (char*)magic))) {
            nclog(NCLOGERR, "Failed to register dispatch table for UDF%d: %d",
                  udf_number, stat);
            goto done;
        }
    }
#else
    /* Legacy mode: init function returns int and registers itself */
    {
        int (*init_function)(void) = NULL;
        
        /* Get the initialization function */
        init_function = (int (*)(void))get_symbol(handle, init_func);
        if (!init_function) {
            stat = NC_ENOTNC;
            goto done;
        }
        
        /* Call the initialization function */
        if ((stat = init_function())) {
            nclog(NCLOGERR, "Plugin init function %s failed: %d", init_func, stat);
            goto done;
        }
        
        /* Verify the dispatch table was registered */
        memset(magic_check, 0, sizeof(magic_check));
        if ((stat = nc_inq_user_format(mode_flag, &dispatch_table, magic_check))) {
            nclog(NCLOGERR, "Plugin did not register dispatch table for UDF%d", udf_number);
            goto done;
        }
        
        if (dispatch_table == NULL) {
            nclog(NCLOGERR, "Plugin registered NULL dispatch table for UDF%d", udf_number);
            stat = NC_EINVAL;
            goto done;
        }
        
        /* Verify dispatch ABI version */
        if (dispatch_table->dispatch_version != NC_DISPATCH_VERSION) {
            nclog(NCLOGERR, "Plugin dispatch ABI mismatch for UDF%d: expected %d, got %d",
                  udf_number, NC_DISPATCH_VERSION, dispatch_table->dispatch_version);
            stat = NC_EINVAL;
            goto done;
        }
        
        /* Optionally verify magic number matches */
        if (magic != NULL && strlen(magic_check) > 0) {
            if (strcmp(magic, magic_check) != 0) {
                nclog(NCLOGWARN, "Plugin magic number mismatch for UDF%d: expected %s, got %s",
                      udf_number, magic, magic_check);
            }
        }
    }
#endif
    
    nclog(NCLOGNOTE, "Successfully loaded UDF%d plugin from %s", 
          udf_number, library_path);
    
done:
    /* Handles are intentionally not closed; the OS will reclaim at process exit.
     * The dispatch table and its functions must remain accessible. */
    return stat;
}

/**
 * Load and initialize all UDF plugins from RC file configuration.
 *
 * This function loops through all 10 UDF slots (0-9) and checks for
 * corresponding RC file entries. If both LIBRARY and INIT keys are
 * present for a slot, it attempts to load that plugin.
 *
 * @return NC_NOERR (always succeeds, even if plugins fail to load).
 *
 * @author Edward Hartnett
 * @date 2/2/26
 */
int
NC_udf_load_plugins(void)
{
    int stat = NC_NOERR;
    
    /* Loop through all 10 UDF slots */
    for (int i = 0; i < NC_MAX_UDF_FORMATS; i++) {
        char key_lib[64], key_init[64], key_magic[64];
        const char* lib = NULL;
        const char* init = NULL;
        const char* magic = NULL;
        
        /* Build RC key names for this UDF slot */
        snprintf(key_lib, sizeof(key_lib), "NETCDF.UDF%d.LIBRARY", i);
        snprintf(key_init, sizeof(key_init), "NETCDF.UDF%d.INIT", i);
        snprintf(key_magic, sizeof(key_magic), "NETCDF.UDF%d.MAGIC", i);
        
        /* Look up RC values */
        lib = NC_rclookup(key_lib, NULL, NULL);
        init = NC_rclookup(key_init, NULL, NULL);
        magic = NC_rclookup(key_magic, NULL, NULL);
        
        /* If both LIBRARY and INIT are present, try to load the plugin */
        if (lib && init) {
            if ((stat = load_udf_plugin(i, lib, init, magic))) {
                nclog(NCLOGWARN, "Failed to load UDF%d plugin from %s: %d", i, lib, stat);
            }
        } else if (lib || init) {
            /* Warn about partial configuration */
            nclog(NCLOGWARN, "Ignoring partial UDF%d configuration "
                  "(both NETCDF.UDF%d.LIBRARY and NETCDF.UDF%d.INIT are required)",
                  i, i, i);
        }
    }
    
    /* Always return success - plugin loading failures are not fatal */
    return NC_NOERR;
}