test-tool: Document the -t command line option.
[libguestfs.git] / fuse / guestmount.c
1 /* guestmount - mount guests using libguestfs and FUSE
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  * Derived from the example program 'fusexmp.c':
19  * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
20  *
21  * This program can be distributed under the terms of the GNU GPL.
22  * See the file COPYING.
23  */
24
25 #define FUSE_USE_VERSION 26
26
27 #include <config.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <inttypes.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <getopt.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <time.h>
41 #include <assert.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <locale.h>
45 #include <libintl.h>
46
47 #include <fuse.h>
48 #include <guestfs.h>
49
50 #include "progname.h"
51
52 #include "guestmount.h"
53 #include "options.h"
54 #include "dircache.h"
55
56 /* See <attr/xattr.h> */
57 #ifndef ENOATTR
58 #define ENOATTR ENODATA
59 #endif
60
61 guestfs_h *g = NULL;
62 int read_only = 0;
63 int live = 0;
64 int verbose = 0;
65 int inspector = 0;
66 int keys_from_stdin = 0;
67 int echo_keys = 0;
68 const char *libvirt_uri;
69 int dir_cache_timeout = 60;
70 static int trace_calls = 0;
71
72 #define TRACE_CALL(fs,...)                                              \
73   if (trace_calls) {                                                    \
74     fprintf (stderr, "%s: %s (" fs ")\n",                               \
75              program_name, __func__, __VA_ARGS__);                      \
76   }
77
78 static int
79 error (void)
80 {
81   return -guestfs_last_errno (g);
82 }
83
84 static struct guestfs_xattr_list *
85 copy_xattr_list (const struct guestfs_xattr *first, size_t num)
86 {
87   struct guestfs_xattr_list *xattrs;
88
89   xattrs = malloc (sizeof *xattrs);
90   if (xattrs == NULL) {
91     perror ("malloc");
92     return NULL;
93   }
94
95   xattrs->len = num;
96   xattrs->val = malloc (num * sizeof (struct guestfs_xattr));
97   if (xattrs->val == NULL) {
98     perror ("malloc");
99     free (xattrs);
100     return NULL;
101   }
102
103   size_t i;
104   for (i = 0; i < num; ++i) {
105     xattrs->val[i].attrname = strdup (first[i].attrname);
106     xattrs->val[i].attrval_len = first[i].attrval_len;
107     xattrs->val[i].attrval = malloc (first[i].attrval_len);
108     memcpy (xattrs->val[i].attrval, first[i].attrval, first[i].attrval_len);
109   }
110
111   return xattrs;
112 }
113
114 static int
115 fg_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
116             off_t offset, struct fuse_file_info *fi)
117 {
118   TRACE_CALL ("%s, %p, %ld", path, buf, (long) offset);
119
120   time_t now;
121   time (&now);
122
123   dir_cache_remove_all_expired (now);
124
125   struct guestfs_dirent_list *ents;
126
127   ents = guestfs_readdir (g, path);
128   if (ents == NULL)
129     return error ();
130
131   size_t i;
132   for (i = 0; i < ents->len; ++i) {
133     struct stat stat;
134     memset (&stat, 0, sizeof stat);
135
136     stat.st_ino = ents->val[i].ino;
137     switch (ents->val[i].ftyp) {
138     case 'b': stat.st_mode = S_IFBLK; break;
139     case 'c': stat.st_mode = S_IFCHR; break;
140     case 'd': stat.st_mode = S_IFDIR; break;
141     case 'f': stat.st_mode = S_IFIFO; break;
142     case 'l': stat.st_mode = S_IFLNK; break;
143     case 'r': stat.st_mode = S_IFREG; break;
144     case 's': stat.st_mode = S_IFSOCK; break;
145     case 'u':
146     case '?':
147     default:  stat.st_mode = 0;
148     }
149
150     /* Copied from the example, which also ignores 'offset'.  I'm
151      * not quite sure how this is ever supposed to work on large
152      * directories. XXX
153      */
154     if (filler (buf, ents->val[i].name, &stat, 0))
155       break;
156   }
157
158   /* Now prepopulate the directory caches.  This step is just an
159    * optimization, don't worry if it fails.
160    */
161   char **names = malloc ((ents->len + 1) * sizeof (char *));
162   if (names) {
163     for (i = 0; i < ents->len; ++i)
164       names[i] = ents->val[i].name;
165     names[i] = NULL;
166
167     struct guestfs_stat_list *ss = guestfs_lstatlist (g, path, names);
168     if (ss) {
169       for (i = 0; i < ss->len; ++i) {
170         if (ss->val[i].ino >= 0) {
171           struct stat statbuf;
172
173           statbuf.st_dev = ss->val[i].dev;
174           statbuf.st_ino = ss->val[i].ino;
175           statbuf.st_mode = ss->val[i].mode;
176           statbuf.st_nlink = ss->val[i].nlink;
177           statbuf.st_uid = ss->val[i].uid;
178           statbuf.st_gid = ss->val[i].gid;
179           statbuf.st_rdev = ss->val[i].rdev;
180           statbuf.st_size = ss->val[i].size;
181           statbuf.st_blksize = ss->val[i].blksize;
182           statbuf.st_blocks = ss->val[i].blocks;
183           statbuf.st_atime = ss->val[i].atime;
184           statbuf.st_mtime = ss->val[i].mtime;
185           statbuf.st_ctime = ss->val[i].ctime;
186
187           lsc_insert (path, names[i], now, &statbuf);
188         }
189       }
190       guestfs_free_stat_list (ss);
191     }
192
193     struct guestfs_xattr_list *xattrs = guestfs_lxattrlist (g, path, names);
194     if (xattrs) {
195       size_t ni, num;
196       struct guestfs_xattr *first;
197       struct guestfs_xattr_list *copy;
198       for (i = 0, ni = 0; i < xattrs->len; ++i, ++ni) {
199         assert (strlen (xattrs->val[i].attrname) == 0);
200         if (xattrs->val[i].attrval_len > 0) {
201           ++i;
202           first = &xattrs->val[i];
203           num = 0;
204           for (; i < xattrs->len && strlen (xattrs->val[i].attrname) > 0; ++i)
205             num++;
206
207           copy = copy_xattr_list (first, num);
208           if (copy)
209             xac_insert (path, names[ni], now, copy);
210
211           i--;
212         }
213       }
214       guestfs_free_xattr_list (xattrs);
215     }
216
217     char **links = guestfs_readlinklist (g, path, names);
218     if (links) {
219       for (i = 0; names[i] != NULL; ++i) {
220         if (links[i][0])
221           /* Note that rlc_insert owns the string links[i] after this, */
222           rlc_insert (path, names[i], now, links[i]);
223         else
224           /* which is why we have to free links[i] here. */
225           free (links[i]);
226       }
227       free (links);             /* free the array, not the strings */
228     }
229
230     free (names);
231   }
232
233   guestfs_free_dirent_list (ents);
234
235   return 0;
236 }
237
238 static int
239 fg_getattr (const char *path, struct stat *statbuf)
240 {
241   TRACE_CALL ("%s, %p", path, statbuf);
242
243   const struct stat *buf;
244
245   buf = lsc_lookup (path);
246   if (buf) {
247     memcpy (statbuf, buf, sizeof *statbuf);
248     return 0;
249   }
250
251   struct guestfs_stat *r;
252
253   r = guestfs_lstat (g, path);
254   if (r == NULL)
255     return error ();
256
257   statbuf->st_dev = r->dev;
258   statbuf->st_ino = r->ino;
259   statbuf->st_mode = r->mode;
260   statbuf->st_nlink = r->nlink;
261   statbuf->st_uid = r->uid;
262   statbuf->st_gid = r->gid;
263   statbuf->st_rdev = r->rdev;
264   statbuf->st_size = r->size;
265   statbuf->st_blksize = r->blksize;
266   statbuf->st_blocks = r->blocks;
267   statbuf->st_atime = r->atime;
268   statbuf->st_mtime = r->mtime;
269   statbuf->st_ctime = r->ctime;
270
271   guestfs_free_stat (r);
272
273   return 0;
274 }
275
276 /* Nautilus loves to use access(2) to test everything about a file,
277  * such as whether it's executable.  Therefore treat this a lot like
278  * fg_getattr.
279  */
280 static int
281 fg_access (const char *path, int mask)
282 {
283   TRACE_CALL ("%s, %d", path, mask);
284
285   struct stat statbuf;
286   int r;
287
288   if (read_only && (mask & W_OK))
289     return -EROFS;
290
291   r = fg_getattr (path, &statbuf);
292   if (r < 0 || mask == F_OK)
293     return r;
294
295   struct fuse_context *fuse = fuse_get_context ();
296   int ok = 1;
297
298   if (mask & R_OK)
299     ok = ok &&
300       (  fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IRUSR
301        : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IRGRP
302        : statbuf.st_mode & S_IROTH);
303   if (mask & W_OK)
304     ok = ok &&
305       (  fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IWUSR
306        : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IWGRP
307        : statbuf.st_mode & S_IWOTH);
308   if (mask & X_OK)
309     ok = ok &&
310       (  fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IXUSR
311        : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IXGRP
312        : statbuf.st_mode & S_IXOTH);
313
314   return ok ? 0 : -EACCES;
315 }
316
317 static int
318 fg_readlink (const char *path, char *buf, size_t size)
319 {
320   TRACE_CALL ("%s, %p, %zu", path, buf, size);
321
322   const char *r;
323   int free_it = 0;
324
325   r = rlc_lookup (path);
326   if (!r) {
327     r = guestfs_readlink (g, path);
328     if (r == NULL)
329       return error ();
330     free_it = 1;
331   }
332
333   /* Note this is different from the real readlink(2) syscall.  FUSE wants
334    * the string to be always nul-terminated, even if truncated.
335    */
336   size_t len = strlen (r);
337   if (len > size - 1)
338     len = size - 1;
339
340   memcpy (buf, r, len);
341   buf[len] = '\0';
342
343   if (free_it) {
344     char *tmp = (char *) r;
345     free (tmp);
346   }
347
348   return 0;
349 }
350
351 static int
352 fg_mknod (const char *path, mode_t mode, dev_t rdev)
353 {
354   TRACE_CALL ("%s, 0%o, 0x%lx", path, mode, (long) rdev);
355
356   int r;
357
358   if (read_only) return -EROFS;
359
360   dir_cache_invalidate (path);
361
362   r = guestfs_mknod (g, mode, major (rdev), minor (rdev), path);
363   if (r == -1)
364     return error ();
365
366   return 0;
367 }
368
369 static int
370 fg_mkdir (const char *path, mode_t mode)
371 {
372   TRACE_CALL ("%s, 0%o", path, mode);
373
374   int r;
375
376   if (read_only) return -EROFS;
377
378   dir_cache_invalidate (path);
379
380   r = guestfs_mkdir_mode (g, path, mode);
381   if (r == -1)
382     return error ();
383
384   return 0;
385 }
386
387 static int
388 fg_unlink (const char *path)
389 {
390   TRACE_CALL ("%s", path);
391
392   int r;
393
394   if (read_only) return -EROFS;
395
396   dir_cache_invalidate (path);
397
398   r = guestfs_rm (g, path);
399   if (r == -1)
400     return error ();
401
402   return 0;
403 }
404
405 static int
406 fg_rmdir (const char *path)
407 {
408   TRACE_CALL ("%s", path);
409
410   int r;
411
412   if (read_only) return -EROFS;
413
414   dir_cache_invalidate (path);
415
416   r = guestfs_rmdir (g, path);
417   if (r == -1)
418     return error ();
419
420   return 0;
421 }
422
423 static int
424 fg_symlink (const char *from, const char *to)
425 {
426   TRACE_CALL ("%s, %s", from, to);
427
428   int r;
429
430   if (read_only) return -EROFS;
431
432   dir_cache_invalidate (to);
433
434   r = guestfs_ln_s (g, from, to);
435   if (r == -1)
436     return error ();
437
438   return 0;
439 }
440
441 static int
442 fg_rename (const char *from, const char *to)
443 {
444   TRACE_CALL ("%s, %s", from, to);
445
446   int r;
447
448   if (read_only) return -EROFS;
449
450   dir_cache_invalidate (from);
451   dir_cache_invalidate (to);
452
453   /* XXX It's not clear how close the 'mv' command is to the
454    * rename syscall.  We might need to add the rename syscall
455    * to the guestfs(3) API.
456    */
457   r = guestfs_mv (g, from, to);
458   if (r == -1)
459     return error ();
460
461   return 0;
462 }
463
464 static int
465 fg_link (const char *from, const char *to)
466 {
467   TRACE_CALL ("%s, %s", from, to);
468
469   int r;
470
471   if (read_only) return -EROFS;
472
473   dir_cache_invalidate (from);
474   dir_cache_invalidate (to);
475
476   r = guestfs_ln (g, from, to);
477   if (r == -1)
478     return error ();
479
480   return 0;
481 }
482
483 static int
484 fg_chmod (const char *path, mode_t mode)
485 {
486   TRACE_CALL ("%s, 0%o", path, mode);
487
488   int r;
489
490   if (read_only) return -EROFS;
491
492   dir_cache_invalidate (path);
493
494   r = guestfs_chmod (g, mode, path);
495   if (r == -1)
496     return error ();
497
498   return 0;
499 }
500
501 static int
502 fg_chown (const char *path, uid_t uid, gid_t gid)
503 {
504   TRACE_CALL ("%s, %ld, %ld", path, (long) uid, (long) gid);
505
506   int r;
507
508   if (read_only) return -EROFS;
509
510   dir_cache_invalidate (path);
511
512   r = guestfs_lchown (g, uid, gid, path);
513   if (r == -1)
514     return error ();
515
516   return 0;
517 }
518
519 static int
520 fg_truncate (const char *path, off_t size)
521 {
522   TRACE_CALL ("%s, %ld", path, (long) size);
523
524   int r;
525
526   if (read_only) return -EROFS;
527
528   dir_cache_invalidate (path);
529
530   r = guestfs_truncate_size (g, path, size);
531   if (r == -1)
532     return error ();
533
534   return 0;
535 }
536
537 static int
538 fg_utimens (const char *path, const struct timespec ts[2])
539 {
540   TRACE_CALL ("%s, [{ %ld, %ld }, { %ld, %ld }]",
541               path, ts[0].tv_sec, ts[0].tv_nsec, ts[1].tv_sec, ts[1].tv_nsec);
542
543   int r;
544
545   if (read_only) return -EROFS;
546
547   dir_cache_invalidate (path);
548
549   time_t atsecs = ts[0].tv_sec;
550   long atnsecs = ts[0].tv_nsec;
551   time_t mtsecs = ts[1].tv_sec;
552   long mtnsecs = ts[1].tv_nsec;
553
554 #ifdef UTIME_NOW
555   if (atnsecs == UTIME_NOW)
556     atnsecs = -1;
557 #endif
558 #ifdef UTIME_OMIT
559   if (atnsecs == UTIME_OMIT)
560     atnsecs = -2;
561 #endif
562 #ifdef UTIME_NOW
563   if (mtnsecs == UTIME_NOW)
564     mtnsecs = -1;
565 #endif
566 #ifdef UTIME_OMIT
567   if (mtnsecs == UTIME_OMIT)
568     mtnsecs = -2;
569 #endif
570
571   r = guestfs_utimens (g, path, atsecs, atnsecs, mtsecs, mtnsecs);
572   if (r == -1)
573     return error ();
574
575   return 0;
576 }
577
578 /* All this function needs to do is to check that the requested open
579  * flags are valid.  See the notes in <fuse/fuse.h>.
580  */
581 static int
582 fg_open (const char *path, struct fuse_file_info *fi)
583 {
584   TRACE_CALL ("%s, 0%o", path, fi->flags);
585              
586   int flags = fi->flags & 3;
587
588   if (read_only && flags != O_RDONLY)
589     return -EROFS;
590
591   return 0;
592 }
593
594 static int
595 fg_read (const char *path, char *buf, size_t size, off_t offset,
596          struct fuse_file_info *fi)
597 {
598   TRACE_CALL ("%s, %p, %zu, %ld", path, buf, size, offset);
599              
600   char *r;
601   size_t rsize;
602
603   if (verbose)
604     fprintf (stderr, "fg_read: %s: size %zu offset %ju\n",
605              path, size, offset);
606
607   /* The guestfs protocol limits size to somewhere over 2MB.  We just
608    * reduce the requested size here accordingly and push the problem
609    * up to every user.  http://www.jwz.org/doc/worse-is-better.html
610    */
611   const size_t limit = 2 * 1024 * 1024;
612   if (size > limit)
613     size = limit;
614
615   r = guestfs_pread (g, path, size, offset, &rsize);
616   if (r == NULL)
617     return error ();
618
619   /* This should never happen, but at least it stops us overflowing
620    * the output buffer if it does happen.
621    */
622   if (rsize > size)
623     rsize = size;
624
625   memcpy (buf, r, rsize);
626   free (r);
627
628   return rsize;
629 }
630
631 static int
632 fg_write (const char *path, const char *buf, size_t size,
633           off_t offset, struct fuse_file_info *fi)
634 {
635   TRACE_CALL ("%s, %p, %zu, %ld", path, buf, size, offset);
636
637   if (read_only) return -EROFS;
638
639   dir_cache_invalidate (path);
640
641   /* See fg_read. */
642   const size_t limit = 2 * 1024 * 1024;
643   if (size > limit)
644     size = limit;
645
646   int r;
647   r = guestfs_pwrite (g, path, buf, size, offset);
648   if (r == -1)
649     return error ();
650
651   return r;
652 }
653
654 static int
655 fg_statfs (const char *path, struct statvfs *stbuf)
656 {
657   TRACE_CALL ("%s, %p", path, stbuf);
658
659   struct guestfs_statvfs *r;
660
661   r = guestfs_statvfs (g, path);
662   if (r == NULL)
663     return error ();
664
665   stbuf->f_bsize = r->bsize;
666   stbuf->f_frsize = r->frsize;
667   stbuf->f_blocks = r->blocks;
668   stbuf->f_bfree = r->bfree;
669   stbuf->f_bavail = r->bavail;
670   stbuf->f_files = r->files;
671   stbuf->f_ffree = r->ffree;
672   stbuf->f_favail = r->favail;
673   stbuf->f_fsid = r->fsid;
674   stbuf->f_flag = r->flag;
675   stbuf->f_namemax = r->namemax;
676
677   guestfs_free_statvfs (r);
678
679   return 0;
680 }
681
682 static int
683 fg_release (const char *path, struct fuse_file_info *fi)
684 {
685   TRACE_CALL ("%s", path);
686
687   /* Just a stub. This method is optional and can safely be left
688    * unimplemented.
689    */
690   return 0;
691 }
692
693 /* Emulate this by calling sync. */
694 static int fg_fsync(const char *path, int isdatasync,
695                      struct fuse_file_info *fi)
696 {
697   TRACE_CALL ("%s, %d", path, isdatasync);
698
699   int r;
700
701   r = guestfs_sync (g);
702   if (r == -1)
703     return error ();
704
705   return 0;
706 }
707
708 static int
709 fg_setxattr (const char *path, const char *name, const char *value,
710              size_t size, int flags)
711 {
712   TRACE_CALL ("%s, %s, %p, %zu", path, name, value, size);
713
714   int r;
715
716   if (read_only) return -EROFS;
717
718   dir_cache_invalidate (path);
719
720   /* XXX Underlying guestfs(3) API doesn't understand the flags. */
721   r = guestfs_lsetxattr (g, name, value, size, path);
722   if (r == -1)
723     return error ();
724
725   return 0;
726 }
727
728 /* The guestfs(3) API for getting xattrs is much easier to use
729  * than the real syscall.  Unfortunately we now have to emulate
730  * the real syscall using that API :-(
731  */
732 static int
733 fg_getxattr (const char *path, const char *name, char *value,
734              size_t size)
735 {
736   TRACE_CALL ("%s, %s, %p, %zu", path, name, value, size);
737
738   const struct guestfs_xattr_list *xattrs;
739   int free_attrs = 0;
740
741   xattrs = xac_lookup (path);
742   if (xattrs == NULL) {
743     xattrs = guestfs_lgetxattrs (g, path);
744     if (xattrs == NULL)
745       return error ();
746     free_attrs = 1;
747   }
748
749   /* Find the matching attribute (index in 'i'). */
750   ssize_t r;
751   size_t i;
752   for (i = 0; i < xattrs->len; ++i) {
753     if (STREQ (xattrs->val[i].attrname, name))
754       break;
755   }
756
757   if (i == xattrs->len) {       /* not found */
758     r = -ENOATTR;
759     goto out;
760   }
761
762   /* The getxattr man page is unclear, but if value == NULL then we
763    * return the space required (the caller then makes a second syscall
764    * after allocating the required amount of space).  If value != NULL
765    * then it's not clear what we should do, but it appears we should
766    * copy as much as possible and return -ERANGE if there's not enough
767    * space in the buffer.
768    */
769   size_t sz = xattrs->val[i].attrval_len;
770   if (value == NULL) {
771     r = sz;
772     goto out;
773   }
774
775   if (sz <= size)
776     r = sz;
777   else {
778     r = -ERANGE;
779     sz = size;
780   }
781   memcpy (value, xattrs->val[i].attrval, sz);
782
783 out:
784   if (free_attrs)
785     guestfs_free_xattr_list ((struct guestfs_xattr_list *) xattrs);
786
787   return r;
788 }
789
790 /* Ditto as above. */
791 static int
792 fg_listxattr (const char *path, char *list, size_t size)
793 {
794   TRACE_CALL ("%s, %p, %zu", path, list, size);
795
796   const struct guestfs_xattr_list *xattrs;
797   int free_attrs = 0;
798
799   xattrs = xac_lookup (path);
800   if (xattrs == NULL) {
801     xattrs = guestfs_lgetxattrs (g, path);
802     if (xattrs == NULL)
803       return error ();
804     free_attrs = 1;
805   }
806
807   /* Calculate how much space is required to hold the result. */
808   size_t space = 0;
809   size_t len;
810   size_t i;
811   for (i = 0; i < xattrs->len; ++i) {
812     len = strlen (xattrs->val[i].attrname) + 1;
813     space += len;
814   }
815
816   /* The listxattr man page is unclear, but if list == NULL then we
817    * return the space required (the caller then makes a second syscall
818    * after allocating the required amount of space).  If list != NULL
819    * then it's not clear what we should do, but it appears we should
820    * copy as much as possible and return -ERANGE if there's not enough
821    * space in the buffer.
822    */
823   ssize_t r;
824   if (list == NULL) {
825     r = space;
826     goto out;
827   }
828
829   r = 0;
830   for (i = 0; i < xattrs->len; ++i) {
831     len = strlen (xattrs->val[i].attrname) + 1;
832     if (size >= len) {
833       memcpy (list, xattrs->val[i].attrname, len);
834       size -= len;
835       list += len;
836       r += len;
837     } else {
838       r = -ERANGE;
839       break;
840     }
841   }
842
843  out:
844   if (free_attrs)
845     guestfs_free_xattr_list ((struct guestfs_xattr_list *) xattrs);
846
847   return r;
848 }
849
850 static int
851 fg_removexattr(const char *path, const char *name)
852 {
853   TRACE_CALL ("%s, %s", path, name);
854
855   int r;
856
857   if (read_only) return -EROFS;
858
859   dir_cache_invalidate (path);
860
861   r = guestfs_lremovexattr (g, name, path);
862   if (r == -1)
863     return error ();
864
865   return 0;
866 }
867
868 static struct fuse_operations fg_operations = {
869   .getattr      = fg_getattr,
870   .access       = fg_access,
871   .readlink     = fg_readlink,
872   .readdir      = fg_readdir,
873   .mknod        = fg_mknod,
874   .mkdir        = fg_mkdir,
875   .symlink      = fg_symlink,
876   .unlink       = fg_unlink,
877   .rmdir        = fg_rmdir,
878   .rename       = fg_rename,
879   .link         = fg_link,
880   .chmod        = fg_chmod,
881   .chown        = fg_chown,
882   .truncate     = fg_truncate,
883   .utimens      = fg_utimens,
884   .open         = fg_open,
885   .read         = fg_read,
886   .write        = fg_write,
887   .statfs       = fg_statfs,
888   .release      = fg_release,
889   .fsync        = fg_fsync,
890   .setxattr     = fg_setxattr,
891   .getxattr     = fg_getxattr,
892   .listxattr    = fg_listxattr,
893   .removexattr  = fg_removexattr,
894 };
895
896 static void __attribute__((noreturn))
897 fuse_help (void)
898 {
899   const char *tmp_argv[] = { program_name, "--help", NULL };
900   fuse_main (2, (char **) tmp_argv, &fg_operations, NULL);
901   exit (EXIT_SUCCESS);
902 }
903
904 static void __attribute__((noreturn))
905 usage (int status)
906 {
907   if (status != EXIT_SUCCESS)
908     fprintf (stderr, _("Try `%s --help' for more information.\n"),
909              program_name);
910   else {
911     fprintf (stdout,
912            _("%s: FUSE module for libguestfs\n"
913              "%s lets you mount a virtual machine filesystem\n"
914              "Copyright (C) 2009-2010 Red Hat Inc.\n"
915              "Usage:\n"
916              "  %s [--options] [-- [--FUSE-options]] mountpoint\n"
917              "Options:\n"
918              "  -a|--add image       Add image\n"
919              "  -c|--connect uri     Specify libvirt URI for -d option\n"
920              "  --dir-cache-timeout  Set readdir cache timeout (default 5 sec)\n"
921              "  -d|--domain guest    Add disks from libvirt guest\n"
922              "  --echo-keys          Don't turn off echo for passphrases\n"
923              "  --format[=raw|..]    Force disk format for -a option\n"
924              "  --fuse-help          Display extra FUSE options\n"
925              "  -i|--inspector       Automatically mount filesystems\n"
926              "  --help               Display help message and exit\n"
927              "  --keys-from-stdin    Read passphrases from stdin\n"
928              "  --live               Connect to a live virtual machine\n"
929              "  -m|--mount dev[:mnt[:opts]] Mount dev on mnt (if omitted, /)\n"
930              "  -n|--no-sync         Don't autosync\n"
931              "  -o|--option opt      Pass extra option to FUSE\n"
932              "  -r|--ro              Mount read-only\n"
933              "  --selinux            Enable SELinux support\n"
934              "  -v|--verbose         Verbose messages\n"
935              "  -V|--version         Display version and exit\n"
936              "  -w|--rw              Mount read-write\n"
937              "  -x|--trace           Trace guestfs API calls\n"
938              ),
939              program_name, program_name, program_name);
940   }
941   exit (status);
942 }
943
944 int
945 main (int argc, char *argv[])
946 {
947   setlocale (LC_ALL, "");
948   bindtextdomain (PACKAGE, LOCALEBASEDIR);
949   textdomain (PACKAGE);
950
951   parse_config ();
952
953   enum { HELP_OPTION = CHAR_MAX + 1 };
954
955   /* The command line arguments are broadly compatible with (a subset
956    * of) guestfish.  Thus we have to deal mainly with -a, -m and --ro.
957    */
958   static const char *options = "a:c:d:im:no:rv?Vwx";
959   static const struct option long_options[] = {
960     { "add", 1, 0, 'a' },
961     { "connect", 1, 0, 'c' },
962     { "dir-cache-timeout", 1, 0, 0 },
963     { "domain", 1, 0, 'd' },
964     { "echo-keys", 0, 0, 0 },
965     { "format", 2, 0, 0 },
966     { "fuse-help", 0, 0, 0 },
967     { "help", 0, 0, HELP_OPTION },
968     { "inspector", 0, 0, 'i' },
969     { "keys-from-stdin", 0, 0, 0 },
970     { "live", 0, 0, 0 },
971     { "mount", 1, 0, 'm' },
972     { "no-sync", 0, 0, 'n' },
973     { "option", 1, 0, 'o' },
974     { "ro", 0, 0, 'r' },
975     { "rw", 0, 0, 'w' },
976     { "selinux", 0, 0, 0 },
977     { "trace", 0, 0, 'x' },
978     { "verbose", 0, 0, 'v' },
979     { "version", 0, 0, 'V' },
980     { 0, 0, 0, 0 }
981   };
982
983   struct drv *drvs = NULL;
984   struct drv *drv;
985   struct mp *mps = NULL;
986   struct mp *mp;
987   char *p;
988   const char *format = NULL;
989   int c, r;
990   int option_index;
991   struct sigaction sa;
992
993   int fuse_argc = 0;
994   const char **fuse_argv = NULL;
995
996 #define ADD_FUSE_ARG(str)                                               \
997   do {                                                                  \
998     fuse_argc ++;                                                       \
999     fuse_argv = realloc (fuse_argv, (1+fuse_argc) * sizeof (char *));   \
1000     if (!fuse_argv) {                                                   \
1001       perror ("realloc");                                               \
1002       exit (EXIT_FAILURE);                                                         \
1003     }                                                                   \
1004     fuse_argv[fuse_argc-1] = (str);                                     \
1005     fuse_argv[fuse_argc] = NULL;                                        \
1006   } while (0)
1007
1008   /* LC_ALL=C is required so we can parse error messages. */
1009   setenv ("LC_ALL", "C", 1);
1010
1011   /* Set global program name that is not polluted with libtool artifacts.  */
1012   set_program_name (argv[0]);
1013
1014   memset (&sa, 0, sizeof sa);
1015   sa.sa_handler = SIG_IGN;
1016   sa.sa_flags = SA_RESTART;
1017   sigaction (SIGPIPE, &sa, NULL);
1018
1019   /* Various initialization. */
1020   init_dir_caches ();
1021
1022   g = guestfs_create ();
1023   if (g == NULL) {
1024     fprintf (stderr, _("guestfs_create: failed to create handle\n"));
1025     exit (EXIT_FAILURE);
1026   }
1027
1028   guestfs_set_recovery_proc (g, 0);
1029
1030   ADD_FUSE_ARG (program_name);
1031   /* MUST be single-threaded.  You cannot have two threads accessing the
1032    * same libguestfs handle, and opening more than one handle is likely
1033    * to be very expensive.
1034    */
1035   ADD_FUSE_ARG ("-s");
1036
1037   for (;;) {
1038     c = getopt_long (argc, argv, options, long_options, &option_index);
1039     if (c == -1) break;
1040
1041     switch (c) {
1042     case 0:                     /* options which are long only */
1043       if (STREQ (long_options[option_index].name, "dir-cache-timeout"))
1044         dir_cache_timeout = atoi (optarg);
1045       else if (STREQ (long_options[option_index].name, "fuse-help"))
1046         fuse_help ();
1047       else if (STREQ (long_options[option_index].name, "selinux"))
1048         guestfs_set_selinux (g, 1);
1049       else if (STREQ (long_options[option_index].name, "format")) {
1050         if (!optarg || STREQ (optarg, ""))
1051           format = NULL;
1052         else
1053           format = optarg;
1054       } else if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
1055         keys_from_stdin = 1;
1056       } else if (STREQ (long_options[option_index].name, "echo-keys")) {
1057         echo_keys = 1;
1058       } else if (STREQ (long_options[option_index].name, "live")) {
1059         live = 1;
1060       } else {
1061         fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
1062                  program_name, long_options[option_index].name, option_index);
1063         exit (EXIT_FAILURE);
1064       }
1065       break;
1066
1067     case 'a':
1068       OPTION_a;
1069       break;
1070
1071     case 'c':
1072       OPTION_c;
1073       break;
1074
1075     case 'd':
1076       OPTION_d;
1077       break;
1078
1079     case 'i':
1080       OPTION_i;
1081       break;
1082
1083     case 'm':
1084       OPTION_m;
1085       break;
1086
1087     case 'n':
1088       OPTION_n;
1089       break;
1090
1091     case 'o':
1092       ADD_FUSE_ARG ("-o");
1093       ADD_FUSE_ARG (optarg);
1094       break;
1095
1096     case 'r':
1097       OPTION_r;
1098       break;
1099
1100     case 'v':
1101       OPTION_v;
1102       break;
1103
1104     case 'V':
1105       OPTION_V;
1106       break;
1107
1108     case 'w':
1109       OPTION_w;
1110       break;
1111
1112     case 'x':
1113       OPTION_x;
1114       ADD_FUSE_ARG ("-f");
1115       guestfs_set_recovery_proc (g, 1);
1116       trace_calls = 1;
1117       break;
1118
1119     case HELP_OPTION:
1120       usage (EXIT_SUCCESS);
1121
1122     default:
1123       usage (EXIT_FAILURE);
1124     }
1125   }
1126
1127   /* Check we have the right options. */
1128   if (!drvs || !(mps || inspector)) {
1129     fprintf (stderr,
1130              _("%s: must have at least one -a/-d and at least one -m/-i option\n"),
1131              program_name);
1132     exit (EXIT_FAILURE);
1133   }
1134
1135   /* We'd better have a mountpoint. */
1136   if (optind+1 != argc) {
1137     fprintf (stderr,
1138              _("%s: you must specify a mountpoint in the host filesystem\n"),
1139              program_name);
1140     exit (EXIT_FAILURE);
1141   }
1142
1143   /* Do the guest drives and mountpoints. */
1144   add_drives (drvs, 'a');
1145   if (guestfs_launch (g) == -1)
1146     exit (EXIT_FAILURE);
1147   if (inspector)
1148     inspect_mount ();
1149   mount_mps (mps);
1150
1151   free_drives (drvs);
1152   free_mps (mps);
1153
1154   /* FUSE example does this, not clear if it's necessary, but ... */
1155   if (guestfs_umask (g, 0) == -1)
1156     exit (EXIT_FAILURE);
1157
1158   /* At the last minute, remove the libguestfs error handler.  In code
1159    * above this point, the default error handler has been used which
1160    * sends all errors to stderr.  Now before entering FUSE itself we
1161    * want to silence errors so we can convert them (see error()
1162    * function above).
1163    */
1164   guestfs_set_error_handler (g, NULL, NULL);
1165
1166   /* Finish off FUSE args. */
1167   ADD_FUSE_ARG (argv[optind]);
1168
1169   /*
1170     It says about the line containing the for-statement:
1171     error: assuming signed overflow does not occur when simplifying conditional to constant [-Wstrict-overflow]
1172
1173   if (verbose) {
1174     fprintf (stderr, "guestmount: invoking FUSE with args [");
1175     for (i = 0; i < fuse_argc; ++i) {
1176       if (i > 0) fprintf (stderr, ", ");
1177       fprintf (stderr, "%s", fuse_argv[i]);
1178     }
1179     fprintf (stderr, "]\n");
1180   }
1181   */
1182
1183   r = fuse_main (fuse_argc, (char **) fuse_argv, &fg_operations, NULL);
1184
1185   /* Cleanup. */
1186   guestfs_close (g);
1187   free_dir_caches ();
1188
1189   exit (r == -1 ? 1 : 0);
1190 }