xref: /petsc/src/sys/fileio/grpath.c (revision 0226ec35a99031c5bdd82a492055a25793359ffb)
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 
18 /*@C
19    PetscGetRealPath - Get the path without symbolic links etc. and in absolute form.
20 
21    Not Collective
22 
23    Input Parameter:
24 .  path - path to resolve
25 
26    Output Parameter:
27 .  rpath - resolved path
28 
29    Level: developer
30 
31    Notes:
32    rpath is assumed to be of length `PETSC_MAX_PATH_LEN`.
33 
34    Systems that use the automounter often generate absolute paths
35    of the form "/tmp_mnt....".  However, the automounter will fail to
36    mount this path if it is not already mounted, so we remove this from
37    the head of the line.  This may cause problems if, for some reason,
38    /tmp_mnt is valid and not the result of the automounter.
39 
40 .seealso: `PetscGetFullPath()`
41 @*/
42 PetscErrorCode PetscGetRealPath(const char path[], char rpath[])
43 {
44 #if !defined(PETSC_HAVE_REALPATH) && defined(PETSC_HAVE_READLINK)
45   char tmp1[PETSC_MAX_PATH_LEN], char tmp3[PETSC_MAX_PATH_LEN], tmp4[PETSC_MAX_PATH_LEN], *tmp2;
46   size_t N, len1, len2;
47   int    n, m;
48 #endif
49   size_t len;
50 
51   PetscFunctionBegin;
52 #if defined(PETSC_HAVE_REALPATH)
53   PetscCheck(realpath(path, rpath), PETSC_COMM_SELF, PETSC_ERR_LIB, "realpath()");
54 #else
55   #if defined(PETSC_HAVE_READLINK)
56   /* Algorithm: we move through the path, replacing links with the real paths.   */
57   PetscCall(PetscStrlen(path, &N));
58   PetscCall(PetscStrncpy(rpath, path, N + 1)); /* assuming adequate buffer */
59   PetscCall(PetscStrlen(rpath, &N));
60   while (N) {
61     PetscCall(PetscStrncpy(tmp1, rpath, N));
62     tmp1[N] = 0;
63     n       = readlink(tmp1, tmp3, PETSC_MAX_PATH_LEN);
64     if (n > 0) {
65       tmp3[n] = 0; /* readlink does not automatically add 0 to string end */
66       if (tmp3[0] != '/') {
67         PetscCall(PetscStrchr(tmp1, '/', &tmp2));
68         PetscCall(PetscStrlen(tmp1, &len1));
69         PetscCall(PetscStrlen(tmp2, &len2));
70         m = len1 - len2;
71         PetscCall(PetscStrncpy(tmp4, tmp1, m));
72         tmp4[m] = 0;
73         PetscCall(PetscStrlen(tmp4, &len));
74         PetscCall(PetscStrlcat(tmp4, "/", PETSC_MAX_PATH_LEN));
75         PetscCall(PetscStrlcat(tmp4, tmp3, PETSC_MAX_PATH_LEN));
76         PetscCall(PetscGetRealPath(tmp4, rpath));
77         PetscCall(PetscStrlcat(rpath, path + N, PETSC_MAX_PATH_LEN));
78       } else {
79         PetscCall(PetscGetRealPath(tmp3, tmp1));
80         PetscCall(PetscStrncpy(rpath, tmp1, PETSC_MAX_PATH_LEN));
81         PetscCall(PetscStrlcat(rpath, path + N, PETSC_MAX_PATH_LEN));
82       }
83       PetscFunctionReturn(PETSC_SUCCESS);
84     }
85     PetscCall(PetscStrchr(tmp1, '/', &tmp2));
86     if (tmp2) {
87       PetscCall(PetscStrlen(tmp1, &len1));
88       PetscCall(PetscStrlen(tmp2, &len2));
89       N = len1 - len2;
90     } else {
91       PetscCall(PetscStrlen(tmp1, &N));
92     }
93   }
94   #endif
95   PetscCall(PetscStrncpy(rpath, path, PETSC_MAX_PATH_LEN)); /* assuming adequate buffer */
96 #endif
97 
98   /* remove garbage some automounters put at the beginning of the path */
99   {
100     const char   garbage[]   = "/tmp_mnt/";
101     const size_t garbage_len = sizeof(garbage) - 1; // 9
102     PetscBool    flg;
103 
104     PetscCall(PetscStrncmp(garbage, rpath, garbage_len, &flg));
105     if (flg) {
106       const size_t no_slash_len = garbage_len - 1; // 8
107 
108       PetscCall(PetscStrlen(rpath, &len));
109       // shift the array left by no_slash_len
110       PetscCall(PetscArraymove(rpath, rpath + no_slash_len, len - no_slash_len));
111       // zero out the end we just moved from
112       PetscCall(PetscArrayzero(rpath + len - no_slash_len, no_slash_len));
113     }
114   }
115   PetscFunctionReturn(PETSC_SUCCESS);
116 }
117