1 /* libguestfs - the guestfsd daemon
2 * Copyright (C) 2009 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "../src/guestfs_protocol.h"
27 #include "optgroups.h"
29 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
31 # ifdef HAVE_ATTR_XATTR_H
32 # include <attr/xattr.h>
34 # ifdef HAVE_SYS_XATTR_H
35 # include <sys/xattr.h>
40 optgroup_linuxxattrs_available (void)
45 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));
46 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));
47 static int _removexattr (const char *xattr, const char *path, int (*removexattr) (const char *path, const char *name));
49 guestfs_int_xattr_list *
50 do_getxattrs (const char *path)
52 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
53 return getxattrs (path, listxattr, getxattr);
55 reply_with_error ("no support for listxattr and getxattr");
60 guestfs_int_xattr_list *
61 do_lgetxattrs (const char *path)
63 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
64 return getxattrs (path, llistxattr, lgetxattr);
66 reply_with_error ("no support for llistxattr and lgetxattr");
72 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
74 #if defined(HAVE_SETXATTR)
75 return _setxattr (xattr, val, vallen, path, setxattr);
77 reply_with_error ("no support for setxattr");
83 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
85 #if defined(HAVE_LSETXATTR)
86 return _setxattr (xattr, val, vallen, path, lsetxattr);
88 reply_with_error ("no support for lsetxattr");
94 do_removexattr (const char *xattr, const char *path)
96 #if defined(HAVE_REMOVEXATTR)
97 return _removexattr (xattr, path, removexattr);
99 reply_with_error ("no support for removexattr");
105 do_lremovexattr (const char *xattr, const char *path)
107 #if defined(HAVE_LREMOVEXATTR)
108 return _removexattr (xattr, path, lremovexattr);
110 reply_with_error ("no support for lremovexattr");
115 static guestfs_int_xattr_list *
116 getxattrs (const char *path,
117 ssize_t (*listxattr) (const char *path, char *list, size_t size),
118 ssize_t (*getxattr) (const char *path, const char *name,
119 void *value, size_t size))
124 guestfs_int_xattr_list *r = NULL;
127 len = listxattr (path, NULL, 0);
130 reply_with_perror ("listxattr: %s", path);
136 reply_with_perror ("malloc");
141 len = listxattr (path, buf, len);
144 reply_with_perror ("listxattr: %s", path);
148 r = calloc (1, sizeof (*r));
150 reply_with_perror ("malloc");
154 /* What we get from the kernel is a string "foo\0bar\0baz" of length
155 * len. First count the strings.
157 r->guestfs_int_xattr_list_len = 0;
158 for (i = 0; i < len; i += strlen (&buf[i]) + 1)
159 r->guestfs_int_xattr_list_len++;
161 r->guestfs_int_xattr_list_val =
162 calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
163 if (r->guestfs_int_xattr_list_val == NULL) {
164 reply_with_perror ("calloc");
168 for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
170 vlen = getxattr (path, &buf[i], NULL, 0);
173 reply_with_perror ("getxattr");
177 r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
178 r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
179 r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
181 if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
182 r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
183 reply_with_perror ("malloc");
188 vlen = getxattr (path, &buf[i],
189 r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
193 reply_with_perror ("getxattr");
205 if (r->guestfs_int_xattr_list_val) {
207 for (k = 0; k < r->guestfs_int_xattr_list_len; ++k) {
208 free (r->guestfs_int_xattr_list_val[k].attrname);
209 free (r->guestfs_int_xattr_list_val[k].attrval.attrval_val);
212 free (r->guestfs_int_xattr_list_val);
219 _setxattr (const char *xattr, const char *val, int vallen, const char *path,
220 int (*setxattr) (const char *path, const char *name,
221 const void *value, size_t size, int flags))
226 r = setxattr (path, xattr, val, vallen, 0);
229 reply_with_perror ("setxattr");
237 _removexattr (const char *xattr, const char *path,
238 int (*removexattr) (const char *path, const char *name))
243 r = removexattr (path, xattr);
246 reply_with_perror ("removexattr");
253 guestfs_int_xattr_list *
254 do_lxattrlist (const char *path, char *const *names)
256 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
257 /* XXX This would be easier if the kernel had lgetxattrat. In the
258 * meantime we use this buffer to store the whole path name.
260 char pathname[PATH_MAX];
261 size_t path_len = strlen (path);
262 guestfs_int_xattr_list *ret = NULL;
264 size_t k, m, nr_attrs;
268 if (path_len >= PATH_MAX) {
269 reply_with_perror ("path longer than PATH_MAX");
273 strcpy (pathname, path);
275 ret = malloc (sizeof (*ret));
277 reply_with_perror ("malloc");
281 ret->guestfs_int_xattr_list_len = 0;
282 ret->guestfs_int_xattr_list_val = NULL;
284 for (k = 0; names[k] != NULL; ++k) {
285 /* Be careful in here about which errors cause the whole call
286 * to abort, and which errors allow us to continue processing
287 * the call, recording a special "error attribute" in the
288 * outgoing struct list.
290 if (path_len + strlen (names[k]) + 2 > PATH_MAX) {
291 reply_with_perror ("path and name longer than PATH_MAX");
294 pathname[path_len] = '/';
295 strcpy (&pathname[path_len+1], names[k]);
297 /* Reserve space for the special attribute. */
299 realloc (ret->guestfs_int_xattr_list_val,
300 (ret->guestfs_int_xattr_list_len+1)*sizeof (guestfs_int_xattr));
301 if (newptr == NULL) {
302 reply_with_perror ("realloc");
305 ret->guestfs_int_xattr_list_val = newptr;
306 ret->guestfs_int_xattr_list_len++;
308 guestfs_int_xattr *entry =
309 &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-1];
310 entry->attrname = NULL;
311 entry->attrval.attrval_len = 0;
312 entry->attrval.attrval_val = NULL;
314 entry->attrname = strdup ("");
315 if (entry->attrname == NULL) {
316 reply_with_perror ("strdup");
321 len = llistxattr (pathname, NULL, 0);
324 continue; /* not fatal */
328 reply_with_perror ("malloc");
333 len = llistxattr (pathname, buf, len);
336 continue; /* not fatal */
338 /* What we get from the kernel is a string "foo\0bar\0baz" of length
339 * len. First count the strings.
342 for (i = 0; i < len; i += strlen (&buf[i]) + 1)
346 realloc (ret->guestfs_int_xattr_list_val,
347 (ret->guestfs_int_xattr_list_len+nr_attrs) *
348 sizeof (guestfs_int_xattr));
349 if (newptr == NULL) {
350 reply_with_perror ("realloc");
353 ret->guestfs_int_xattr_list_val = newptr;
354 ret->guestfs_int_xattr_list_len += nr_attrs;
356 /* entry[0] is the special attribute,
357 * entry[1..nr_attrs] are the attributes.
359 entry = &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-nr_attrs-1];
360 for (m = 1; m <= nr_attrs; ++m) {
361 entry[m].attrname = NULL;
362 entry[m].attrval.attrval_len = 0;
363 entry[m].attrval.attrval_val = NULL;
366 for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
368 vlen = lgetxattr (pathname, &buf[i], NULL, 0);
371 reply_with_perror ("getxattr");
375 entry[j+1].attrname = strdup (&buf[i]);
376 entry[j+1].attrval.attrval_val = malloc (vlen);
377 entry[j+1].attrval.attrval_len = vlen;
379 if (entry[j+1].attrname == NULL ||
380 entry[j+1].attrval.attrval_val == NULL) {
381 reply_with_perror ("malloc");
386 vlen = lgetxattr (pathname, &buf[i],
387 entry[j+1].attrval.attrval_val, vlen);
390 reply_with_perror ("getxattr");
395 free (buf); buf = NULL;
398 snprintf (num, sizeof num, "%zu", nr_attrs);
399 entry[0].attrval.attrval_len = strlen (num) + 1;
400 entry[0].attrval.attrval_val = strdup (num);
402 if (entry[0].attrval.attrval_val == NULL) {
403 reply_with_perror ("strdup");
408 /* If verbose, debug what we're about to send back. */
410 fprintf (stderr, "lxattrlist: returning: [\n");
411 for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
412 const guestfs_int_xattr *entry = &ret->guestfs_int_xattr_list_val[k];
413 if (STRNEQ (entry[0].attrname, "")) {
414 fprintf (stderr, "ERROR: expecting empty attrname at k = %zu\n", k);
417 fprintf (stderr, " %zu: special attrval = %s\n",
418 k, entry[0].attrval.attrval_val);
419 for (i = 1; k+i < ret->guestfs_int_xattr_list_len; ++i) {
420 if (STREQ (entry[i].attrname, ""))
422 fprintf (stderr, " name %s, value length %d\n",
423 entry[i].attrname, entry[i].attrval.attrval_len);
427 fprintf (stderr, "]\n");
435 if (ret->guestfs_int_xattr_list_val) {
436 for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
437 free (ret->guestfs_int_xattr_list_val[k].attrname);
438 free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val);
440 free (ret->guestfs_int_xattr_list_val);
446 reply_with_error ("no support for llistxattr and lgetxattr");
451 #else /* no xattr.h */
453 optgroup_linuxxattrs_available (void)
458 guestfs_int_xattr_list *
459 do_getxattrs (const char *path)
461 NOT_AVAILABLE (NULL);
464 guestfs_int_xattr_list *
465 do_lgetxattrs (const char *path)
467 NOT_AVAILABLE (NULL);
471 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
477 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
483 do_removexattr (const char *xattr, const char *path)
489 do_lremovexattr (const char *xattr, const char *path)
494 guestfs_int_xattr_list *
495 do_lxattrlist (const char *path, char *const *names)
497 NOT_AVAILABLE (NULL);
500 #endif /* no xattr.h */