Remove out-of-date comment.
[libguestfs.git] / daemon / xattr.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <unistd.h>
23
24 #include "../src/guestfs_protocol.h"
25 #include "daemon.h"
26 #include "actions.h"
27 #include "optgroups.h"
28
29 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
30
31 # ifdef HAVE_ATTR_XATTR_H
32 #  include <attr/xattr.h>
33 # else
34 #  ifdef HAVE_SYS_XATTR_H
35 #   include <sys/xattr.h>
36 #  endif
37 # endif
38
39 int
40 optgroup_linuxxattrs_available (void)
41 {
42   return 1;
43 }
44
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));
48
49 guestfs_int_xattr_list *
50 do_getxattrs (const char *path)
51 {
52 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
53   return getxattrs (path, listxattr, getxattr);
54 #else
55   reply_with_error ("no support for listxattr and getxattr");
56   return NULL;
57 #endif
58 }
59
60 guestfs_int_xattr_list *
61 do_lgetxattrs (const char *path)
62 {
63 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
64   return getxattrs (path, llistxattr, lgetxattr);
65 #else
66   reply_with_error ("no support for llistxattr and lgetxattr");
67   return NULL;
68 #endif
69 }
70
71 int
72 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
73 {
74 #if defined(HAVE_SETXATTR)
75   return _setxattr (xattr, val, vallen, path, setxattr);
76 #else
77   reply_with_error ("no support for setxattr");
78   return -1;
79 #endif
80 }
81
82 int
83 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
84 {
85 #if defined(HAVE_LSETXATTR)
86   return _setxattr (xattr, val, vallen, path, lsetxattr);
87 #else
88   reply_with_error ("no support for lsetxattr");
89   return -1;
90 #endif
91 }
92
93 int
94 do_removexattr (const char *xattr, const char *path)
95 {
96 #if defined(HAVE_REMOVEXATTR)
97   return _removexattr (xattr, path, removexattr);
98 #else
99   reply_with_error ("no support for removexattr");
100   return -1;
101 #endif
102 }
103
104 int
105 do_lremovexattr (const char *xattr, const char *path)
106 {
107 #if defined(HAVE_LREMOVEXATTR)
108   return _removexattr (xattr, path, lremovexattr);
109 #else
110   reply_with_error ("no support for lremovexattr");
111   return -1;
112 #endif
113 }
114
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))
120 {
121   ssize_t len, vlen;
122   char *buf = NULL;
123   int i, j;
124   guestfs_int_xattr_list *r = NULL;
125
126   CHROOT_IN;
127   len = listxattr (path, NULL, 0);
128   CHROOT_OUT;
129   if (len == -1) {
130     reply_with_perror ("listxattr: %s", path);
131     goto error;
132   }
133
134   buf = malloc (len);
135   if (buf == NULL) {
136     reply_with_perror ("malloc");
137     goto error;
138   }
139
140   CHROOT_IN;
141   len = listxattr (path, buf, len);
142   CHROOT_OUT;
143   if (len == -1) {
144     reply_with_perror ("listxattr: %s", path);
145     goto error;
146   }
147
148   r = calloc (1, sizeof (*r));
149   if (r == NULL) {
150     reply_with_perror ("malloc");
151     goto error;
152   }
153
154   /* What we get from the kernel is a string "foo\0bar\0baz" of length
155    * len.  First count the strings.
156    */
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++;
160
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");
165     goto error;
166   }
167
168   for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
169     CHROOT_IN;
170     vlen = getxattr (path, &buf[i], NULL, 0);
171     CHROOT_OUT;
172     if (vlen == -1) {
173       reply_with_perror ("getxattr");
174       goto error;
175     }
176
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;
180
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");
184       goto error;
185     }
186
187     CHROOT_IN;
188     vlen = getxattr (path, &buf[i],
189                      r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
190                      vlen);
191     CHROOT_OUT;
192     if (vlen == -1) {
193       reply_with_perror ("getxattr");
194       goto error;
195     }
196   }
197
198   free (buf);
199
200   return r;
201
202  error:
203   free (buf);
204   if (r) {
205     if (r->guestfs_int_xattr_list_val) {
206       unsigned int k;
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);
210       }
211     }
212     free (r->guestfs_int_xattr_list_val);
213   }
214   free (r);
215   return NULL;
216 }
217
218 static int
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))
222 {
223   int r;
224
225   CHROOT_IN;
226   r = setxattr (path, xattr, val, vallen, 0);
227   CHROOT_OUT;
228   if (r == -1) {
229     reply_with_perror ("setxattr");
230     return -1;
231   }
232
233   return 0;
234 }
235
236 static int
237 _removexattr (const char *xattr, const char *path,
238               int (*removexattr) (const char *path, const char *name))
239 {
240   int r;
241
242   CHROOT_IN;
243   r = removexattr (path, xattr);
244   CHROOT_OUT;
245   if (r == -1) {
246     reply_with_perror ("removexattr");
247     return -1;
248   }
249
250   return 0;
251 }
252
253 guestfs_int_xattr_list *
254 do_lxattrlist (const char *path, char *const *names)
255 {
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.
259    */
260   char pathname[PATH_MAX];
261   size_t path_len = strlen (path);
262   guestfs_int_xattr_list *ret = NULL;
263   int i, j;
264   size_t k, m, nr_attrs;
265   ssize_t len, vlen;
266   char *buf = NULL;
267
268   if (path_len >= PATH_MAX) {
269     reply_with_perror ("path longer than PATH_MAX");
270     goto error;
271   }
272
273   strcpy (pathname, path);
274
275   ret = malloc (sizeof (*ret));
276   if (ret == NULL) {
277     reply_with_perror ("malloc");
278     goto error;
279   }
280
281   ret->guestfs_int_xattr_list_len = 0;
282   ret->guestfs_int_xattr_list_val = NULL;
283
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.
289      */
290     if (path_len + strlen (names[k]) + 2 > PATH_MAX) {
291       reply_with_perror ("path and name longer than PATH_MAX");
292       goto error;
293     }
294     pathname[path_len] = '/';
295     strcpy (&pathname[path_len+1], names[k]);
296
297     /* Reserve space for the special attribute. */
298     void *newptr =
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");
303       goto error;
304     }
305     ret->guestfs_int_xattr_list_val = newptr;
306     ret->guestfs_int_xattr_list_len++;
307
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;
313
314     entry->attrname = strdup ("");
315     if (entry->attrname == NULL) {
316       reply_with_perror ("strdup");
317       goto error;
318     }
319
320     CHROOT_IN;
321     len = llistxattr (pathname, NULL, 0);
322     CHROOT_OUT;
323     if (len == -1)
324       continue; /* not fatal */
325
326     buf = malloc (len);
327     if (buf == NULL) {
328       reply_with_perror ("malloc");
329       goto error;
330     }
331
332     CHROOT_IN;
333     len = llistxattr (pathname, buf, len);
334     CHROOT_OUT;
335     if (len == -1)
336       continue; /* not fatal */
337
338     /* What we get from the kernel is a string "foo\0bar\0baz" of length
339      * len.  First count the strings.
340      */
341     nr_attrs = 0;
342     for (i = 0; i < len; i += strlen (&buf[i]) + 1)
343       nr_attrs++;
344
345     newptr =
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");
351       goto error;
352     }
353     ret->guestfs_int_xattr_list_val = newptr;
354     ret->guestfs_int_xattr_list_len += nr_attrs;
355
356     /* entry[0] is the special attribute,
357      * entry[1..nr_attrs] are the attributes.
358      */
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;
364     }
365
366     for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
367       CHROOT_IN;
368       vlen = lgetxattr (pathname, &buf[i], NULL, 0);
369       CHROOT_OUT;
370       if (vlen == -1) {
371         reply_with_perror ("getxattr");
372         goto error;
373       }
374
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;
378
379       if (entry[j+1].attrname == NULL ||
380           entry[j+1].attrval.attrval_val == NULL) {
381         reply_with_perror ("malloc");
382         goto error;
383       }
384
385       CHROOT_IN;
386       vlen = lgetxattr (pathname, &buf[i],
387                         entry[j+1].attrval.attrval_val, vlen);
388       CHROOT_OUT;
389       if (vlen == -1) {
390         reply_with_perror ("getxattr");
391         goto error;
392       }
393     }
394
395     free (buf); buf = NULL;
396
397     char num[16];
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);
401
402     if (entry[0].attrval.attrval_val == NULL) {
403       reply_with_perror ("strdup");
404       goto error;
405     }
406   }
407
408   /* If verbose, debug what we're about to send back. */
409   if (verbose) {
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);
415         break;
416       }
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, ""))
421           break;
422         fprintf (stderr, "    name %s, value length %d\n",
423                  entry[i].attrname, entry[i].attrval.attrval_len);
424       }
425       k += i-1;
426     }
427     fprintf (stderr, "]\n");
428   }
429
430   return ret;
431
432  error:
433   free (buf);
434   if (ret) {
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);
439       }
440       free (ret->guestfs_int_xattr_list_val);
441     }
442     free (ret);
443   }
444   return NULL;
445 #else
446   reply_with_error ("no support for llistxattr and lgetxattr");
447   return NULL;
448 #endif
449 }
450
451 #else /* no xattr.h */
452 int
453 optgroup_linuxxattrs_available (void)
454 {
455   return 0;
456 }
457
458 guestfs_int_xattr_list *
459 do_getxattrs (const char *path)
460 {
461   NOT_AVAILABLE (NULL);
462 }
463
464 guestfs_int_xattr_list *
465 do_lgetxattrs (const char *path)
466 {
467   NOT_AVAILABLE (NULL);
468 }
469
470 int
471 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
472 {
473   NOT_AVAILABLE (-1);
474 }
475
476 int
477 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
478 {
479   NOT_AVAILABLE (-1);
480 }
481
482 int
483 do_removexattr (const char *xattr, const char *path)
484 {
485   NOT_AVAILABLE (-1);
486 }
487
488 int
489 do_lremovexattr (const char *xattr, const char *path)
490 {
491   NOT_AVAILABLE (-1);
492 }
493
494 guestfs_int_xattr_list *
495 do_lxattrlist (const char *path, char *const *names)
496 {
497   NOT_AVAILABLE (NULL);
498 }
499
500 #endif /* no xattr.h */