change strncmp() == 0 to STREQLEN()
[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
28 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
29
30 #ifdef HAVE_ATTR_XATTR_H
31 #include <attr/xattr.h>
32 #else
33 #ifdef HAVE_SYS_XATTR_H
34 #include <sys/xattr.h>
35 #endif
36 #endif
37
38 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));
39 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));
40 static int _removexattr (const char *xattr, const char *path, int (*removexattr) (const char *path, const char *name));
41
42 guestfs_int_xattr_list *
43 do_getxattrs (const char *path)
44 {
45 #if defined(HAVE_LISTXATTR) && defined(HAVE_GETXATTR)
46   return getxattrs (path, listxattr, getxattr);
47 #else
48   reply_with_error ("getxattrs: no support for listxattr and getxattr");
49   return NULL;
50 #endif
51 }
52
53 guestfs_int_xattr_list *
54 do_lgetxattrs (const char *path)
55 {
56 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
57   return getxattrs (path, llistxattr, lgetxattr);
58 #else
59   reply_with_error ("lgetxattrs: no support for llistxattr and lgetxattr");
60   return NULL;
61 #endif
62 }
63
64 int
65 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
66 {
67 #if defined(HAVE_SETXATTR)
68   return _setxattr (xattr, val, vallen, path, setxattr);
69 #else
70   reply_with_error ("setxattr: no support for setxattr");
71   return -1;
72 #endif
73 }
74
75 int
76 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
77 {
78 #if defined(HAVE_LSETXATTR)
79   return _setxattr (xattr, val, vallen, path, lsetxattr);
80 #else
81   reply_with_error ("lsetxattr: no support for lsetxattr");
82   return -1;
83 #endif
84 }
85
86 int
87 do_removexattr (const char *xattr, const char *path)
88 {
89 #if defined(HAVE_REMOVEXATTR)
90   return _removexattr (xattr, path, removexattr);
91 #else
92   reply_with_error ("removexattr: no support for removexattr");
93   return -1;
94 #endif
95 }
96
97 int
98 do_lremovexattr (const char *xattr, const char *path)
99 {
100 #if defined(HAVE_LREMOVEXATTR)
101   return _removexattr (xattr, path, lremovexattr);
102 #else
103   reply_with_error ("lremovexattr: no support for lremovexattr");
104   return -1;
105 #endif
106 }
107
108 static guestfs_int_xattr_list *
109 getxattrs (const char *path,
110            ssize_t (*listxattr) (const char *path, char *list, size_t size),
111            ssize_t (*getxattr) (const char *path, const char *name,
112                                 void *value, size_t size))
113 {
114   ssize_t len, vlen;
115   char *buf = NULL;
116   int i, j;
117   guestfs_int_xattr_list *r = NULL;
118
119   CHROOT_IN;
120   len = listxattr (path, NULL, 0);
121   CHROOT_OUT;
122   if (len == -1) {
123     reply_with_perror ("listxattr");
124     goto error;
125   }
126
127   buf = malloc (len);
128   if (buf == NULL) {
129     reply_with_perror ("malloc");
130     goto error;
131   }
132
133   CHROOT_IN;
134   len = listxattr (path, buf, len);
135   CHROOT_OUT;
136   if (len == -1) {
137     reply_with_perror ("listxattr");
138     goto error;
139   }
140
141   r = calloc (1, sizeof (*r));
142   if (r == NULL) {
143     reply_with_perror ("malloc");
144     goto error;
145   }
146
147   /* What we get from the kernel is a string "foo\0bar\0baz" of length
148    * len.  First count the strings.
149    */
150   r->guestfs_int_xattr_list_len = 0;
151   for (i = 0; i < len; i += strlen (&buf[i]) + 1)
152     r->guestfs_int_xattr_list_len++;
153
154   r->guestfs_int_xattr_list_val =
155     calloc (r->guestfs_int_xattr_list_len, sizeof (guestfs_int_xattr));
156   if (r->guestfs_int_xattr_list_val == NULL) {
157     reply_with_perror ("calloc");
158     goto error;
159   }
160
161   for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
162     CHROOT_IN;
163     vlen = getxattr (path, &buf[i], NULL, 0);
164     CHROOT_OUT;
165     if (vlen == -1) {
166       reply_with_perror ("getxattr");
167       goto error;
168     }
169
170     r->guestfs_int_xattr_list_val[j].attrname = strdup (&buf[i]);
171     r->guestfs_int_xattr_list_val[j].attrval.attrval_val = malloc (vlen);
172     r->guestfs_int_xattr_list_val[j].attrval.attrval_len = vlen;
173
174     if (r->guestfs_int_xattr_list_val[j].attrname == NULL ||
175         r->guestfs_int_xattr_list_val[j].attrval.attrval_val == NULL) {
176       reply_with_perror ("malloc");
177       goto error;
178     }
179
180     CHROOT_IN;
181     vlen = getxattr (path, &buf[i],
182                      r->guestfs_int_xattr_list_val[j].attrval.attrval_val,
183                      vlen);
184     CHROOT_OUT;
185     if (vlen == -1) {
186       reply_with_perror ("getxattr");
187       goto error;
188     }
189   }
190
191   free (buf);
192
193   return r;
194
195  error:
196   free (buf);
197   if (r) {
198     if (r->guestfs_int_xattr_list_val) {
199       unsigned int k;
200       for (k = 0; k < r->guestfs_int_xattr_list_len; ++k) {
201         free (r->guestfs_int_xattr_list_val[k].attrname);
202         free (r->guestfs_int_xattr_list_val[k].attrval.attrval_val);
203       }
204     }
205     free (r->guestfs_int_xattr_list_val);
206   }
207   free (r);
208   return NULL;
209 }
210
211 static int
212 _setxattr (const char *xattr, const char *val, int vallen, const char *path,
213            int (*setxattr) (const char *path, const char *name,
214                             const void *value, size_t size, int flags))
215 {
216   int r;
217
218   CHROOT_IN;
219   r = setxattr (path, xattr, val, vallen, 0);
220   CHROOT_OUT;
221   if (r == -1) {
222     reply_with_perror ("setxattr");
223     return -1;
224   }
225
226   return 0;
227 }
228
229 static int
230 _removexattr (const char *xattr, const char *path,
231               int (*removexattr) (const char *path, const char *name))
232 {
233   int r;
234
235   CHROOT_IN;
236   r = removexattr (path, xattr);
237   CHROOT_OUT;
238   if (r == -1) {
239     reply_with_perror ("removexattr");
240     return -1;
241   }
242
243   return 0;
244 }
245
246 guestfs_int_xattr_list *
247 do_lxattrlist (const char *path, char *const *names)
248 {
249 #if defined(HAVE_LLISTXATTR) && defined(HAVE_LGETXATTR)
250   /* XXX This would be easier if the kernel had lgetxattrat.  In the
251    * meantime we use this buffer to store the whole path name.
252    */
253   char pathname[PATH_MAX];
254   size_t path_len = strlen (path);
255   guestfs_int_xattr_list *ret = NULL;
256   int i, j;
257   size_t k, m, nr_attrs;
258   ssize_t len, vlen;
259   char *buf = NULL;
260
261   if (path_len >= PATH_MAX) {
262     reply_with_perror ("lxattrlist: path longer than PATH_MAX");
263     goto error;
264   }
265
266   strcpy (pathname, path);
267
268   ret = malloc (sizeof (*ret));
269   if (ret == NULL) {
270     reply_with_perror ("malloc");
271     goto error;
272   }
273
274   ret->guestfs_int_xattr_list_len = 0;
275   ret->guestfs_int_xattr_list_val = NULL;
276
277   for (k = 0; names[k] != NULL; ++k) {
278     /* Be careful in here about which errors cause the whole call
279      * to abort, and which errors allow us to continue processing
280      * the call, recording a special "error attribute" in the
281      * outgoing struct list.
282      */
283     if (path_len + strlen (names[k]) + 2 > PATH_MAX) {
284       reply_with_perror ("lxattrlist: path and name longer than PATH_MAX");
285       goto error;
286     }
287     pathname[path_len] = '/';
288     strcpy (&pathname[path_len+1], names[k]);
289
290     /* Reserve space for the special attribute. */
291     void *newptr =
292       realloc (ret->guestfs_int_xattr_list_val,
293                (ret->guestfs_int_xattr_list_len+1)*sizeof (guestfs_int_xattr));
294     if (newptr == NULL) {
295       reply_with_perror ("realloc");
296       goto error;
297     }
298     ret->guestfs_int_xattr_list_val = newptr;
299     ret->guestfs_int_xattr_list_len++;
300
301     guestfs_int_xattr *entry =
302       &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-1];
303     entry->attrname = NULL;
304     entry->attrval.attrval_len = 0;
305     entry->attrval.attrval_val = NULL;
306
307     entry->attrname = strdup ("");
308     if (entry->attrname == NULL) {
309       reply_with_perror ("strdup");
310       goto error;
311     }
312
313     CHROOT_IN;
314     len = llistxattr (pathname, NULL, 0);
315     CHROOT_OUT;
316     if (len == -1)
317       continue; /* not fatal */
318
319     buf = malloc (len);
320     if (buf == NULL) {
321       reply_with_perror ("malloc");
322       goto error;
323     }
324
325     CHROOT_IN;
326     len = llistxattr (pathname, buf, len);
327     CHROOT_OUT;
328     if (len == -1)
329       continue; /* not fatal */
330
331     /* What we get from the kernel is a string "foo\0bar\0baz" of length
332      * len.  First count the strings.
333      */
334     nr_attrs = 0;
335     for (i = 0; i < len; i += strlen (&buf[i]) + 1)
336       nr_attrs++;
337
338     newptr =
339       realloc (ret->guestfs_int_xattr_list_val,
340                (ret->guestfs_int_xattr_list_len+nr_attrs) *
341                sizeof (guestfs_int_xattr));
342     if (newptr == NULL) {
343       reply_with_perror ("realloc");
344       goto error;
345     }
346     ret->guestfs_int_xattr_list_val = newptr;
347     ret->guestfs_int_xattr_list_len += nr_attrs;
348
349     /* entry[0] is the special attribute,
350      * entry[1..nr_attrs] are the attributes.
351      */
352     entry = &ret->guestfs_int_xattr_list_val[ret->guestfs_int_xattr_list_len-nr_attrs-1];
353     for (m = 1; m <= nr_attrs; ++m) {
354       entry[m].attrname = NULL;
355       entry[m].attrval.attrval_len = 0;
356       entry[m].attrval.attrval_val = NULL;
357     }
358
359     for (i = 0, j = 0; i < len; i += strlen (&buf[i]) + 1, ++j) {
360       CHROOT_IN;
361       vlen = lgetxattr (pathname, &buf[i], NULL, 0);
362       CHROOT_OUT;
363       if (vlen == -1) {
364         reply_with_perror ("getxattr");
365         goto error;
366       }
367
368       entry[j+1].attrname = strdup (&buf[i]);
369       entry[j+1].attrval.attrval_val = malloc (vlen);
370       entry[j+1].attrval.attrval_len = vlen;
371
372       if (entry[j+1].attrname == NULL ||
373           entry[j+1].attrval.attrval_val == NULL) {
374         reply_with_perror ("malloc");
375         goto error;
376       }
377
378       CHROOT_IN;
379       vlen = lgetxattr (pathname, &buf[i],
380                         entry[j+1].attrval.attrval_val, vlen);
381       CHROOT_OUT;
382       if (vlen == -1) {
383         reply_with_perror ("getxattr");
384         goto error;
385       }
386     }
387
388     free (buf); buf = NULL;
389
390     char num[16];
391     snprintf (num, sizeof num, "%zu", nr_attrs);
392     entry[0].attrval.attrval_len = strlen (num) + 1;
393     entry[0].attrval.attrval_val = strdup (num);
394
395     if (entry[0].attrval.attrval_val == NULL) {
396       reply_with_perror ("strdup");
397       goto error;
398     }
399   }
400
401   /* If verbose, debug what we're about to send back. */
402   if (verbose) {
403     fprintf (stderr, "lxattrlist: returning: [\n");
404     for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
405       const guestfs_int_xattr *entry = &ret->guestfs_int_xattr_list_val[k];
406       if (strcmp (entry[0].attrname, "") != 0) {
407         fprintf (stderr, "ERROR: expecting empty attrname at k = %zu\n", k);
408         break;
409       }
410       fprintf (stderr, "  %zu: special attrval = %s\n",
411                k, entry[0].attrval.attrval_val);
412       for (i = 1; k+i < ret->guestfs_int_xattr_list_len; ++i) {
413         if (strcmp (entry[i].attrname, "") == 0)
414           break;
415         fprintf (stderr, "    name %s, value length %d\n",
416                  entry[i].attrname, entry[i].attrval.attrval_len);
417       }
418       k += i-1;
419     }
420     fprintf (stderr, "]\n");
421   }
422
423   return ret;
424
425  error:
426   free (buf);
427   if (ret) {
428     if (ret->guestfs_int_xattr_list_val) {
429       for (k = 0; k < ret->guestfs_int_xattr_list_len; ++k) {
430         free (ret->guestfs_int_xattr_list_val[k].attrname);
431         free (ret->guestfs_int_xattr_list_val[k].attrval.attrval_val);
432       }
433       free (ret->guestfs_int_xattr_list_val);
434     }
435     free (ret);
436   }
437   return NULL;
438 #else
439   reply_with_error ("lxattrlist: no support for llistxattr and lgetxattr");
440   return NULL;
441 #endif
442 }
443
444 #else /* no xattr.h */
445
446 guestfs_int_xattr_list *
447 do_getxattrs (const char *path)
448 {
449   reply_with_error ("getxattrs: no support for xattrs");
450   return NULL;
451 }
452
453 guestfs_int_xattr_list *
454 do_lgetxattrs (const char *path)
455 {
456   reply_with_error ("lgetxattrs: no support for xattrs");
457   return NULL;
458 }
459
460 int
461 do_setxattr (const char *xattr, const char *val, int vallen, const char *path)
462 {
463   reply_with_error ("setxattr: no support for xattrs");
464   return -1;
465 }
466
467 int
468 do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path)
469 {
470   reply_with_error ("lsetxattr: no support for xattrs");
471   return -1;
472 }
473
474 int
475 do_removexattr (const char *xattr, const char *path)
476 {
477   reply_with_error ("removexattr: no support for xattrs");
478   return -1;
479 }
480
481 int
482 do_lremovexattr (const char *xattr, const char *path)
483 {
484   reply_with_error ("lremovexattr: no support for xattrs");
485   return -1;
486 }
487
488 guestfs_int_xattr_list *
489 do_lxattrlist (const char *path, char *const *names)
490 {
491   reply_with_error ("lxattrlist: no support for xattrs");
492   return NULL;
493 }
494
495 #endif /* no xattr.h */