todo: Remove event log parsing - done.
[libguestfs.git] / daemon / xattr.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009-2011 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 "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   return ret;
409
410  error:
411   free (buf);
412   if (ret) {
413     if (ret->guestfs_int_xattr_list_val) {
414       for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
415         free (ret->guestfs_int_xattr_list_val[k].attrname);
416         free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val);
417       }
418       free (ret->guestfs_int_xattr_list_val);
419     }
420     free (ret);
421   }
422   return NULL;
423 #else
424   reply_with_error ("no support for llistxattr and lgetxattr");
425   return NULL;
426 #endif
427 }
428
429 char *
430 do_getxattr (const char *path, const char *name, size_t *size_r)
431 {
432   ssize_t r;
433   char *buf;
434   size_t len;
435
436   CHROOT_IN;
437   r = getxattr (path, name, NULL, 0);
438   CHROOT_OUT;
439   if (r == -1) {
440     reply_with_perror ("getxattr");
441     return NULL;
442   }
443
444   len = r;
445   buf = malloc (len);
446   if (buf == NULL) {
447     reply_with_perror ("malloc");
448     return NULL;
449   }
450
451   CHROOT_IN;
452   r = getxattr (path, name, buf, len);
453   CHROOT_OUT;
454   if (r == -1) {
455     reply_with_perror ("getxattr");
456     free (buf);
457     return NULL;
458   }
459
460   if (len != (size_t) r) {
461     reply_with_error ("getxattr: unexpected size (%zu/%zd)", len, r);
462     free (buf);
463     return NULL;
464   }
465
466   /* Must set size_r last thing before returning. */
467   *size_r = len;
468   return buf; /* caller frees */
469 }
470
471 char *
472 do_lgetxattr (const char *path, const char *name, size_t *size_r)
473 {
474   ssize_t r;
475   char *buf;
476   size_t len;
477
478   CHROOT_IN;
479   r = lgetxattr (path, name, NULL, 0);
480   CHROOT_OUT;
481   if (r == -1) {
482     reply_with_perror ("lgetxattr");
483     return NULL;
484   }
485
486   len = r;
487   buf = malloc (len);
488   if (buf == NULL) {
489     reply_with_perror ("malloc");
490     return NULL;
491   }
492
493   CHROOT_IN;
494   r = lgetxattr (path, name, buf, len);
495   CHROOT_OUT;
496   if (r == -1) {
497     reply_with_perror ("lgetxattr");
498     free (buf);
499     return NULL;
500   }
501
502   if (len != (size_t) r) {
503     reply_with_error ("lgetxattr: unexpected size (%zu/%zd)", len, r);
504     free (buf);
505     return NULL;
506   }
507
508   /* Must set size_r last thing before returning. */
509   *size_r = len;
510   return buf; /* caller frees */
511 }
512
513 #else /* no xattr.h */
514 int
515 optgroup_linuxxattrs_available (void)
516 {
517   return 0;
518 }
519
520 guestfs_int_xattr_list *
521 do_getxattrs (const char *path)
522 {
523   NOT_AVAILABLE (NULL);
524 }
525
526 guestfs_int_xattr_list *
527 do_lgetxattrs (const char *path)
528 {
529   NOT_AVAILABLE (NULL);
530 }
531
532 int
533 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
534 {
535   NOT_AVAILABLE (-1);
536 }
537
538 int
539 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
540 {
541   NOT_AVAILABLE (-1);
542 }
543
544 int
545 do_removexattr (const char *xattr, const char *path)
546 {
547   NOT_AVAILABLE (-1);
548 }
549
550 int
551 do_lremovexattr (const char *xattr, const char *path)
552 {
553   NOT_AVAILABLE (-1);
554 }
555
556 guestfs_int_xattr_list *
557 do_lxattrlist (const char *path, char *const *names)
558 {
559   NOT_AVAILABLE (NULL);
560 }
561
562 char *
563 do_getxattr (const char *path, const char *name, size_t *size_r)
564 {
565   NOT_AVAILABLE (NULL);
566 }
567
568 char *
569 do_lgetxattr (const char *path, const char *name, size_t *size_r)
570 {
571   NOT_AVAILABLE (NULL);
572 }
573
574 #endif /* no xattr.h */