xref: /petsc/src/sys/fileio/grpath.c (revision 6dd63270497ad23dcf16ae500a87ff2b2a0b7474)
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>
18 
19 /*@C
20   PetscGetRealPath - Get the path without symbolic links etc. in absolute form.
21 
22   Not Collective
23 
24   Input Parameter:
25 . path - path to resolve
26 
27   Output Parameter:
28 . rpath - resolved path
29 
30   Level: developer
31 
32   Notes:
33   `rpath` is assumed to be of length `PETSC_MAX_PATH_LEN`.
34 
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.
40 
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;
51 
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
99 
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;
105 
106     PetscCall(PetscStrncmp(garbage, rpath, garbage_len, &flg));
107     if (flg) {
108       const size_t no_slash_len = garbage_len - 1; // 8
109 
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 }
119