00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "c.h"
00017
00018 #include <ctype.h>
00019 #include <sys/stat.h>
00020 #ifdef WIN32
00021 #ifdef _WIN32_IE
00022 #undef _WIN32_IE
00023 #endif
00024 #define _WIN32_IE 0x0500
00025 #ifdef near
00026 #undef near
00027 #endif
00028 #define near
00029 #include <shlobj.h>
00030 #else
00031 #include <unistd.h>
00032 #endif
00033
00034 #include "pg_config_paths.h"
00035
00036
00037 #ifndef WIN32
00038 #define IS_PATH_VAR_SEP(ch) ((ch) == ':')
00039 #else
00040 #define IS_PATH_VAR_SEP(ch) ((ch) == ';')
00041 #endif
00042
00043 static void make_relative_path(char *ret_path, const char *target_path,
00044 const char *bin_path, const char *my_exec_path);
00045 static void trim_directory(char *path);
00046 static void trim_trailing_separator(char *path);
00047
00048
00049
00050
00051
00052
00053
00054
00055 #ifdef WIN32
00056
00057 static char *
00058 skip_drive(const char *path)
00059 {
00060 if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
00061 {
00062 path += 2;
00063 while (*path && !IS_DIR_SEP(*path))
00064 path++;
00065 }
00066 else if (isalpha((unsigned char) path[0]) && path[1] == ':')
00067 {
00068 path += 2;
00069 }
00070 return (char *) path;
00071 }
00072 #else
00073
00074 #define skip_drive(path) (path)
00075 #endif
00076
00077
00078
00079
00080
00081
00082 bool
00083 has_drive_prefix(const char *path)
00084 {
00085 return skip_drive(path) != path;
00086 }
00087
00088
00089
00090
00091
00092
00093
00094 char *
00095 first_dir_separator(const char *filename)
00096 {
00097 const char *p;
00098
00099 for (p = skip_drive(filename); *p; p++)
00100 if (IS_DIR_SEP(*p))
00101 return (char *) p;
00102 return NULL;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111 char *
00112 first_path_var_separator(const char *pathlist)
00113 {
00114 const char *p;
00115
00116
00117 for (p = pathlist; *p; p++)
00118 if (IS_PATH_VAR_SEP(*p))
00119 return (char *) p;
00120 return NULL;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129 char *
00130 last_dir_separator(const char *filename)
00131 {
00132 const char *p,
00133 *ret = NULL;
00134
00135 for (p = skip_drive(filename); *p; p++)
00136 if (IS_DIR_SEP(*p))
00137 ret = p;
00138 return (char *) ret;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 void
00158 make_native_path(char *filename)
00159 {
00160 #ifdef WIN32
00161 char *p;
00162
00163 for (p = filename; *p; p++)
00164 if (*p == '/')
00165 *p = '\\';
00166 #endif
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 void
00180 join_path_components(char *ret_path,
00181 const char *head, const char *tail)
00182 {
00183 if (ret_path != head)
00184 strlcpy(ret_path, head, MAXPGPATH);
00185
00186
00187
00188
00189
00190
00191
00192 while (tail[0] == '.' && IS_DIR_SEP(tail[1]))
00193 tail += 2;
00194
00195 if (*tail)
00196 {
00197
00198 snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path),
00199 "%s%s",
00200 (*(skip_drive(head)) != '\0') ? "/" : "",
00201 tail);
00202 }
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 void
00216 canonicalize_path(char *path)
00217 {
00218 char *p,
00219 *to_p;
00220 char *spath;
00221 bool was_sep = false;
00222 int pending_strips;
00223
00224 #ifdef WIN32
00225
00226
00227
00228
00229
00230 for (p = path; *p; p++)
00231 {
00232 if (*p == '\\')
00233 *p = '/';
00234 }
00235
00236
00237
00238
00239
00240 if (p > path && *(p - 1) == '"')
00241 *(p - 1) = '/';
00242 #endif
00243
00244
00245
00246
00247
00248
00249 trim_trailing_separator(path);
00250
00251
00252
00253
00254 p = path;
00255 #ifdef WIN32
00256
00257 if (*p)
00258 p++;
00259 #endif
00260 to_p = p;
00261 for (; *p; p++, to_p++)
00262 {
00263
00264 while (*p == '/' && was_sep)
00265 p++;
00266 if (to_p != p)
00267 *to_p = *p;
00268 was_sep = (*p == '/');
00269 }
00270 *to_p = '\0';
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 spath = skip_drive(path);
00283 pending_strips = 0;
00284 for (;;)
00285 {
00286 int len = strlen(spath);
00287
00288 if (len >= 2 && strcmp(spath + len - 2, "/.") == 0)
00289 trim_directory(path);
00290 else if (strcmp(spath, ".") == 0)
00291 {
00292
00293 if (pending_strips > 0)
00294 *spath = '\0';
00295 break;
00296 }
00297 else if ((len >= 3 && strcmp(spath + len - 3, "/..") == 0) ||
00298 strcmp(spath, "..") == 0)
00299 {
00300 trim_directory(path);
00301 pending_strips++;
00302 }
00303 else if (pending_strips > 0 && *spath != '\0')
00304 {
00305
00306 trim_directory(path);
00307 pending_strips--;
00308
00309 if (*spath == '\0')
00310 strcpy(spath, ".");
00311 }
00312 else
00313 break;
00314 }
00315
00316 if (pending_strips > 0)
00317 {
00318
00319
00320
00321
00322
00323 while (--pending_strips > 0)
00324 strcat(path, "../");
00325 strcat(path, "..");
00326 }
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 bool
00338 path_contains_parent_reference(const char *path)
00339 {
00340 int path_len;
00341
00342 path = skip_drive(path);
00343
00344 path_len = strlen(path);
00345
00346
00347
00348
00349
00350 if (strcmp(path, "..") == 0 ||
00351 strncmp(path, "../", 3) == 0 ||
00352 strstr(path, "/../") != NULL ||
00353 (path_len >= 3 && strcmp(path + path_len - 3, "/..") == 0))
00354 return true;
00355
00356 return false;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366 bool
00367 path_is_relative_and_below_cwd(const char *path)
00368 {
00369 if (is_absolute_path(path))
00370 return false;
00371
00372 else if (path_contains_parent_reference(path))
00373 return false;
00374 #ifdef WIN32
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 else if (isalpha((unsigned char) path[0]) && path[1] == ':' &&
00386 !IS_DIR_SEP(path[2]))
00387 return false;
00388 #endif
00389 else
00390 return true;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 bool
00400 path_is_prefix_of_path(const char *path1, const char *path2)
00401 {
00402 int path1_len = strlen(path1);
00403
00404 if (strncmp(path1, path2, path1_len) == 0 &&
00405 (IS_DIR_SEP(path2[path1_len]) || path2[path1_len] == '\0'))
00406 return true;
00407 return false;
00408 }
00409
00410
00411
00412
00413
00414 const char *
00415 get_progname(const char *argv0)
00416 {
00417 const char *nodir_name;
00418 char *progname;
00419
00420 nodir_name = last_dir_separator(argv0);
00421 if (nodir_name)
00422 nodir_name++;
00423 else
00424 nodir_name = skip_drive(argv0);
00425
00426
00427
00428
00429
00430 progname = strdup(nodir_name);
00431 if (progname == NULL)
00432 {
00433 fprintf(stderr, "%s: out of memory\n", nodir_name);
00434 abort();
00435 }
00436
00437 #if defined(__CYGWIN__) || defined(WIN32)
00438
00439 if (strlen(progname) > sizeof(EXE) - 1 &&
00440 pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
00441 progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
00442 #endif
00443
00444 return progname;
00445 }
00446
00447
00448
00449
00450
00451
00452 static int
00453 dir_strcmp(const char *s1, const char *s2)
00454 {
00455 while (*s1 && *s2)
00456 {
00457 if (
00458 #ifndef WIN32
00459 *s1 != *s2
00460 #else
00461
00462 pg_tolower((unsigned char) *s1) != pg_tolower((unsigned char) *s2)
00463 #endif
00464 && !(IS_DIR_SEP(*s1) && IS_DIR_SEP(*s2)))
00465 return (int) *s1 - (int) *s2;
00466 s1++, s2++;
00467 }
00468 if (*s1)
00469 return 1;
00470 if (*s2)
00471 return -1;
00472 return 0;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 static void
00501 make_relative_path(char *ret_path, const char *target_path,
00502 const char *bin_path, const char *my_exec_path)
00503 {
00504 int prefix_len;
00505 int tail_start;
00506 int tail_len;
00507 int i;
00508
00509
00510
00511
00512
00513 prefix_len = 0;
00514 for (i = 0; target_path[i] && bin_path[i]; i++)
00515 {
00516 if (IS_DIR_SEP(target_path[i]) && IS_DIR_SEP(bin_path[i]))
00517 prefix_len = i + 1;
00518 else if (target_path[i] != bin_path[i])
00519 break;
00520 }
00521 if (prefix_len == 0)
00522 goto no_match;
00523 tail_len = strlen(bin_path) - prefix_len;
00524
00525
00526
00527
00528
00529 strlcpy(ret_path, my_exec_path, MAXPGPATH);
00530 trim_directory(ret_path);
00531 canonicalize_path(ret_path);
00532
00533
00534
00535
00536 tail_start = (int) strlen(ret_path) - tail_len;
00537 if (tail_start > 0 &&
00538 IS_DIR_SEP(ret_path[tail_start - 1]) &&
00539 dir_strcmp(ret_path + tail_start, bin_path + prefix_len) == 0)
00540 {
00541 ret_path[tail_start] = '\0';
00542 trim_trailing_separator(ret_path);
00543 join_path_components(ret_path, ret_path, target_path + prefix_len);
00544 canonicalize_path(ret_path);
00545 return;
00546 }
00547
00548 no_match:
00549 strlcpy(ret_path, target_path, MAXPGPATH);
00550 canonicalize_path(ret_path);
00551 }
00552
00553
00554
00555
00556
00557 void
00558 get_share_path(const char *my_exec_path, char *ret_path)
00559 {
00560 make_relative_path(ret_path, PGSHAREDIR, PGBINDIR, my_exec_path);
00561 }
00562
00563
00564
00565
00566 void
00567 get_etc_path(const char *my_exec_path, char *ret_path)
00568 {
00569 make_relative_path(ret_path, SYSCONFDIR, PGBINDIR, my_exec_path);
00570 }
00571
00572
00573
00574
00575 void
00576 get_include_path(const char *my_exec_path, char *ret_path)
00577 {
00578 make_relative_path(ret_path, INCLUDEDIR, PGBINDIR, my_exec_path);
00579 }
00580
00581
00582
00583
00584 void
00585 get_pkginclude_path(const char *my_exec_path, char *ret_path)
00586 {
00587 make_relative_path(ret_path, PKGINCLUDEDIR, PGBINDIR, my_exec_path);
00588 }
00589
00590
00591
00592
00593 void
00594 get_includeserver_path(const char *my_exec_path, char *ret_path)
00595 {
00596 make_relative_path(ret_path, INCLUDEDIRSERVER, PGBINDIR, my_exec_path);
00597 }
00598
00599
00600
00601
00602 void
00603 get_lib_path(const char *my_exec_path, char *ret_path)
00604 {
00605 make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path);
00606 }
00607
00608
00609
00610
00611 void
00612 get_pkglib_path(const char *my_exec_path, char *ret_path)
00613 {
00614 make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path);
00615 }
00616
00617
00618
00619
00620 void
00621 get_locale_path(const char *my_exec_path, char *ret_path)
00622 {
00623 make_relative_path(ret_path, LOCALEDIR, PGBINDIR, my_exec_path);
00624 }
00625
00626
00627
00628
00629 void
00630 get_doc_path(const char *my_exec_path, char *ret_path)
00631 {
00632 make_relative_path(ret_path, DOCDIR, PGBINDIR, my_exec_path);
00633 }
00634
00635
00636
00637
00638 void
00639 get_html_path(const char *my_exec_path, char *ret_path)
00640 {
00641 make_relative_path(ret_path, HTMLDIR, PGBINDIR, my_exec_path);
00642 }
00643
00644
00645
00646
00647 void
00648 get_man_path(const char *my_exec_path, char *ret_path)
00649 {
00650 make_relative_path(ret_path, MANDIR, PGBINDIR, my_exec_path);
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660 bool
00661 get_home_path(char *ret_path)
00662 {
00663 #ifndef WIN32
00664 char pwdbuf[BUFSIZ];
00665 struct passwd pwdstr;
00666 struct passwd *pwd = NULL;
00667
00668 if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0)
00669 return false;
00670 strlcpy(ret_path, pwd->pw_dir, MAXPGPATH);
00671 return true;
00672 #else
00673 char *tmppath;
00674
00675
00676
00677
00678
00679
00680 tmppath = getenv("APPDATA");
00681 if (!tmppath)
00682 return false;
00683 snprintf(ret_path, MAXPGPATH, "%s/postgresql", tmppath);
00684 return true;
00685 #endif
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 void
00705 get_parent_directory(char *path)
00706 {
00707 trim_directory(path);
00708 }
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 static void
00719 trim_directory(char *path)
00720 {
00721 char *p;
00722
00723 path = skip_drive(path);
00724
00725 if (path[0] == '\0')
00726 return;
00727
00728
00729 for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
00730 ;
00731
00732 for (; !IS_DIR_SEP(*p) && p > path; p--)
00733 ;
00734
00735 for (; p > path && IS_DIR_SEP(*(p - 1)); p--)
00736 ;
00737
00738 if (p == path && IS_DIR_SEP(*p))
00739 p++;
00740 *p = '\0';
00741 }
00742
00743
00744
00745
00746
00747
00748
00749 static void
00750 trim_trailing_separator(char *path)
00751 {
00752 char *p;
00753
00754 path = skip_drive(path);
00755 p = path + strlen(path);
00756 if (p > path)
00757 for (p--; p > path && IS_DIR_SEP(*p); p--)
00758 *p = '\0';
00759 }