df: Add --uuid option to print guest UUIDs instead of names (RHBZ#646821).
[libguestfs.git] / daemon / link.c
index 57e3538..3766d8c 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
 
 #include "actions.h"
 
 char *
-do_readlink (char *path)
+do_readlink (const char *path)
 {
   ssize_t r;
   char *ret;
   char link[PATH_MAX];
 
-  NEED_ROOT (NULL);
-  ABS_PATH (path, NULL);
-
   CHROOT_IN;
   r = readlink (path, link, sizeof link);
   CHROOT_OUT;
@@ -54,6 +52,56 @@ do_readlink (char *path)
   return ret;                  /* caller frees */
 }
 
+char **
+do_readlinklist (const char *path, char *const *names)
+{
+  int fd_cwd;
+  size_t i;
+  ssize_t r;
+  char link[PATH_MAX];
+  const char *str;
+  char **ret = NULL;
+  int size = 0, alloc = 0;
+
+  CHROOT_IN;
+  fd_cwd = open (path, O_RDONLY | O_DIRECTORY);
+  CHROOT_OUT;
+
+  if (fd_cwd == -1) {
+    reply_with_perror ("open: %s", path);
+    return NULL;
+  }
+
+  for (i = 0; names[i] != NULL; ++i) {
+    r = readlinkat (fd_cwd, names[i], link, sizeof link);
+    if (r >= PATH_MAX) {
+      reply_with_perror ("readlinkat: returned link is too long");
+      free_strings (ret);
+      close (fd_cwd);
+      return NULL;
+    }
+    /* Because of the way this function is intended to be used,
+     * we actually expect to see errors here, and they are not fatal.
+     */
+    if (r >= 0) {
+      link[r] = '\0';
+      str = link;
+    } else
+      str = "";
+    if (add_string (&ret, &size, &alloc, str) == -1) {
+      close (fd_cwd);
+      return NULL;
+    }
+  }
+
+  close (fd_cwd);
+
+  if (add_string (&ret, &size, &alloc, NULL) == -1)
+    return NULL;
+
+  return ret;
+}
+
 static int
 _link (const char *flag, int symbolic, const char *target, const char *linkname)
 {
@@ -62,10 +110,6 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
   char *buf_linkname;
   char *buf_target;
 
-  NEED_ROOT (-1);
-  ABS_PATH (linkname, -1);
-  /* but target does not need to be absolute */
-
   /* Prefix linkname with sysroot. */
   buf_linkname = sysroot_path (linkname);
   if (!buf_linkname) {
@@ -90,19 +134,19 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
 
   if (flag)
     r = command (NULL, &err,
-                "ln", flag, "--", /* target could begin with '-' */
-                buf_target ? : target, buf_linkname, NULL);
+                 "ln", flag, "--", /* target could begin with '-' */
+                 buf_target ? : target, buf_linkname, NULL);
   else
     r = command (NULL, &err,
-                "ln", "--",
-                buf_target ? : target, buf_linkname, NULL);
+                 "ln", "--",
+                 buf_target ? : target, buf_linkname, NULL);
   free (buf_linkname);
   free (buf_target);
   if (r == -1) {
     reply_with_error ("ln%s%s: %s: %s: %s",
-                     flag ? " " : "",
-                     flag ? : "",
-                     target, linkname, err);
+                      flag ? " " : "",
+                      flag ? : "",
+                      target, linkname, err);
     free (err);
     return -1;
   }
@@ -113,25 +157,25 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
 }
 
 int
-do_ln (char *target, char *linkname)
+do_ln (const char *target, const char *linkname)
 {
   return _link (NULL, 0, target, linkname);
 }
 
 int
-do_ln_f (char *target, char *linkname)
+do_ln_f (const char *target, const char *linkname)
 {
   return _link ("-f", 0, target, linkname);
 }
 
 int
-do_ln_s (char *target, char *linkname)
+do_ln_s (const char *target, const char *linkname)
 {
   return _link ("-s", 1, target, linkname);
 }
 
 int
-do_ln_sf (char *target, char *linkname)
+do_ln_sf (const char *target, const char *linkname)
 {
   return _link ("-sf", 1, target, linkname);
 }