* resolve_symlinks - resolve symlinks to the underlying file * * Replace "path" by the absolute path to the referenced file. * * Returns 0 if OK, -1 if error. * * Note: we are not particularly tense about producing nice error messages * because we are not really expecting error here; we just determined that * the symlink does point to a valid executable. */
| 232 | * the symlink does point to a valid executable. |
| 233 | */ |
| 234 | static int |
| 235 | resolve_symlinks(char *path) |
| 236 | { |
| 237 | #ifdef HAVE_READLINK |
| 238 | struct stat buf; |
| 239 | char orig_wd[MAXPGPATH], |
| 240 | link_buf[MAXPGPATH]; |
| 241 | char *fname; |
| 242 | |
| 243 | /* |
| 244 | * To resolve a symlink properly, we have to chdir into its directory and |
| 245 | * then chdir to where the symlink points; otherwise we may fail to |
| 246 | * resolve relative links correctly (consider cases involving mount |
| 247 | * points, for example). After following the final symlink, we use |
| 248 | * getcwd() to figure out where the heck we're at. |
| 249 | * |
| 250 | * One might think we could skip all this if path doesn't point to a |
| 251 | * symlink to start with, but that's wrong. We also want to get rid of |
| 252 | * any directory symlinks that are present in the given path. We expect |
| 253 | * getcwd() to give us an accurate, symlink-free path. |
| 254 | */ |
| 255 | if (!getcwd(orig_wd, MAXPGPATH)) |
| 256 | { |
| 257 | log_error(errcode_for_file_access(), |
| 258 | _("could not identify current directory: %m")); |
| 259 | return -1; |
| 260 | } |
| 261 | |
| 262 | for (;;) |
| 263 | { |
| 264 | char *lsep; |
| 265 | int rllen; |
| 266 | |
| 267 | lsep = last_dir_separator(path); |
| 268 | if (lsep) |
| 269 | { |
| 270 | *lsep = '\0'; |
| 271 | if (chdir(path) == -1) |
| 272 | { |
| 273 | log_error(errcode_for_file_access(), |
| 274 | _("could not change directory to \"%s\": %m"), path); |
| 275 | return -1; |
| 276 | } |
| 277 | fname = lsep + 1; |
| 278 | } |
| 279 | else |
| 280 | fname = path; |
| 281 | |
| 282 | if (lstat(fname, &buf) < 0 || |
| 283 | !S_ISLNK(buf.st_mode)) |
| 284 | break; |
| 285 | |
| 286 | errno = 0; |
| 287 | rllen = readlink(fname, link_buf, sizeof(link_buf)); |
| 288 | if (rllen < 0 || rllen >= sizeof(link_buf)) |
| 289 | { |
| 290 | log_error(errcode_for_file_access(), |
| 291 | _("could not read symbolic link \"%s\": %m"), fname); |
no test coverage detected