88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/port/path.c,v 1.43 2004/11/0604:24:14 tgl Exp $
11+ * $PostgreSQL: pgsql/src/port/path.c,v 1.44 2004/11/0621:39:45 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
3232#define IS_PATH_SEP (ch ) ((ch) == ';')
3333#endif
3434
35- static const char * relative_path ( const char * bin_path ,const char * other_path );
36- static void make_relative ( const char * my_exec_path ,const char * p , char * ret_path );
35+ static void make_relative_path ( char * ret_path ,const char * target_path ,
36+ const char * bin_path ,const char * my_exec_path );
3737static void trim_directory (char * path );
3838static void trim_trailing_separator (char * path );
3939
40- /* Move to last of consecutive separators or to null byte */
41- #define MOVE_TO_SEP_END (p ) \
42- { \
43- while (IS_DIR_SEP((p)[0]) && (IS_DIR_SEP((p)[1]) || !(p)[1])) \
44- (p)++; \
45- }
4640
4741/*
4842 * skip_drive
@@ -252,11 +246,11 @@ canonicalize_path(char *path)
252246{
253247int len = strlen (path );
254248
255- if (len >= 2 && strcmp (path + len - 2 ,"/." )== 0 )
249+ if (len > 2 && strcmp (path + len - 2 ,"/." )== 0 )
256250{
257251trim_directory (path );
258252}
259- else if (len >= 3 && strcmp (path + len - 3 ,"/.." )== 0 )
253+ else if (len > 3 && strcmp (path + len - 3 ,"/.." )== 0 )
260254{
261255trim_directory (path );
262256trim_directory (path );/* remove directory above */
@@ -305,132 +299,123 @@ get_progname(const char *argv0)
305299
306300
307301/*
308- *get_share_path
302+ * make_relative_path - make a path relative to the actual binary location
303+ *
304+ * This function exists to support relocation of installation trees.
305+ *
306+ *ret_path is the output area (must be of size MAXPGPATH)
307+ *target_path is the compiled-in path to the directory we want to find
308+ *bin_path is the compiled-in path to the directory of executables
309+ *my_exec_path is the actual location of my executable
310+ *
311+ * If target_path matches bin_path up to the last directory component of
312+ * bin_path, then we build the result as my_exec_path (less the executable
313+ * name and last directory) joined to the non-matching part of target_path.
314+ * Otherwise, we return target_path as-is.
315+ *
316+ * For example:
317+ *target_path = '/usr/local/share/postgresql'
318+ *bin_path = '/usr/local/bin'
319+ *my_exec_path = '/opt/pgsql/bin/postmaster'
320+ * Given these inputs we would return '/opt/pgsql/share/postgresql'
309321 */
310- void
311- get_share_path (const char * my_exec_path ,char * ret_path )
322+ static void
323+ make_relative_path (char * ret_path ,const char * target_path ,
324+ const char * bin_path ,const char * my_exec_path )
312325{
313- const char * p ;
326+ const char * bin_end ;
327+ int prefix_len ;
328+
329+ bin_end = last_dir_separator (bin_path );
330+ if (!bin_end )
331+ gotono_match ;
332+ prefix_len = bin_end - bin_path + 1 ;
333+ if (strncmp (target_path ,bin_path ,prefix_len )!= 0 )
334+ gotono_match ;
335+
336+ StrNCpy (ret_path ,my_exec_path ,MAXPGPATH );
337+ trim_directory (ret_path );/* remove my executable name */
338+ trim_directory (ret_path );/* remove last directory component (/bin) */
339+ join_path_components (ret_path ,ret_path ,target_path + prefix_len );
340+ canonicalize_path (ret_path );
341+ return ;
314342
315- if ((p = relative_path (PGBINDIR ,PGSHAREDIR )))
316- make_relative (my_exec_path ,p ,ret_path );
317- else
318- StrNCpy (ret_path ,PGSHAREDIR ,MAXPGPATH );
343+ no_match :
344+ StrNCpy (ret_path ,target_path ,MAXPGPATH );
319345canonicalize_path (ret_path );
320346}
321347
322348
349+ /*
350+ *get_share_path
351+ */
352+ void
353+ get_share_path (const char * my_exec_path ,char * ret_path )
354+ {
355+ make_relative_path (ret_path ,PGSHAREDIR ,PGBINDIR ,my_exec_path );
356+ }
357+
323358/*
324359 *get_etc_path
325360 */
326361void
327362get_etc_path (const char * my_exec_path ,char * ret_path )
328363{
329- const char * p ;
330-
331- if ((p = relative_path (PGBINDIR ,SYSCONFDIR )))
332- make_relative (my_exec_path ,p ,ret_path );
333- else
334- StrNCpy (ret_path ,SYSCONFDIR ,MAXPGPATH );
335- canonicalize_path (ret_path );
364+ make_relative_path (ret_path ,SYSCONFDIR ,PGBINDIR ,my_exec_path );
336365}
337366
338-
339367/*
340368 *get_include_path
341369 */
342370void
343371get_include_path (const char * my_exec_path ,char * ret_path )
344372{
345- const char * p ;
346-
347- if ((p = relative_path (PGBINDIR ,INCLUDEDIR )))
348- make_relative (my_exec_path ,p ,ret_path );
349- else
350- StrNCpy (ret_path ,INCLUDEDIR ,MAXPGPATH );
351- canonicalize_path (ret_path );
373+ make_relative_path (ret_path ,INCLUDEDIR ,PGBINDIR ,my_exec_path );
352374}
353375
354-
355376/*
356377 *get_pkginclude_path
357378 */
358379void
359380get_pkginclude_path (const char * my_exec_path ,char * ret_path )
360381{
361- const char * p ;
362-
363- if ((p = relative_path (PGBINDIR ,PKGINCLUDEDIR )))
364- make_relative (my_exec_path ,p ,ret_path );
365- else
366- StrNCpy (ret_path ,PKGINCLUDEDIR ,MAXPGPATH );
367- canonicalize_path (ret_path );
382+ make_relative_path (ret_path ,PKGINCLUDEDIR ,PGBINDIR ,my_exec_path );
368383}
369384
370-
371385/*
372386 *get_includeserver_path
373387 */
374388void
375389get_includeserver_path (const char * my_exec_path ,char * ret_path )
376390{
377- const char * p ;
378-
379- if ((p = relative_path (PGBINDIR ,INCLUDEDIRSERVER )))
380- make_relative (my_exec_path ,p ,ret_path );
381- else
382- StrNCpy (ret_path ,INCLUDEDIRSERVER ,MAXPGPATH );
383- canonicalize_path (ret_path );
391+ make_relative_path (ret_path ,INCLUDEDIRSERVER ,PGBINDIR ,my_exec_path );
384392}
385393
386-
387394/*
388395 *get_lib_path
389396 */
390397void
391398get_lib_path (const char * my_exec_path ,char * ret_path )
392399{
393- const char * p ;
394-
395- if ((p = relative_path (PGBINDIR ,LIBDIR )))
396- make_relative (my_exec_path ,p ,ret_path );
397- else
398- StrNCpy (ret_path ,LIBDIR ,MAXPGPATH );
399- canonicalize_path (ret_path );
400+ make_relative_path (ret_path ,LIBDIR ,PGBINDIR ,my_exec_path );
400401}
401402
402-
403403/*
404404 *get_pkglib_path
405405 */
406406void
407407get_pkglib_path (const char * my_exec_path ,char * ret_path )
408408{
409- const char * p ;
410-
411- if ((p = relative_path (PGBINDIR ,PKGLIBDIR )))
412- make_relative (my_exec_path ,p ,ret_path );
413- else
414- StrNCpy (ret_path ,PKGLIBDIR ,MAXPGPATH );
415- canonicalize_path (ret_path );
409+ make_relative_path (ret_path ,PKGLIBDIR ,PGBINDIR ,my_exec_path );
416410}
417411
418-
419412/*
420413 *get_locale_path
421- *
422- *Return locale path, either relative to /bin or hardcoded
423414 */
424415void
425416get_locale_path (const char * my_exec_path ,char * ret_path )
426417{
427- const char * p ;
428-
429- if ((p = relative_path (PGBINDIR ,LOCALEDIR )))
430- make_relative (my_exec_path ,p ,ret_path );
431- else
432- StrNCpy (ret_path ,LOCALEDIR ,MAXPGPATH );
433- canonicalize_path (ret_path );
418+ make_relative_path (ret_path ,LOCALEDIR ,PGBINDIR ,my_exec_path );
434419}
435420
436421
@@ -440,14 +425,16 @@ get_locale_path(const char *my_exec_path, char *ret_path)
440425bool
441426get_home_path (char * ret_path )
442427{
443- if (getenv (HOMEDIR )== NULL )
428+ const char * homedir = getenv (HOMEDIR );
429+
430+ if (homedir == NULL )
444431{
445432* ret_path = '\0' ;
446433return false;
447434}
448435else
449436{
450- StrNCpy (ret_path ,getenv ( HOMEDIR ) ,MAXPGPATH );
437+ StrNCpy (ret_path ,homedir ,MAXPGPATH );
451438canonicalize_path (ret_path );
452439return true;
453440}
@@ -515,91 +502,6 @@ set_pglocale_pgservice(const char *argv0, const char *app)
515502}
516503
517504
518- /*
519- *make_relative - adjust path to be relative to bin/
520- *
521- * ret_path is the output area (must be of size MAXPGPATH)
522- */
523- static void
524- make_relative (const char * my_exec_path ,const char * p ,char * ret_path )
525- {
526- char path [MAXPGPATH ];
527-
528- StrNCpy (path ,my_exec_path ,MAXPGPATH );
529- trim_directory (path );/* remove my executable name */
530- trim_directory (path );/* remove last directory component (/bin) */
531- join_path_components (ret_path ,path ,p );
532- }
533-
534-
535- /*
536- *relative_path
537- *
538- *Do the supplied paths differ only in their last component?
539- */
540- static const char *
541- relative_path (const char * bin_path ,const char * other_path )
542- {
543- #ifdef WIN32
544- /* Driver letters match? */
545- if (isalpha (* bin_path )&& bin_path [1 ]== ':' &&
546- (!isalpha (* other_path )|| !other_path [1 ]== ':' ))
547- return NULL ;
548- if ((!isalpha (* bin_path )|| !bin_path [1 ]== ':' )&&
549- (isalpha (* other_path )&& other_path [1 ]== ':' ))
550- return NULL ;
551- if (isalpha (* bin_path )&& bin_path [1 ]== ':' &&
552- isalpha (* other_path )&& other_path [1 ]== ':' )
553- {
554- if (toupper (* bin_path )!= toupper (* other_path ))
555- return NULL ;
556- bin_path += 2 ;
557- other_path += 2 ;
558- }
559- #endif
560-
561- while (1 )
562- {
563- /* Move past adjacent slashes like //, and trailing ones */
564- MOVE_TO_SEP_END (bin_path );
565- MOVE_TO_SEP_END (other_path );
566-
567- /* One of the paths is done? */
568- if (!* bin_path || !* other_path )
569- break ;
570-
571- /* Win32 filesystem is case insensitive */
572- if ((!IS_DIR_SEP (* bin_path )|| !IS_DIR_SEP (* other_path ))&&
573- #ifndef WIN32
574- * bin_path != * other_path
575- #else
576- toupper ((unsignedchar )* bin_path )!= toupper ((unsignedchar )* other_path )
577- #endif
578- )
579- break ;
580-
581- bin_path ++ ;
582- other_path ++ ;
583- }
584-
585- /* identical? */
586- if (!* bin_path && !* other_path )
587- return NULL ;
588-
589- /* advance past directory name */
590- while (!IS_DIR_SEP (* bin_path )&& * bin_path )
591- bin_path ++ ;
592-
593- MOVE_TO_SEP_END (bin_path );
594-
595- /* Is bin done? */
596- if (!* bin_path )
597- return other_path ;
598- else
599- return NULL ;
600- }
601-
602-
603505/*
604506 *trim_directory
605507 *