Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rbd_fuse / rbd-fuse.cc
1 /*
2  * rbd-fuse
3  */
4 #define FUSE_USE_VERSION 30
5
6 #include "include/int_types.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <fuse.h>
15 #include <pthread.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <assert.h>
21 #include <string>
22 #include <mutex>
23
24 #if defined(__FreeBSD__)
25 #include <sys/param.h>
26 #endif
27
28 #include "include/compat.h"
29 #include "include/rbd/librbd.h"
30
31 static int gotrados = 0;
32 char *pool_name;
33 char *mount_image_name;
34 rados_t cluster;
35 rados_ioctx_t ioctx;
36
37 std::mutex readdir_lock;
38
39 struct rbd_stat {
40         u_char valid;
41         rbd_image_info_t rbd_info;
42 };
43
44 struct rbd_options {
45         char *ceph_config;
46         char *pool_name;
47         char *image_name;
48 };
49
50 struct rbd_image {
51         char *image_name;
52         struct rbd_image *next;
53 };
54 struct rbd_image_data {
55     struct rbd_image *images;
56     void *buf;
57 };
58 struct rbd_image_data rbd_image_data;
59
60 struct rbd_openimage {
61         char *image_name;
62         rbd_image_t image;
63         struct rbd_stat rbd_stat;
64 };
65 #define MAX_RBD_IMAGES          128
66 struct rbd_openimage opentbl[MAX_RBD_IMAGES];
67
68 struct rbd_options rbd_options = {(char*) "/etc/ceph/ceph.conf", (char*) "rbd",
69                                   NULL};
70
71 #define rbdsize(fd)     opentbl[fd].rbd_stat.rbd_info.size
72 #define rbdblksize(fd)  opentbl[fd].rbd_stat.rbd_info.obj_size
73 #define rbdblkcnt(fd)   opentbl[fd].rbd_stat.rbd_info.num_objs
74
75 uint64_t imagesize = 1024ULL * 1024 * 1024;
76 uint64_t imageorder = 22ULL;
77 uint64_t imagefeatures = 1ULL;
78
79 // Minimize calls to rbd_list: marks bracketing of opendir/<ops>/releasedir
80 int in_opendir;
81
82 /* prototypes */
83 int connect_to_cluster(rados_t *pcluster);
84 void enumerate_images(struct rbd_image_data *data);
85 int open_rbd_image(const char *image_name);
86 int find_openrbd(const char *path);
87
88 void simple_err(const char *msg, int err);
89
90 void
91 enumerate_images(struct rbd_image_data *data)
92 {
93         struct rbd_image **head = &data->images;
94         char *ibuf = NULL;
95         size_t ibuf_len = 0;
96         struct rbd_image *im, *next;
97         char *ip;
98         int ret;
99
100         if (*head != NULL) {
101                 for (im = *head; im != NULL;) {
102                         next = im->next;
103                         free(im);
104                         im = next;
105                 }
106                 *head = NULL;
107                 free(data->buf);
108                 data->buf = NULL;
109         }
110
111         ret = rbd_list(ioctx, ibuf, &ibuf_len);
112         if (ret == -ERANGE) {
113                 assert(ibuf_len > 0);
114                 ibuf = (char*) malloc(ibuf_len);
115                 if (!ibuf) {
116                         simple_err("Failed to get ibuf", -ENOMEM);
117                         return;
118                 }
119         } else if (ret < 0) {
120                 simple_err("Failed to get ibuf_len", ret);
121                 return;
122         }
123
124         ret = rbd_list(ioctx, ibuf, &ibuf_len);
125         if (ret < 0) {
126                 simple_err("Failed to populate ibuf", ret);
127                 free(ibuf);
128                 return;
129         }
130         assert(ret == (int)ibuf_len);
131
132         fprintf(stderr, "pool %s: ", pool_name);
133         for (ip = ibuf; ip < &ibuf[ibuf_len]; ip += strlen(ip) + 1)  {
134                 if ((mount_image_name == NULL) ||
135                     ((strlen(mount_image_name) > 0) &&
136                     (strcmp(ip, mount_image_name) == 0))) {
137                         fprintf(stderr, "%s, ", ip);
138                         im = static_cast<rbd_image*>(malloc(sizeof(*im)));
139                         im->image_name = ip;
140                         im->next = *head;
141                         *head = im;
142                 }
143         }
144         fprintf(stderr, "\n");
145         data->buf = ibuf;
146 }
147
148 int
149 find_openrbd(const char *path)
150 {
151         int i;
152
153         /* find in opentbl[] entry if already open */
154         for (i = 0; i < MAX_RBD_IMAGES; i++) {
155                 if ((opentbl[i].image_name != NULL) &&
156                     (strcmp(opentbl[i].image_name, path) == 0)) {
157                         return i;
158                 }
159         }
160         return -1;
161 }
162
163 int
164 open_rbd_image(const char *image_name)
165 {
166         struct rbd_image *im;
167         struct rbd_openimage *rbd = NULL;
168         int fd;
169
170         if (image_name == (char *)NULL) 
171                 return -1;
172
173         // relies on caller to keep rbd_image_data up to date
174         for (im = rbd_image_data.images; im != NULL; im = im->next) {
175                 if (strcmp(im->image_name, image_name) == 0) {
176                         break;
177                 }
178         }
179         if (im == NULL)
180                 return -1;
181
182         /* find in opentbl[] entry if already open */
183         if ((fd = find_openrbd(image_name)) != -1) {
184                 rbd = &opentbl[fd];
185         } else {
186                 int i;
187                 // allocate an opentbl[] and open the image
188                 for (i = 0; i < MAX_RBD_IMAGES; i++) {
189                         if (opentbl[i].image == NULL) {
190                                 fd = i;
191                                 rbd = &opentbl[fd];
192                                 rbd->image_name = strdup(image_name);
193                                 break;
194                         }
195                 }
196                 if (i == MAX_RBD_IMAGES || !rbd)
197                         return -1;
198                 int ret = rbd_open(ioctx, rbd->image_name, &(rbd->image), NULL);
199                 if (ret < 0) {
200                         simple_err("open_rbd_image: can't open: ", ret);
201                         return ret;
202                 }
203         }
204         rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
205                  sizeof(rbd_image_info_t));
206         rbd->rbd_stat.valid = 1;
207         return fd;
208 }
209
210 static void
211 iter_images(void *cookie,
212             void (*iter)(void *cookie, const char *image))
213 {
214         struct rbd_image *im;
215
216         readdir_lock.lock();
217
218         for (im = rbd_image_data.images; im != NULL; im = im->next)
219                 iter(cookie, im->image_name);
220         readdir_lock.unlock();
221 }
222
223 static void count_images_cb(void *cookie, const char *image)
224 {
225         (*((unsigned int *)cookie))++;
226 }
227
228 static int count_images(void)
229 {
230         unsigned int count = 0;
231
232         readdir_lock.lock();
233         enumerate_images(&rbd_image_data);
234         readdir_lock.unlock();
235
236         iter_images(&count, count_images_cb);
237         return count;
238 }
239
240 extern "C" {
241
242 static int rbdfs_getattr(const char *path, struct stat *stbuf)
243 {
244         int fd;
245         time_t now;
246
247         if (!gotrados)
248                 return -ENXIO;
249
250         if (path[0] == 0)
251                 return -ENOENT;
252
253         memset(stbuf, 0, sizeof(struct stat));
254
255         if (strcmp(path, "/") == 0) {
256
257                 now = time(NULL);
258                 stbuf->st_mode = S_IFDIR + 0755;
259                 stbuf->st_nlink = 2+count_images();
260                 stbuf->st_uid = getuid();
261                 stbuf->st_gid = getgid();
262                 stbuf->st_size = 1024;
263                 stbuf->st_blksize = 1024;
264                 stbuf->st_blocks = 1;
265                 stbuf->st_atime = now;
266                 stbuf->st_mtime = now;
267                 stbuf->st_ctime = now;
268
269                 return 0;
270         }
271
272         if (!in_opendir) {
273                 readdir_lock.lock();
274                 enumerate_images(&rbd_image_data);
275                 readdir_lock.unlock();
276         }
277         fd = open_rbd_image(path + 1);
278         if (fd < 0)
279                 return -ENOENT;
280
281         now = time(NULL);
282         stbuf->st_mode = S_IFREG | 0666;
283         stbuf->st_nlink = 1;
284         stbuf->st_uid = getuid();
285         stbuf->st_gid = getgid();
286         stbuf->st_size = rbdsize(fd);
287         stbuf->st_blksize = rbdblksize(fd);
288         stbuf->st_blocks = rbdblkcnt(fd);
289         stbuf->st_atime = now;
290         stbuf->st_mtime = now;
291         stbuf->st_ctime = now;
292
293         return 0;
294 }
295
296
297 static int rbdfs_open(const char *path, struct fuse_file_info *fi)
298 {
299         int fd;
300
301         if (!gotrados)
302                 return -ENXIO;
303
304         if (path[0] == 0)
305                 return -ENOENT;
306
307         readdir_lock.lock();
308         enumerate_images(&rbd_image_data);
309         readdir_lock.unlock();
310         fd = open_rbd_image(path + 1);
311         if (fd < 0)
312                 return -ENOENT;
313
314         fi->fh = fd;
315         return 0;
316 }
317
318 static int rbdfs_read(const char *path, char *buf, size_t size,
319                         off_t offset, struct fuse_file_info *fi)
320 {
321         size_t numread;
322         struct rbd_openimage *rbd;
323
324         if (!gotrados)
325                 return -ENXIO;
326
327         rbd = &opentbl[fi->fh];
328         numread = 0;
329         while (size > 0) {
330                 ssize_t ret;
331
332                 ret = rbd_read(rbd->image, offset, size, buf);
333
334                 if (ret <= 0)
335                         break;
336                 buf += ret;
337                 size -= ret;
338                 offset += ret;
339                 numread += ret;
340         }
341
342         return numread;
343 }
344
345 static int rbdfs_write(const char *path, const char *buf, size_t size,
346                          off_t offset, struct fuse_file_info *fi)
347 {
348         size_t numwritten;
349         struct rbd_openimage *rbd;
350
351         if (!gotrados)
352                 return -ENXIO;
353
354         rbd = &opentbl[fi->fh];
355         numwritten = 0;
356         while (size > 0) {
357                 ssize_t ret;
358
359                 if ((size_t)(offset + size) > rbdsize(fi->fh)) {
360                         int r;
361                         fprintf(stderr, "rbdfs_write resizing %s to 0x%" PRIxMAX "\n",
362                                 path, offset+size);
363                         r = rbd_resize(rbd->image, offset+size);
364                         if (r < 0)
365                                 return r;
366
367                         r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
368                                  sizeof(rbd_image_info_t));
369                         if (r < 0)
370                                 return r;
371                 }
372                 ret = rbd_write(rbd->image, offset, size, buf);
373
374                 if (ret < 0)
375                         break;
376                 buf += ret;
377                 size -= ret;
378                 offset += ret;
379                 numwritten += ret;
380         }
381
382         return numwritten;
383 }
384
385 static void rbdfs_statfs_image_cb(void *num, const char *image)
386 {
387         int     fd;
388
389         ((uint64_t *)num)[0]++;
390
391         fd = open_rbd_image(image);
392         if (fd >= 0)
393                 ((uint64_t *)num)[1] += rbdsize(fd);
394 }
395
396 static int rbdfs_statfs(const char *path, struct statvfs *buf)
397 {
398         uint64_t num[2];
399
400         if (!gotrados)
401                 return -ENXIO;
402
403         num[0] = 1;
404         num[1] = 0;
405         readdir_lock.lock();
406         enumerate_images(&rbd_image_data);
407         readdir_lock.unlock();
408         iter_images(num, rbdfs_statfs_image_cb);
409
410 #define RBDFS_BSIZE     4096
411         buf->f_bsize = RBDFS_BSIZE;
412         buf->f_frsize = RBDFS_BSIZE;
413         buf->f_blocks = num[1] / RBDFS_BSIZE;
414         buf->f_bfree = 0;
415         buf->f_bavail = 0;
416         buf->f_files = num[0];
417         buf->f_ffree = 0;
418         buf->f_favail = 0;
419         buf->f_fsid = 0;
420         buf->f_flag = 0;
421         buf->f_namemax = PATH_MAX;
422
423         return 0;
424 }
425
426 static int rbdfs_fsync(const char *path, int datasync,
427                          struct fuse_file_info *fi)
428 {
429         if (!gotrados)
430                 return -ENXIO;
431         rbd_flush(opentbl[fi->fh].image);
432         return 0;
433 }
434
435 static int rbdfs_opendir(const char *path, struct fuse_file_info *fi)
436 {
437         // only one directory, so global "in_opendir" flag should be fine
438         readdir_lock.lock();
439         in_opendir++;
440         enumerate_images(&rbd_image_data);
441         readdir_lock.unlock();
442         return 0;
443 }
444
445 struct rbdfs_readdir_info {
446         void *buf;
447         fuse_fill_dir_t filler;
448 };
449
450 static void rbdfs_readdir_cb(void *_info, const char *name)
451 {
452         struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
453
454         info->filler(info->buf, name, NULL, 0);
455 }
456
457 static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
458                            off_t offset, struct fuse_file_info *fi)
459 {
460         struct rbdfs_readdir_info info = { buf, filler };
461
462         if (!gotrados)
463                 return -ENXIO;
464         if (!in_opendir)
465                 fprintf(stderr, "in readdir, but not inside opendir?\n");
466
467         if (strcmp(path, "/") != 0)
468                 return -ENOENT;
469
470         filler(buf, ".", NULL, 0);
471         filler(buf, "..", NULL, 0);
472         iter_images(&info, rbdfs_readdir_cb);
473
474         return 0;
475 }
476 static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
477 {
478         // see opendir comments
479         readdir_lock.lock();
480         in_opendir--;
481         readdir_lock.unlock();
482         return 0;
483 }
484
485 void *
486 rbdfs_init(struct fuse_conn_info *conn)
487 {
488         int ret;
489
490         // init cannot fail, so if we fail here, gotrados remains at 0,
491         // causing other operations to fail immediately with ENXIO
492
493         ret = connect_to_cluster(&cluster);
494         if (ret < 0)
495                 exit(90);
496
497         pool_name = rbd_options.pool_name;
498         mount_image_name = rbd_options.image_name;
499         ret = rados_ioctx_create(cluster, pool_name, &ioctx);
500         if (ret < 0)
501                 exit(91);
502 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
503         conn->want |= FUSE_CAP_BIG_WRITES;
504 #endif
505         gotrados = 1;
506
507         // init's return value shows up in fuse_context.private_data,
508         // also to void (*destroy)(void *); useful?
509         return NULL;
510 }
511
512 void
513 rbdfs_destroy(void *unused)
514 {
515         if (!gotrados)
516                 return;
517         for (int i = 0; i < MAX_RBD_IMAGES; ++i) {
518                 if (opentbl[i].image) {
519                         rbd_close(opentbl[i].image);
520                         opentbl[i].image = NULL;
521                 }
522         }
523         rados_ioctx_destroy(ioctx);
524         rados_shutdown(cluster);
525 }
526
527 int
528 rbdfs_checkname(const char *checkname)
529 {
530     const char *extra[] = {"@", "/"};
531     std::string strCheckName(checkname);
532     
533     if (strCheckName.empty())
534         return -EINVAL;
535
536     unsigned int sz = sizeof(extra) / sizeof(const char*);
537     for (unsigned int i = 0; i < sz; i++)
538     {
539         std::string ex(extra[i]);
540         if (std::string::npos != strCheckName.find(ex))
541             return -EINVAL;
542     }
543
544     return 0;
545 }
546
547 // return -errno on error.  fi->fh is not set until open time
548
549 int
550 rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
551 {
552          int r;
553          int order = imageorder;
554
555          r = rbdfs_checkname(path+1);
556          if (r != 0)
557          {
558             return r;  
559          }
560
561          r = rbd_create2(ioctx, path+1, imagesize, imagefeatures, &order);
562          return r;
563 }
564
565 int
566 rbdfs_rename(const char *path, const char *destname)
567 {
568     int r;
569
570     r = rbdfs_checkname(destname+1);
571     if (r != 0)
572     {
573       return r;
574     }
575
576     if (strcmp(path, "/") == 0)
577         return -EINVAL;
578
579     return rbd_rename(ioctx, path+1, destname+1);
580 }
581
582 int
583 rbdfs_utime(const char *path, struct utimbuf *utime)
584 {
585         // called on create; not relevant
586         return 0;
587 }
588
589 int
590 rbdfs_unlink(const char *path)
591 {
592         int fd = find_openrbd(path+1);
593         if (fd != -1) {
594                 struct rbd_openimage *rbd = &opentbl[fd];
595                 rbd_close(rbd->image);
596                 rbd->image = 0;
597                 free(rbd->image_name);
598                 rbd->rbd_stat.valid = 0;
599         }
600         return rbd_remove(ioctx, path+1);
601 }
602
603
604 int
605 rbdfs_truncate(const char *path, off_t size)
606 {
607         int fd;
608         int r;
609         struct rbd_openimage *rbd;
610
611         if ((fd = open_rbd_image(path+1)) < 0)
612                 return -ENOENT;
613
614         rbd = &opentbl[fd];
615         fprintf(stderr, "truncate %s to %" PRIdMAX " (0x%" PRIxMAX ")\n",
616           path, size, size);
617         r = rbd_resize(rbd->image, size);
618         if (r < 0)
619                 return r;
620
621         r = rbd_stat(rbd->image, &(rbd->rbd_stat.rbd_info),
622                  sizeof(rbd_image_info_t));
623         if (r < 0)
624                 return r;
625         return 0;
626 }
627
628 /**
629  * set an xattr on path, with name/value, length size.
630  * Presumably flags are from Linux, as in XATTR_CREATE or 
631  * XATTR_REPLACE (both "set", but fail if exist vs fail if not exist.
632  *
633  * We accept xattrs only on the root node.
634  *
635  * All values converted with strtoull, so can be expressed in any base
636  */
637
638 struct rbdfuse_attr {
639         char *attrname;
640         uint64_t *attrvalp;
641 } attrs[] = {
642     { (char*) "user.rbdfuse.imagesize", &imagesize },
643     { (char*) "user.rbdfuse.imageorder", &imageorder },
644     { (char*) "user.rbdfuse.imagefeatures", &imagefeatures },
645     { NULL, NULL }
646 };
647
648 int
649 rbdfs_setxattr(const char *path, const char *name, const char *value,
650                size_t size,
651                int flags
652 #if defined(DARWIN)
653                ,uint32_t pos
654 #endif
655     )
656 {
657         struct rbdfuse_attr *ap;
658         if (strcmp(path, "/") != 0)
659                 return -EINVAL;
660
661         for (ap = attrs; ap->attrname != NULL; ap++) {
662                 if (strcmp(name, ap->attrname) == 0) {
663                         *ap->attrvalp = strtoull(value, NULL, 0);
664                         fprintf(stderr, "rbd-fuse: %s set to 0x%" PRIx64 "\n",
665                                 ap->attrname, *ap->attrvalp);
666                         return 0;
667                 }
668         }
669         return -EINVAL;
670 }
671
672 int
673 rbdfs_getxattr(const char *path, const char *name, char *value,
674                  size_t size
675 #if defined(DARWIN)
676                ,uint32_t position
677 #endif
678   )
679 {
680         struct rbdfuse_attr *ap;
681         char buf[128];
682         // allow gets on other files; ls likes to ask for things like
683         // security.*
684
685         for (ap = attrs; ap->attrname != NULL; ap++) {
686                 if (strcmp(name, ap->attrname) == 0) {
687                         sprintf(buf, "%" PRIu64, *ap->attrvalp);
688                         if (value != NULL && size >= strlen(buf))
689                                 strcpy(value, buf);
690                         fprintf(stderr, "rbd-fuse: get %s\n", ap->attrname);
691                         return (strlen(buf));
692                 }
693         }
694         return 0;
695 }
696
697 int
698 rbdfs_listxattr(const char *path, char *list, size_t len)
699 {
700         struct rbdfuse_attr *ap;
701         size_t required_len = 0;
702
703         if (strcmp(path, "/") != 0)
704                 return -EINVAL;
705
706         for (ap = attrs; ap->attrname != NULL; ap++)
707                 required_len += strlen(ap->attrname) + 1;
708         if (len >= required_len) {
709                 for (ap = attrs; ap->attrname != NULL; ap++) {
710                         sprintf(list, "%s", ap->attrname);
711                         list += strlen(ap->attrname) + 1;
712                 }
713         }
714         return required_len;
715 }
716
717 const static struct fuse_operations rbdfs_oper = {
718   getattr:    rbdfs_getattr,
719   readlink:   0,
720   getdir:     0,
721   mknod:      0,
722   mkdir:      0,
723   unlink:     rbdfs_unlink,
724   rmdir:      0,
725   symlink:    0,
726   rename:     rbdfs_rename,
727   link:       0,
728   chmod:      0,
729   chown:      0,
730   truncate:   rbdfs_truncate,
731   utime:      rbdfs_utime,
732   open:       rbdfs_open,
733   read:       rbdfs_read,
734   write:      rbdfs_write,
735   statfs:     rbdfs_statfs,
736   flush:      0,
737   release:    0,
738   fsync:      rbdfs_fsync,
739   setxattr:   rbdfs_setxattr,
740   getxattr:   rbdfs_getxattr,
741   listxattr:  rbdfs_listxattr,
742   removexattr: 0,
743   opendir:    rbdfs_opendir,
744   readdir:    rbdfs_readdir,
745   releasedir: rbdfs_releasedir,
746   fsyncdir:   0,
747   init:       rbdfs_init,
748   destroy:    rbdfs_destroy,
749   access:     0,
750   create:     rbdfs_create,
751   /* skip unimplemented */
752 };
753
754 } /* extern "C" */
755
756 enum {
757         KEY_HELP,
758         KEY_VERSION,
759         KEY_CEPH_CONFIG,
760         KEY_CEPH_CONFIG_LONG,
761         KEY_RADOS_POOLNAME,
762         KEY_RADOS_POOLNAME_LONG,
763         KEY_RBD_IMAGENAME,
764         KEY_RBD_IMAGENAME_LONG
765 };
766
767 static struct fuse_opt rbdfs_opts[] = {
768         FUSE_OPT_KEY("-h", KEY_HELP),
769         FUSE_OPT_KEY("--help", KEY_HELP),
770         FUSE_OPT_KEY("-V", KEY_VERSION),
771         FUSE_OPT_KEY("--version", KEY_VERSION),
772         {"-c %s", offsetof(struct rbd_options, ceph_config), KEY_CEPH_CONFIG},
773         {"--configfile=%s", offsetof(struct rbd_options, ceph_config),
774          KEY_CEPH_CONFIG_LONG},
775         {"-p %s", offsetof(struct rbd_options, pool_name), KEY_RADOS_POOLNAME},
776         {"--poolname=%s", offsetof(struct rbd_options, pool_name),
777          KEY_RADOS_POOLNAME_LONG},
778         {"-r %s", offsetof(struct rbd_options, image_name), KEY_RBD_IMAGENAME},
779         {"--image=%s", offsetof(struct rbd_options, image_name),
780         KEY_RBD_IMAGENAME_LONG},
781 };
782
783 static void usage(const char *progname)
784 {
785         fprintf(stderr,
786 "Usage: %s mountpoint [options]\n"
787 "\n"
788 "General options:\n"
789 "    -h   --help            print help\n"
790 "    -V   --version         print version\n"
791 "    -c   --configfile      ceph configuration file [/etc/ceph/ceph.conf]\n"
792 "    -p   --poolname        rados pool name [rbd]\n"
793 "    -r   --image           RBD image name\n"
794 "\n", progname);
795 }
796
797 static int rbdfs_opt_proc(void *data, const char *arg, int key,
798                             struct fuse_args *outargs)
799 {
800         if (key == KEY_HELP) {
801                 usage(outargs->argv[0]);
802                 fuse_opt_add_arg(outargs, "-ho");
803                 fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL);
804                 exit(1);
805         }
806
807         if (key == KEY_VERSION) {
808                 fuse_opt_add_arg(outargs, "--version");
809                 fuse_main(outargs->argc, outargs->argv, &rbdfs_oper, NULL);
810                 exit(0);
811         }
812
813         if (key == KEY_CEPH_CONFIG) {
814                 if (rbd_options.ceph_config != NULL) {
815                         free(rbd_options.ceph_config);
816                         rbd_options.ceph_config = NULL;
817                 }
818                 rbd_options.ceph_config = strdup(arg+2);
819                 return 0;
820         }
821
822         if (key == KEY_RADOS_POOLNAME) {
823                 if (rbd_options.pool_name != NULL) {
824                         free(rbd_options.pool_name);
825                         rbd_options.pool_name = NULL;
826                 }
827                 rbd_options.pool_name = strdup(arg+2);
828                 return 0;
829         }
830
831         if (key == KEY_RBD_IMAGENAME) {
832                 if (rbd_options.image_name!= NULL) {
833                         free(rbd_options.image_name);
834                         rbd_options.image_name = NULL;
835                 }
836                 rbd_options.image_name = strdup(arg+2);
837                 return 0;
838         }
839
840         return 1;
841 }
842
843 void
844 simple_err(const char *msg, int err)
845 {
846         fprintf(stderr, "%s: %s\n", msg, strerror(-err));
847         return;
848 }
849
850 int
851 connect_to_cluster(rados_t *pcluster)
852 {
853         int r;
854
855         r = rados_create(pcluster, NULL);
856         if (r < 0) {
857                 simple_err("Could not create cluster handle", r);
858                 return r;
859         }
860         rados_conf_parse_env(*pcluster, NULL);
861         r = rados_conf_read_file(*pcluster, rbd_options.ceph_config);
862         if (r < 0) {
863                 simple_err("Error reading Ceph config file", r);
864                 goto failed_shutdown;
865         }
866         r = rados_connect(*pcluster);
867         if (r < 0) {
868                 simple_err("Error connecting to cluster", r);
869                 goto failed_shutdown;
870         }
871
872         return 0;
873
874 failed_shutdown:
875         rados_shutdown(*pcluster);
876         return r;
877 }
878
879 int main(int argc, char *argv[])
880 {
881         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
882
883         if (fuse_opt_parse(&args, &rbd_options, rbdfs_opts, rbdfs_opt_proc) == -1) {
884                 exit(1);
885         }
886
887         return fuse_main(args.argc, args.argv, &rbdfs_oper, NULL);
888 }