--- /dev/null
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+
+#include "../src/guestfs_protocol.h"
+#include "daemon.h"
+#include "actions.h"
+
+static guestfs_int_xattr_list *getxattrs (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 (char *xattr, char *val, int vallen, char *path, int (*setxattr) (const char *path, const char *name, const void *value, size_t size, int flags));
+static int _removexattr (char *xattr, char *path, int (*removexattr) (const char *path, const char *name));
+
+guestfs_int_xattr_list *
+do_getxattrs (char *path)
+{
+#if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
+ return getxattrs (path, listxattr, getxattr);
+#else
+ reply_with_error ("getxattrs: no support for listxattr and getxattr");
+ return NULL;
+#endif
+}
+
+guestfs_int_xattr_list *
+do_lgetxattrs (char *path)
+{
+#if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
+ return getxattrs (path, llistxattr, lgetxattr);
+#else
+ reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr");
+ return NULL;
+#endif
+}
+
+int
+do_setxattr (char *xattr, char *val, int vallen, char *path)
+{
+#if defined(HAVE_SETXATTR)
+ return _setxattr (xattr, val, vallen, path, setxattr);
+#else
+ reply_with_error ("setxattr: no support for setxattr");
+ return -1;
+#endif
+}
+
+int
+do_lsetxattr (char *xattr, char *val, int vallen, char *path)
+{
+#if defined(HAVE_LSETXATTR)
+ return _setxattr (xattr, val, vallen, path, lsetxattr);
+#else
+ reply_with_error ("lsetxattr: no support for lsetxattr");
+ return -1;
+#endif
+}
+
+int
+do_removexattr (char *xattr, char *path)
+{
+#if defined(HAVE_REMOVEXATTR)
+ return _removexattr (xattr, path, removexattr);
+#else
+ reply_with_error ("removexattr: no support for removexattr");
+ return -1;
+#endif
+}
+
+int
+do_lremovexattr (char *xattr, char *path)
+{
+#if defined(HAVE_LREMOVEXATTR)
+ return _removexattr (xattr, path, lremovexattr);
+#else
+ reply_with_error ("lremovexattr: no support for lremovexattr");
+ return -1;
+#endif
+}
+
+static guestfs_int_xattr_list *
+getxattrs (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))
+{
+ ssize_t len, vlen;
+ char *buf = NULL;
+ int i, j;
+ guestfs_int_xattr_list *r = NULL;
+
+ NEED_ROOT (NULL);
+ ABS_PATH (path, NULL);
+
+ CHROOT_IN;
+ len = listxattr (path, NULL, 0);
+ CHROOT_OUT;
+ if (len == -1) {
+ reply_with_perror ("listxattr");
+ goto error;
+ }
+
+ buf = malloc (len);
+ if (buf == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ CHROOT_IN;
+ len = listxattr (path, buf, len);
+ CHROOT_OUT;
+ if (len == -1) {
+ reply_with_perror ("listxattr");
+ goto error;
+ }
+
+ r = calloc (1, sizeof (*r));
+ if (r == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ /* What we get from the kernel is a string "foo\0bar\0baz" of length
+ * len. First count the strings.
+ */
+ r->guestfs_int_xattr_list_len = 0;
+ for (i = 0; i < len; i += strlen (&buf[i]) + 1)
+ r->guestfs_int_xattr_list_len++;
+
+ r->guestfs_int_xattr_list_val =
+ calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
+ if (r->guestfs_int_xattr_list_val == NULL) {
+ reply_with_perror ("calloc");
+ goto error;
+ }
+
+ for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
+ CHROOT_IN;
+ vlen = getxattr (path, &buf[i], NULL, 0);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr");
+ goto error;
+ }
+
+ r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
+ r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
+ r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
+
+ if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
+ r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
+ reply_with_perror ("malloc");
+ goto error;
+ }
+
+ CHROOT_IN;
+ vlen = getxattr (path, &buf[i],
+ r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
+ vlen);
+ CHROOT_OUT;
+ if (vlen == -1) {
+ reply_with_perror ("getxattr");
+ goto error;
+ }
+ }
+
+ free (buf);
+
+ return r;
+
+ error:
+ free (buf);
+ if (r) {
+ if (r->guestfs_int_xattr_list_val)
+ for (i = 0; i < r->guestfs_int_xattr_list_len; ++i) {
+ free (r->guestfs_int_xattr_list_val[i].attrname);
+ free (r->guestfs_int_xattr_list_val[i].attrval.attrval_val);
+ }
+ free (r->guestfs_int_xattr_list_val);
+ }
+ free (r);
+ return NULL;
+}
+
+static int
+_setxattr (char *xattr, char *val, int vallen, char *path,
+ int (*setxattr) (const char *path, const char *name,
+ const void *value, size_t size, int flags))
+{
+ int r;
+
+ CHROOT_IN;
+ r = setxattr (path, xattr, val, vallen, 0);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("setxattr");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+_removexattr (char *xattr, char *path,
+ int (*removexattr) (const char *path, const char *name))
+{
+ int r;
+
+ CHROOT_IN;
+ r = removexattr (path, xattr);
+ CHROOT_OUT;
+ if (r == -1) {
+ reply_with_perror ("removexattr");
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* !HAVE_ATTR_XATTR_H */
+
+guestfs_int_xattr_list *
+do_getxattrs (char *path)
+{
+ reply_with_error ("getxattrs: no support for xattrs");
+ return NULL;
+}
+
+guestfs_int_xattr_list *
+do_lgetxattrs (char *path)
+{
+ reply_with_error ("lgetxattrs: no support for xattrs");
+ return NULL;
+}
+
+int
+do_setxattr (char *xattr, char *val, int vallen, char *path)
+{
+ reply_with_error ("setxattr: no support for xattrs");
+ return -1;
+}
+
+int
+do_lsetxattr (char *xattr, char *val, int vallen, char *path)
+{
+ reply_with_error ("lsetxattr: no support for xattrs");
+ return -1;
+}
+
+int
+do_removexattr (char *xattr, char *path)
+{
+ reply_with_error ("removexattr: no support for xattrs");
+ return -1;
+}
+
+int
+do_lremovexattr (char *xattr, char *path)
+{
+ reply_with_error ("lremovexattr: no support for xattrs");
+ return -1;
+}
+
+#endif /* !HAVE_ATTR_XATTR_H */
See also: C<guestfs_file>");
+ ("getxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 141, [],
+ [],
+ "list extended attributes of a file or directory",
+ "\
+This call lists the extended attributes of the file or directory
+C<path>.
+
+At the system call level, this is a combination of the
+L<listxattr(2)> and L<getxattr(2)> calls.
+
+See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
+
+ ("lgetxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 142, [],
+ [],
+ "list extended attributes of a file or directory",
+ "\
+This is the same as C<guestfs_getxattrs>, but if C<path>
+is a symbolic link, then it returns the extended attributes
+of the link itself.");
+
+ ("setxattr", (RErr, [String "xattr";
+ String "val"; Int "vallen"; (* will be BufferIn *)
+ String "path"]), 143, [],
+ [],
+ "set extended attribute of a file or directory",
+ "\
+This call sets the extended attribute named C<xattr>
+of the file C<path> to the value C<val> (of length C<vallen>).
+The value is arbitrary 8 bit data.
+
+See also: C<guestfs_lsetxattr>, L<attr(5)>.");
+
+ ("lsetxattr", (RErr, [String "xattr";
+ String "val"; Int "vallen"; (* will be BufferIn *)
+ String "path"]), 144, [],
+ [],
+ "set extended attribute of a file or directory",
+ "\
+This is the same as C<guestfs_setxattr>, but if C<path>
+is a symbolic link, then it sets an extended attribute
+of the link itself.");
+
+ ("removexattr", (RErr, [String "xattr"; String "path"]), 145, [],
+ [],
+ "remove extended attribute of a file or directory",
+ "\
+This call removes the extended attribute named C<xattr>
+of the file C<path>.
+
+See also: C<guestfs_lremovexattr>, L<attr(5)>.");
+
+ ("lremovexattr", (RErr, [String "xattr"; String "path"]), 146, [],
+ [],
+ "remove extended attribute of a file or directory",
+ "\
+This is the same as C<guestfs_removexattr>, but if C<path>
+is a symbolic link, then it removes an extended attribute
+of the link itself.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
type field =
| FChar (* C 'char' (really, a 7 bit byte). *)
| FString (* nul-terminated ASCII string. *)
+ | FBuffer (* opaque buffer of bytes, (char *, int) pair *)
| FUInt32
| FInt32
| FUInt64
"release", FInt64;
"extra", FString;
];
+
+ (* Extended attribute. *)
+ "xattr", [
+ "attrname", FString;
+ "attrval", FBuffer;
+ ];
] (* end of structs *)
(* Ugh, Java has to be different ..
"statvfs", "StatVFS";
"dirent", "Dirent";
"version", "Version";
+ "xattr", "XAttr";
]
(* Used for testing language bindings. *)
| name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
| name, FInt64 -> pr " int64_t %s;\n" name
| name, FString -> pr " char *%s;\n" name
+ | name, FBuffer ->
+ pr " /* The next two fields describe a byte array. */\n";
+ pr " uint32_t %s_len;\n" name;
+ pr " char *%s;\n" name
| name, FUUID ->
pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
pr " char %s[32];\n" name
List.iter (function
| name, FChar -> pr " char %s;\n" name
| name, FString -> pr " string %s<>;\n" name
+ | name, FBuffer -> pr " opaque %s<>;\n" name
| name, FUUID -> pr " opaque %s[32];\n" name
| name, (FInt32|FUInt32) -> pr " int %s;\n" name
| name, (FInt64|FUInt64|FBytes) -> pr " hyper %s;\n" name
function
| name, FChar -> pr " char %s;\n" name
| name, FString -> pr " char *%s;\n" name
+ | name, FBuffer ->
+ pr " uint32_t %s_len;\n" name;
+ pr " char *%s;\n" name
| name, FUUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
| name, FUInt32 -> pr " uint32_t %s;\n" name
| name, FInt32 -> pr " int32_t %s;\n" name
pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
pr " return -1;\n";
pr " }\n";
- | FInt32 | FUInt32 | FUInt64 | FChar ->
+ | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
assert false (* can never be an LVM column *)
);
pr " tok = next;\n";
pr "#include <stdlib.h>\n";
pr "#include <string.h>\n";
pr "#include <inttypes.h>\n";
+ pr "#include <ctype.h>\n";
pr "\n";
pr "#include <guestfs.h>\n";
pr "#include \"fish.h\"\n";
List.iter (
fun (typ, cols) ->
let needs_i =
- List.exists (function (_, FUUID) -> true | _ -> false) cols in
+ List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
pr "{\n";
pr " for (i = 0; i < 32; ++i)\n";
pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
pr " printf (\"\\n\");\n"
+ | name, FBuffer ->
+ pr " printf (\"%s: \");\n" name;
+ pr " for (i = 0; i < %s->%s_len; ++i)\n" typ name;
+ pr " if (isprint (%s->%s[i]))\n" typ name;
+ pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
+ pr " else\n";
+ pr " printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
+ pr " printf (\"\\n\");\n"
| name, (FUInt64|FBytes) ->
pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
| name, FInt64 ->
(match col with
| name, FString ->
pr " v = caml_copy_string (%s->%s);\n" typ name
+ | name, FBuffer ->
+ pr " v = caml_alloc_string (%s->%s_len);\n" typ name;
+ pr " memcpy (String_val (v), %s->%s, %s->%s_len);\n"
+ typ name typ name
| name, FUUID ->
pr " v = caml_alloc_string (32);\n";
pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
List.iter (
function
| name, FString -> pr " %s : string;\n" name
+ | name, FBuffer -> pr " %s : string;\n" name
| name, FUUID -> pr " %s : string;\n" name
| name, (FBytes|FInt64|FUInt64) -> pr " %s : int64;\n" name
| name, (FInt32|FUInt32) -> pr " %s : int32;\n" name
| name, FUUID ->
pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
name (String.length name) n name
+ | name, FBuffer ->
+ pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
+ name (String.length name) n name n name
| name, (FBytes|FUInt64) ->
pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
name (String.length name) n name
| name, FString ->
pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
n name
+ | name, FBuffer ->
+ pr " PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
+ n name n name
| name, FUUID ->
pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
n name
pr " PyDict_SetItemString (dict, \"%s\",\n" name;
pr " PyString_FromString (%s->%s));\n"
typ name
+ | name, FBuffer ->
+ pr " PyDict_SetItemString (dict, \"%s\",\n" name;
+ pr " PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
+ typ name typ name
| name, FUUID ->
pr " PyDict_SetItemString (dict, \"%s\",\n" name;
pr " PyString_FromStringAndSize (%s->%s, 32));\n"
function
| name, FString ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
+ | name, FBuffer ->
+ pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
| name, FUUID ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
| name, (FBytes|FUInt64) ->
function
| name, FString ->
pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
+ | name, FBuffer ->
+ pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, r->val[i].%s_len));\n" name name name
| name, FUUID ->
pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
| name, (FBytes|FUInt64) ->
List.iter (
function
| name, FString
- | name, FUUID -> pr " public String %s;\n" name
+ | name, FUUID
+ | name, FBuffer -> pr " public String %s;\n" name
| name, (FBytes|FUInt64|FInt64) -> pr " public long %s;\n" name
| name, (FUInt32|FInt32) -> pr " public int %s;\n" name
| name, FChar -> pr " public char %s;\n" name
pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
pr " }\n";
+ | name, FBuffer ->
+ pr " {\n";
+ pr " int len = r->%s_len;\n" name;
+ pr " char s[len+1];\n";
+ pr " memcpy (s, r->%s, len);\n" name;
+ pr " s[len] = 0;\n";
+ pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
+ pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
+ pr " }\n";
| name, (FBytes|FUInt64|FInt64) ->
pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
pr " }\n";
+ | name, FBuffer ->
+ pr " {\n";
+ pr " int len = r->val[i].%s_len;\n" name;
+ pr " char s[len+1];\n";
+ pr " memcpy (s, r->val[i].%s, len);\n" name;
+ pr " s[len] = 0;\n";
+ pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
+ pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
+ pr " }\n";
| name, (FBytes|FUInt64|FInt64) ->
pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;