nologin: make it possible to build it as single applet
[oweals/busybox.git] / libbb / xreadlink.c
index 7d4cb60a528f64b613a0aadf38afbd3a99b9bc4c..a18dd0748dd1793f16bce6eead9c5b3e34860930 100644 (file)
@@ -5,7 +5,6 @@
  *
  * Licensed under GPLv2, see file LICENSE in this source tree.
  */
-
 #include "libbb.h"
 
 /* Some systems (eg Hurd) do not have MAXSYMLINKS definition,
@@ -123,3 +122,62 @@ char* FAST_FUNC xmalloc_realpath(const char *path)
        return xstrdup(realpath(path, buf));
 #endif
 }
+
+char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
+{
+       char *buf;
+
+       errno = 0;
+       buf = xmalloc_realpath(path);
+       /*
+        * There is one case when "readlink -f" and
+        * "realpath" from coreutils succeed,
+        * even though file does not exist, such as:
+        *     /tmp/file_does_not_exist
+        * (the directory must exist).
+        */
+       if (!buf && errno == ENOENT) {
+               char *last_slash = strrchr(path, '/');
+               if (last_slash) {
+                       *last_slash++ = '\0';
+                       buf = xmalloc_realpath(path);
+                       if (buf) {
+                               unsigned len = strlen(buf);
+                               buf = xrealloc(buf, len + strlen(last_slash) + 2);
+                               buf[len++] = '/';
+                               strcpy(buf + len, last_slash);
+                       }
+               } else {
+                       char *target = xmalloc_readlink(path);
+                       if (target) {
+                               char *cwd;
+                               if (target[0] == '/') {
+                                       /*
+                                        * $ ln -s /bin/qwe symlink  # note: /bin is a link to /usr/bin
+                                        * $ readlink -f symlink
+                                        * /usr/bin/qwe/target_does_not_exist
+                                        * $ realpath symlink
+                                        * /usr/bin/qwe/target_does_not_exist
+                                        */
+                                       buf = xmalloc_realpath_coreutils(target);
+                                       free(target);
+                                       return buf;
+                               }
+                               /*
+                                * $ ln -s target_does_not_exist symlink
+                                * $ readlink -f symlink
+                                * /CURDIR/target_does_not_exist
+                                * $ realpath symlink
+                                * /CURDIR/target_does_not_exist
+                                */
+                               cwd = xrealloc_getcwd_or_warn(NULL);
+                               buf = concat_path_file(cwd, target);
+                               free(cwd);
+                               free(target);
+                               return buf;
+                       }
+               }
+       }
+
+       return buf;
+}