8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.48 2001/03/22 03:59:58 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.49 2001/05/17 17:44:18 petere Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
15
15
#include "postgres.h"
16
16
17
+ #include <errno.h>
17
18
#include <sys/types.h>
18
19
#include <sys/stat.h>
19
20
20
21
#include "dynloader.h"
22
+ #include "miscadmin.h"
21
23
#include "utils/dynamic_loader.h"
22
24
23
25
@@ -44,6 +46,12 @@ static DynamicFileList *file_tail = (DynamicFileList *) NULL;
44
46
45
47
#define SAME_INODE (A ,B ) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
46
48
49
+ char * Dynamic_library_path ;
50
+
51
+ static bool file_exists (const char * name );
52
+ static char * find_in_dynamic_libpath (const char * basename );
53
+ static char * expand_dynamic_library_name (const char * name );
54
+
47
55
48
56
/*
49
57
* Load the specified dynamic-link library file, and look for a function
@@ -60,6 +68,11 @@ load_external_function(char *filename, char *funcname,
60
68
PGFunction retval ;
61
69
char * load_error ;
62
70
struct stat stat_buf ;
71
+ char * fullname ;
72
+
73
+ fullname = expand_dynamic_library_name (filename );
74
+ if (fullname )
75
+ filename = fullname ;
63
76
64
77
/*
65
78
* Scan the list of loaded FILES to see if the file has been loaded.
@@ -143,6 +156,11 @@ load_file(char *filename)
143
156
DynamicFileList * file_scanner ,
144
157
* p ;
145
158
struct stat stat_buf ;
159
+ char * fullname ;
160
+
161
+ fullname = expand_dynamic_library_name (filename );
162
+ if (fullname )
163
+ filename = fullname ;
146
164
147
165
/*
148
166
* We need to do stat() in order to determine whether this is the same
@@ -181,3 +199,181 @@ load_file(char *filename)
181
199
182
200
load_external_function (filename , (char * ) NULL , false);
183
201
}
202
+
203
+
204
+
205
+ static bool
206
+ file_exists (const char * name )
207
+ {
208
+ struct stat st ;
209
+
210
+ AssertArg (name != NULL );
211
+
212
+ if (stat (name , & st ) == 0 )
213
+ return true;
214
+ else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES ))
215
+ elog (ERROR , "stat failed on %s: %s" , name , strerror (errno ));
216
+
217
+ return false;
218
+ }
219
+
220
+
221
+ /* Example format: ".so" */
222
+ #ifndef DLSUFFIX
223
+ #error "DLSUFFIX must be defined to compile this file."
224
+ #endif
225
+
226
+ /* Example format: "/usr/local/pgsql/lib" */
227
+ #ifndef LIBDIR
228
+ #error "LIBDIR needs to be defined to compile this file."
229
+ #endif
230
+
231
+
232
+ /*
233
+ * If name contains a slash, check if the file exists, if so return
234
+ * the name. Else (no slash) try to expand using search path (see
235
+ * find_in_dynamic_libpath below); if that works, return the fully
236
+ * expanded file name. If the previous failed, append DLSUFFIX and
237
+ * try again. If all fails, return NULL. The return value is
238
+ * palloc'ed.
239
+ */
240
+ static char *
241
+ expand_dynamic_library_name (const char * name )
242
+ {
243
+ bool have_slash ;
244
+ char * new ;
245
+ size_t len ;
246
+
247
+ AssertArg (name );
248
+
249
+ have_slash = (strchr (name , '/' ) != NULL );
250
+
251
+ if (!have_slash )
252
+ {
253
+ char * full ;
254
+
255
+ full = find_in_dynamic_libpath (name );
256
+ if (full )
257
+ return full ;
258
+ }
259
+ else
260
+ {
261
+ if (file_exists (name ))
262
+ return pstrdup (name );
263
+ }
264
+
265
+ len = strlen (name );
266
+
267
+ new = palloc (len + strlen (DLSUFFIX ) + 1 );
268
+ strcpy (new , name );
269
+ strcpy (new + len , DLSUFFIX );
270
+
271
+ if (!have_slash )
272
+ {
273
+ char * full ;
274
+
275
+ full = find_in_dynamic_libpath (new );
276
+ pfree (new );
277
+ if (full )
278
+ return full ;
279
+ }
280
+ else
281
+ {
282
+ if (file_exists (new ))
283
+ return new ;
284
+ }
285
+
286
+ return NULL ;
287
+ }
288
+
289
+
290
+
291
+ /*
292
+ * Search for a file called 'basename' in the colon-separated search
293
+ * path 'path'. If the file is found, the full file name is returned
294
+ * in palloced memory. The the file is not found, return NULL.
295
+ */
296
+ static char *
297
+ find_in_dynamic_libpath (const char * basename )
298
+ {
299
+ const char * p ;
300
+ char * full ;
301
+ size_t len ;
302
+ size_t baselen ;
303
+
304
+ AssertArg (basename != NULL );
305
+ AssertArg (strchr (basename , '/' ) == NULL );
306
+ AssertState (Dynamic_library_path != NULL );
307
+
308
+ p = Dynamic_library_path ;
309
+ if (strlen (p ) == 0 )
310
+ return NULL ;
311
+
312
+ baselen = strlen (basename );
313
+
314
+ do {
315
+ len = strcspn (p , ":" );
316
+
317
+ if (len == 0 )
318
+ elog (ERROR , "zero length dynamic_library_path component" );
319
+
320
+ /* substitute special value */
321
+ if (p [0 ] == '$' )
322
+ {
323
+ size_t varname_len = strcspn (p + 1 , "/" ) + 1 ;
324
+ const char * replacement = NULL ;
325
+ size_t repl_len ;
326
+
327
+ if (strncmp (p , "$libdir" , varname_len )== 0 )
328
+ replacement = LIBDIR ;
329
+ else
330
+ elog (ERROR , "invalid dynamic_library_path specification" );
331
+
332
+ repl_len = strlen (replacement );
333
+
334
+ if (p [varname_len ] == '\0' )
335
+ {
336
+ full = palloc (repl_len + 1 + baselen + 1 );
337
+ snprintf (full , repl_len + 1 + baselen + 1 ,
338
+ "%s/%s" , replacement , basename );
339
+ }
340
+ else
341
+ {
342
+ full = palloc (repl_len + (len - varname_len ) + 1 + baselen + 1 );
343
+
344
+ strcpy (full , replacement );
345
+ strncat (full , p + varname_len , len - varname_len );
346
+ full [repl_len + (len - varname_len )] = '\0' ;
347
+ strcat (full , "/" );
348
+ strcat (full , basename );
349
+ }
350
+ }
351
+
352
+ /* regular case */
353
+ else
354
+ {
355
+ /* only absolute paths */
356
+ if (p [0 ] != '/' )
357
+ elog (ERROR , "dynamic_library_path component is not absolute" );
358
+
359
+ full = palloc (len + 1 + baselen + 1 );
360
+ strncpy (full , p , len );
361
+ full [len ] = '/' ;
362
+ strcpy (full + len + 1 , basename );
363
+ }
364
+
365
+ if (DebugLvl > 1 )
366
+ elog (DEBUG , "find_in_dynamic_libpath: trying %s" , full );
367
+
368
+ if (file_exists (full ))
369
+ return full ;
370
+
371
+ pfree (full );
372
+ if (p [len ] == '\0' )
373
+ break ;
374
+ else
375
+ p += len + 1 ;
376
+ } while (1 );
377
+
378
+ return NULL ;
379
+ }
0 commit comments