Actual source code: grpath.c

  1: #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for realpath() */
  2: #include <petscsys.h>
  3: #if defined(PETSC_HAVE_PWD_H)
  4:   #include <pwd.h>
  5: #endif
  6: #include <ctype.h>
  7: #include <sys/stat.h>
  8: #if defined(PETSC_HAVE_UNISTD_H)
  9:   #include <unistd.h>
 10: #endif
 11: #if defined(PETSC_HAVE_SYS_UTSNAME_H)
 12:   #include <sys/utsname.h>
 13: #endif
 14: #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
 15:   #include <sys/systeminfo.h>
 16: #endif
 17: #include <errno.h>

 19: /*@C
 20:   PetscGetRealPath - Get the path without symbolic links etc. in absolute form.

 22:   Not Collective

 24:   Input Parameter:
 25: . path - path to resolve

 27:   Output Parameter:
 28: . rpath - resolved path

 30:   Level: developer

 32:   Notes:
 33:   rpath is assumed to be of length `PETSC_MAX_PATH_LEN`.

 35:   Systems that use the automounter often generate absolute paths
 36:   of the form "/tmp_mnt....".  However, the automounter will fail to
 37:   mount this path if it is not already mounted, so we remove this from
 38:   the head of the line.  This may cause problems if, for some reason,
 39:   /tmp_mnt is valid and not the result of the automounter.

 41: .seealso: `PetscGetFullPath()`
 42: @*/
 43: PetscErrorCode PetscGetRealPath(const char path[], char rpath[])
 44: {
 45: #if !defined(PETSC_HAVE_REALPATH) && defined(PETSC_HAVE_READLINK)
 46:   char tmp1[PETSC_MAX_PATH_LEN], char tmp3[PETSC_MAX_PATH_LEN], tmp4[PETSC_MAX_PATH_LEN], *tmp2;
 47:   size_t N, len1, len2;
 48:   int    n, m;
 49: #endif
 50:   size_t len;

 52:   PetscFunctionBegin;
 53: #if defined(PETSC_HAVE_REALPATH)
 54:   PetscCheck(realpath(path, rpath), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in realpath() due to \"%s\"", strerror(errno));
 55: #else
 56:   #if defined(PETSC_HAVE_READLINK)
 57:   /* Algorithm: we move through the path, replacing links with the real paths.   */
 58:   PetscCall(PetscStrlen(path, &N));
 59:   PetscCall(PetscStrncpy(rpath, path, N + 1)); /* assuming adequate buffer */
 60:   PetscCall(PetscStrlen(rpath, &N));
 61:   while (N) {
 62:     PetscCall(PetscStrncpy(tmp1, rpath, N));
 63:     tmp1[N] = 0;
 64:     n       = readlink(tmp1, tmp3, PETSC_MAX_PATH_LEN);
 65:     PetscCheck(n > -1, PETSC_COMM_SELF, PETSC_ERR_SYS, "Error in readlink() due to \"%\"", strerror(errno));
 66:     if (n > 0) {
 67:       tmp3[n] = 0; /* readlink does not automatically add 0 to string end */
 68:       if (tmp3[0] != '/') {
 69:         PetscCall(PetscStrchr(tmp1, '/', &tmp2));
 70:         PetscCall(PetscStrlen(tmp1, &len1));
 71:         PetscCall(PetscStrlen(tmp2, &len2));
 72:         m = len1 - len2;
 73:         PetscCall(PetscStrncpy(tmp4, tmp1, m));
 74:         tmp4[m] = 0;
 75:         PetscCall(PetscStrlen(tmp4, &len));
 76:         PetscCall(PetscStrlcat(tmp4, "/", PETSC_MAX_PATH_LEN));
 77:         PetscCall(PetscStrlcat(tmp4, tmp3, PETSC_MAX_PATH_LEN));
 78:         PetscCall(PetscGetRealPath(tmp4, rpath));
 79:         PetscCall(PetscStrlcat(rpath, path + N, PETSC_MAX_PATH_LEN));
 80:       } else {
 81:         PetscCall(PetscGetRealPath(tmp3, tmp1));
 82:         PetscCall(PetscStrncpy(rpath, tmp1, PETSC_MAX_PATH_LEN));
 83:         PetscCall(PetscStrlcat(rpath, path + N, PETSC_MAX_PATH_LEN));
 84:       }
 85:       PetscFunctionReturn(PETSC_SUCCESS);
 86:     }
 87:     PetscCall(PetscStrchr(tmp1, '/', &tmp2));
 88:     if (tmp2) {
 89:       PetscCall(PetscStrlen(tmp1, &len1));
 90:       PetscCall(PetscStrlen(tmp2, &len2));
 91:       N = len1 - len2;
 92:     } else {
 93:       PetscCall(PetscStrlen(tmp1, &N));
 94:     }
 95:   }
 96:   #endif
 97:   PetscCall(PetscStrncpy(rpath, path, PETSC_MAX_PATH_LEN)); /* assuming adequate buffer */
 98: #endif

100:   /* remove garbage some automounters put at the beginning of the path */
101:   {
102:     const char   garbage[]   = "/tmp_mnt/";
103:     const size_t garbage_len = sizeof(garbage) - 1; // 9
104:     PetscBool    flg;

106:     PetscCall(PetscStrncmp(garbage, rpath, garbage_len, &flg));
107:     if (flg) {
108:       const size_t no_slash_len = garbage_len - 1; // 8

110:       PetscCall(PetscStrlen(rpath, &len));
111:       // shift the array left by no_slash_len
112:       PetscCall(PetscArraymove(rpath, rpath + no_slash_len, len - no_slash_len));
113:       // zero out the end we just moved from
114:       PetscCall(PetscArrayzero(rpath + len - no_slash_len, no_slash_len));
115:     }
116:   }
117:   PetscFunctionReturn(PETSC_SUCCESS);
118: }