/* libguestfs - the guestfsd daemon
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <stdio.h>
#include <unistd.h>
-#include "../src/guestfs_protocol.h"
+#include "guestfs_protocol.h"
#include "daemon.h"
#include "actions.h"
+#include "optgroups.h"
#if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
-#ifdef HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#else
-#ifdef HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#endif
-#endif
+# ifdef HAVE_ATTR_XATTR_H
+# include <attr/xattr.h>
+# else
+# ifdef HAVE_SYS_XATTR_H
+# include <sys/xattr.h>
+# endif
+# endif
+
+int
+optgroup_linuxxattrs_available (void)
+{
+ return 1;
+}
static guestfs_int_xattr_list *getxattrs (const char *path, ssize_t (*listxattr) (const char *path, char *list, size_t size), ssize_t (*getxattr) (const char *path, const char *name, void *value, size_t size));
static int _setxattr (const char *xattr, const char *val, int vallen, const char *path, int (*setxattr) (const char *path, const char *name, const void *value, size_t size, int flags));
#if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
return getxattrs (path, listxattr, getxattr);
#else
- reply_with_error ("getxattrs: no support for listxattr and getxattr");
+ reply_with_error ("no support for listxattr and getxattr");
return NULL;
#endif
}
#if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
return getxattrs (path, llistxattr, lgetxattr);
#else
- reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr");
+ reply_with_error ("no support for llistxattr and lgetxattr");
return NULL;
#endif
}
#if defined(HAVE_SETXATTR)
return _setxattr (xattr, val, vallen, path, setxattr);
#else
- reply_with_error ("setxattr: no support for setxattr");
+ reply_with_error ("no support for setxattr");
return -1;
#endif
}
#if defined(HAVE_LSETXATTR)
return _setxattr (xattr, val, vallen, path, lsetxattr);
#else
- reply_with_error ("lsetxattr: no support for lsetxattr");
+ reply_with_error ("no support for lsetxattr");
return -1;
#endif
}
#if defined(HAVE_REMOVEXATTR)
return _removexattr (xattr, path, removexattr);
#else
- reply_with_error ("removexattr: no support for removexattr");
+ reply_with_error ("no support for removexattr");
return -1;
#endif
}
#if defined(HAVE_LREMOVEXATTR)
return _removexattr (xattr, path, lremovexattr);
#else
- reply_with_error ("lremovexattr: no support for lremovexattr");
+ reply_with_error ("no support for lremovexattr");
return -1;
#endif
}
len = listxattr (path, NULL, 0);
CHROOT_OUT;
if (len == -1) {
- reply_with_perror ("listxattr");
+ reply_with_perror ("listxattr: %s", path);
goto error;
}
len = listxattr (path, buf, len);
CHROOT_OUT;
if (len == -1) {
- reply_with_perror ("listxattr");
+ reply_with_perror ("listxattr: %s", path);
goto error;
}
return 0;
}
+guestfs_int_xattr_list *
+do_lxattrlist (const char *path, char *const *names)
+{
+#if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
+ /* XXX This would be easier if the kernel had lgetxattrat. In the
+ * meantime we use this buffer to store the whole path name.
+ */
+ char pathname[PATH_MAX];
+ size_t path_len = strlen (path);
+ guestfs_int_xattr_list *ret = NULL;
+ int i, j;
+ size_t k, m, nr_attrs;
+ ssize_t len, vlen;
+ char *buf = NULL;
+
+ if (path_len >= PATH_MAX) {
+ reply_with_perror ("path longer than PATH_MAX");
+ goto error;
+ }
+
+ strcpy (pathname, path);
+
+ ret = malloc (sizeof (*ret));
+ if (ret == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ ret->guestfs_int_xattr_list_len = 0;
+ ret->guestfs_int_xattr_list_val = NULL;
+
+ for (k = 0; names[k] != NULL; ++k) {
+ /* Be careful in here about which errors cause the whole call
+ * to abort, and which errors allow us to continue processing
+ * the call, recording a special "error attribute" in the
+ * outgoing struct list.
+ */
+ if (path_len + strlen (names[k]) + 2 > PATH_MAX) {
+ reply_with_perror ("path and name longer than PATH_MAX");
+ goto error;
+ }
+ pathname[path_len] = '/';
+ strcpy (&pathname[path_len+1], names[k]);
+
+ /* Reserve space for the special attribute. */
+ void *newptr =
+ realloc (ret->guestfs_int_xattr_list_val,
+ (ret->guestfs_int_xattr_list_len+1)*sizeof (guestfs_int_xattr));
+ if (newptr == NULL) {
+ reply_with_perror ("realloc");
+ goto error;
+ }
+ ret->guestfs_int_xattr_list_val = newptr;
+ ret->guestfs_int_xattr_list_len++;
+
+ guestfs_int_xattr *entry =
+ &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-1];
+ entry->attrname = NULL;
+ entry->attrval.attrval_len = 0;
+ entry->attrval.attrval_val = NULL;
+
+ entry->attrname = strdup ("");
+ if (entry->attrname == NULL) {
+ reply_with_perror ("strdup");
+ goto error;
+ }
+
+ CHROOT_IN;
+ len = llistxattr (pathname, NULL, 0);
+ CHROOT_OUT;
+ if (len == -1)
+ continue; /* not fatal */
+
+ buf = malloc (len);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ CHROOT_IN;
+ len = llistxattr (pathname, buf, len);
+ CHROOT_OUT;
+ if (len == -1)
+ continue; /* not fatal */
+
+ /* What we get from the kernel is a string "foo\0bar\0baz" of length
+ * len. First count the strings.
+ */
+ nr_attrs = 0;
+ for (i = 0; i < len; i += strlen (&buf[i]) + 1)
+ nr_attrs++;
+
+ newptr =
+ realloc (ret->guestfs_int_xattr_list_val,
+ (ret->guestfs_int_xattr_list_len+nr_attrs) *
+ sizeof (guestfs_int_xattr));
+ if (newptr == NULL) {
+ reply_with_perror ("realloc");
+ goto error;
+ }
+ ret->guestfs_int_xattr_list_val = newptr;
+ ret->guestfs_int_xattr_list_len += nr_attrs;
+
+ /* entry[0] is the special attribute,
+ * entry[1..nr_attrs] are the attributes.
+ */
+ entry = &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-nr_attrs-1];
+ for (m = 1; m <= nr_attrs; ++m) {
+ entry[m].attrname = NULL;
+ entry[m].attrval.attrval_len = 0;
+ entry[m].attrval.attrval_val = NULL;
+ }
+
+ for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
+ CHROOT_IN;
+ vlen = lgetxattr (pathname, &buf[i], NULL, 0);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr");
+ goto error;
+ }
+
+ entry[j+1].attrname = strdup (&buf[i]);
+ entry[j+1].attrval.attrval_val = malloc (vlen);
+ entry[j+1].attrval.attrval_len = vlen;
+
+ if (entry[j+1].attrname == NULL ||
+ entry[j+1].attrval.attrval_val == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ CHROOT_IN;
+ vlen = lgetxattr (pathname, &buf[i],
+ entry[j+1].attrval.attrval_val, vlen);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr");
+ goto error;
+ }
+ }
+
+ free (buf); buf = NULL;
+
+ char num[16];
+ snprintf (num, sizeof num, "%zu", nr_attrs);
+ entry[0].attrval.attrval_len = strlen (num) + 1;
+ entry[0].attrval.attrval_val = strdup (num);
+
+ if (entry[0].attrval.attrval_val == NULL) {
+ reply_with_perror ("strdup");
+ goto error;
+ }
+ }
+
+ return ret;
+
+ error:
+ free (buf);
+ if (ret) {
+ if (ret->guestfs_int_xattr_list_val) {
+ for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
+ free (ret->guestfs_int_xattr_list_val[k].attrname);
+ free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val);
+ }
+ free (ret->guestfs_int_xattr_list_val);
+ }
+ free (ret);
+ }
+ return NULL;
+#else
+ reply_with_error ("no support for llistxattr and lgetxattr");
+ return NULL;
+#endif
+}
+
+char *
+do_getxattr (const char *path, const char *name, size_t *size_r)
+{
+ ssize_t r;
+ char *buf;
+ size_t len;
+
+ CHROOT_IN;
+ r = getxattr (path, name, NULL, 0);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("getxattr");
+ return NULL;
+ }
+
+ len = r;
+ buf = malloc (len);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ CHROOT_IN;
+ r = getxattr (path, name, buf, len);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("getxattr");
+ free (buf);
+ return NULL;
+ }
+
+ if (len != (size_t) r) {
+ reply_with_error ("getxattr: unexpected size (%zu/%zd)", len, r);
+ free (buf);
+ return NULL;
+ }
+
+ /* Must set size_r last thing before returning. */
+ *size_r = len;
+ return buf; /* caller frees */
+}
+
+char *
+do_lgetxattr (const char *path, const char *name, size_t *size_r)
+{
+ ssize_t r;
+ char *buf;
+ size_t len;
+
+ CHROOT_IN;
+ r = lgetxattr (path, name, NULL, 0);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("lgetxattr");
+ return NULL;
+ }
+
+ len = r;
+ buf = malloc (len);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ CHROOT_IN;
+ r = lgetxattr (path, name, buf, len);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("lgetxattr");
+ free (buf);
+ return NULL;
+ }
+
+ if (len != (size_t) r) {
+ reply_with_error ("lgetxattr: unexpected size (%zu/%zd)", len, r);
+ free (buf);
+ return NULL;
+ }
+
+ /* Must set size_r last thing before returning. */
+ *size_r = len;
+ return buf; /* caller frees */
+}
+
#else /* no xattr.h */
+int
+optgroup_linuxxattrs_available (void)
+{
+ return 0;
+}
guestfs_int_xattr_list *
do_getxattrs (const char *path)
{
- reply_with_error ("getxattrs: no support for xattrs");
- return NULL;
+ NOT_AVAILABLE (NULL);
}
guestfs_int_xattr_list *
do_lgetxattrs (const char *path)
{
- reply_with_error ("lgetxattrs: no support for xattrs");
- return NULL;
+ NOT_AVAILABLE (NULL);
}
int
do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
{
- reply_with_error ("setxattr: no support for xattrs");
- return -1;
+ NOT_AVAILABLE (-1);
}
int
do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
{
- reply_with_error ("lsetxattr: no support for xattrs");
- return -1;
+ NOT_AVAILABLE (-1);
}
int
do_removexattr (const char *xattr, const char *path)
{
- reply_with_error ("removexattr: no support for xattrs");
- return -1;
+ NOT_AVAILABLE (-1);
}
int
do_lremovexattr (const char *xattr, const char *path)
{
- reply_with_error ("lremovexattr: no support for xattrs");
- return -1;
+ NOT_AVAILABLE (-1);
+}
+
+guestfs_int_xattr_list *
+do_lxattrlist (const char *path, char *const *names)
+{
+ NOT_AVAILABLE (NULL);
+}
+
+char *
+do_getxattr (const char *path, const char *name, size_t *size_r)
+{
+ NOT_AVAILABLE (NULL);
+}
+
+char *
+do_lgetxattr (const char *path, const char *name, size_t *size_r)
+{
+ NOT_AVAILABLE (NULL);
}
#endif /* no xattr.h */