11 #include "common/module.h"
12 #include "common/secret.h"
13 #include "include/addr_parsing.h"
14 #include "mount.ceph.h"
17 # define MS_RELATIME (1<<21)
20 bool verboseflag
= false;
21 bool skip_mtab_flag
= false;
23 bool no_fallback
= false;
24 bool ms_mode_specified
= false;
25 bool mon_addr_specified
= false;
26 static const char * const EMPTY_STRING
= "";
28 /* TODO duplicates logic from kernel */
29 #define CEPH_AUTH_NAME_DEFAULT "guest"
31 /* path to sysfs for ceph */
32 #define CEPH_SYS_FS_PATH "/sys/module/ceph/"
33 #define CEPH_SYS_FS_PARAM_PATH CEPH_SYS_FS_PATH"/parameters"
36 * mount support hint from kernel -- we only need to check
37 * v2 support for catching bugs.
39 #define CEPH_V2_MOUNT_SUPPORT_PATH CEPH_SYS_FS_PARAM_PATH"/mount_syntax_v2"
41 #define CEPH_DEFAULT_V2_MS_MODE "prefer-crc"
45 enum mount_dev_format
{
46 MOUNT_DEV_FORMAT_OLD
= 0,
47 MOUNT_DEV_FORMAT_NEW
= 1,
50 struct ceph_mount_info
{
51 unsigned long cmi_flags
;
60 char cmi_secret
[SECRET_BUFSIZE
];
62 /* mount dev syntax format */
63 enum mount_dev_format format
;
66 static void mon_addr_as_resolve_param(char *mon_addr
)
68 for (; *mon_addr
; ++mon_addr
)
73 static void resolved_mon_addr_as_mount_opt(char *mon_addr
)
75 for (; *mon_addr
; ++mon_addr
)
80 static void resolved_mon_addr_as_mount_dev(char *mon_addr
)
82 for (; *mon_addr
; ++mon_addr
)
87 static void block_signals (int how
)
92 sigdelset(&sigs
, SIGTRAP
);
93 sigdelset(&sigs
, SIGSEGV
);
94 sigprocmask (how
, &sigs
, (sigset_t
*) 0);
97 void mount_ceph_debug(const char *fmt
, ...)
109 * append a key value pair option to option string.
111 static void append_opt(const char *key
, const char *value
,
112 struct ceph_mount_info
*cmi
, int *pos
)
115 *pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, *pos
, ",");
118 *pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, *pos
, key
);
119 *pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, *pos
, "=");
120 *pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, *pos
, value
);
122 *pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, *pos
, key
);
127 * remove a key value pair from option string. caller should ensure that the
128 * key value pair is separated by "=".
130 static int remove_opt(struct ceph_mount_info
*cmi
, const char *key
, char **value
)
132 char *key_start
= strstr(cmi
->cmi_opts
, key
);
137 /* key present -- try to split */
138 char *key_sep
= strstr(key_start
, "=");
143 if (strncmp(key
, key_start
, key_sep
- key_start
) != 0) {
148 char *value_end
= strstr(key_sep
, ",");
150 value_end
= key_sep
+ strlen(key_sep
);
152 if (value_end
!= key_sep
&& value
) {
153 size_t len1
= value_end
- key_sep
;
154 *value
= strndup(key_sep
, len1
+1);
157 (*value
)[len1
] = '\0';
161 size_t len2
= strlen(value_end
);
164 memmove(key_start
, value_end
, len2
);
166 /* last kv pair - swallow the comma */
174 static void record_name(const char *name
, struct ceph_mount_info
*cmi
)
179 name_pos
= safe_cat(&cmi
->cmi_name
, &name_len
, name_pos
, name
);
183 * parse old device string of format: <mon_addr>:/<path>
185 static int parse_old_dev(const char *dev_str
, struct ceph_mount_info
*cmi
,
191 mount_path
= strstr(dev_str
, ":/");
193 fprintf(stderr
, "source mount path was not specified\n");
197 len
= mount_path
- dev_str
;
200 /* overrides mon_addr passed via mount option (if any) */
201 cmi
->cmi_mons
= strndup(dev_str
, len
);
204 mon_addr_specified
= true;
206 /* reset mon_addr=<> mount option */
207 mon_addr_specified
= false;
211 cmi
->cmi_path
= strdup(mount_path
);
215 record_name(CEPH_AUTH_NAME_DEFAULT
, cmi
);
217 cmi
->format
= MOUNT_DEV_FORMAT_OLD
;
222 * parse new device string of format: name@<fsid>.fs_name=/path
224 static int parse_new_dev(const char *dev_str
, struct ceph_mount_info
*cmi
,
233 name_end
= strstr(dev_str
, "@");
235 mount_ceph_debug("invalid new device string format\n");
239 len
= name_end
- dev_str
;
241 fprintf(stderr
, "missing <name> in device\n");
245 name
= (char *)alloca(len
+1);
246 memcpy(name
, dev_str
, len
);
249 if (cmi
->cmi_name
&& strcmp(cmi
->cmi_name
, name
)) {
250 fprintf(stderr
, "mismatching ceph user in mount option and device string\n");
254 /* record name and store in option string */
255 if (!cmi
->cmi_name
) {
256 record_name(name
, cmi
);
257 append_opt("name", name
, cmi
, opt_pos
);
261 /* check if an fsid is included in the device string */
262 dot
= strstr(name_end
, ".");
264 fprintf(stderr
, "invalid device string format\n");
267 len
= dot
- name_end
;
269 /* check if this _looks_ like a UUID */
270 if (len
!= CLUSTER_FSID_LEN
- 1) {
271 fprintf(stderr
, "invalid device string format\n");
275 cmi
->cmi_fsid
= strndup(name_end
, len
);
281 fs_name
= strstr(dot
, "=");
283 fprintf(stderr
, "invalid device string format\n");
288 fprintf(stderr
, "missing <fs_name> in device\n");
291 cmi
->cmi_fsname
= strndup(dot
, len
);
292 if (!cmi
->cmi_fsname
)
296 if (strlen(fs_name
)) {
297 cmi
->cmi_path
= strdup(fs_name
);
302 /* new-style dev - force using v2 addrs first */
303 if (!ms_mode_specified
&& !mon_addr_specified
)
304 append_opt("ms_mode", CEPH_DEFAULT_V2_MS_MODE
, cmi
,
307 cmi
->format
= MOUNT_DEV_FORMAT_NEW
;
311 static int parse_dev(const char *dev_str
, struct ceph_mount_info
*cmi
,
316 ret
= parse_new_dev(dev_str
, cmi
, opt_pos
);
317 if (ret
< 0 && ret
!= -ENODEV
)
320 ret
= parse_old_dev(dev_str
, cmi
, opt_pos
);
322 fprintf(stderr
, "error parsing device string\n");
326 /* resolve monitor host and optionally record in option string.
327 * use opt_pos to determine if the caller wants to record the
328 * resolved address in mount option (c.f., mount_old_device_format).
330 static int finalize_src(struct ceph_mount_info
*cmi
, int *opt_pos
,
331 char **resolved_addr
)
334 size_t len
= strlen(cmi
->cmi_mons
);
335 char *addr
= alloca(len
+1);
337 memcpy(addr
, cmi
->cmi_mons
, len
+1);
338 mon_addr_as_resolve_param(addr
);
340 src
= resolve_addrs(addr
);
344 mount_ceph_debug("mount.ceph: resolved to: \"%s\"\n", src
);
346 resolved_mon_addr_as_mount_opt(src
);
347 append_opt("mon_addr", src
, cmi
, opt_pos
);
348 } else if (resolved_addr
) {
349 *resolved_addr
= strdup(src
);
358 capng_setpid(getpid());
359 capng_clear(CAPNG_SELECT_BOTH
);
360 if (capng_update(CAPNG_ADD
, CAPNG_PERMITTED
, CAP_DAC_READ_SEARCH
)) {
361 fprintf(stderr
, "Unable to update permitted capability set.\n");
364 if (capng_update(CAPNG_ADD
, CAPNG_EFFECTIVE
, CAP_DAC_READ_SEARCH
)) {
365 fprintf(stderr
, "Unable to update effective capability set.\n");
368 if (capng_apply(CAPNG_SELECT_BOTH
)) {
369 fprintf(stderr
, "Unable to apply new capability set.\n");
376 * Attempt to fetch info from the local config file, if one is present. Since
377 * this involves activity that may be dangerous for a privileged task, we
378 * fork(), have the child drop privileges and do the processing and then hand
379 * back the results via memory shared with the parent.
381 static int fetch_config_info(struct ceph_mount_info
*cmi
)
385 struct ceph_config_info
*cci
;
387 /* Don't do anything if we already have requisite info */
388 if (cmi
->cmi_secret
[0] && cmi
->cmi_mons
&& cmi
->cmi_fsid
)
391 cci
= mmap((void *)0, sizeof(*cci
), PROT_READ
| PROT_WRITE
,
392 MAP_ANONYMOUS
| MAP_SHARED
, -1, 0);
393 if (cci
== MAP_FAILED
) {
394 mount_ceph_debug("Unable to allocate memory: %s\n",
401 mount_ceph_debug("fork() failure: %s\n", strerror(errno
));
407 char *entity_name
= NULL
;
412 ret
= drop_capabilities();
416 name_pos
= safe_cat(&entity_name
, &name_len
, name_pos
, "client.");
417 name_pos
= safe_cat(&entity_name
, &name_len
, name_pos
, cmi
->cmi_name
);
418 mount_ceph_get_config_info(cmi
->cmi_conf
, entity_name
, v2_addrs
, cci
);
424 if (!WIFEXITED(ret
)) {
425 mount_ceph_debug("Child process terminated abnormally.\n");
429 ret
= WEXITSTATUS(ret
);
431 mount_ceph_debug("Child exited with status %d\n", ret
);
437 * Copy values from MAP_SHARED buffer to cmi if we didn't
438 * already find anything and we got something from the child.
441 if (!cmi
->cmi_secret
[0] && cci
->cci_secret
[0]) {
443 len
= strnlen(cci
->cci_secret
, SECRET_BUFSIZE
);
444 if (len
< SECRET_BUFSIZE
) {
445 memcpy(cmi
->cmi_secret
, cci
->cci_secret
, len
+ 1);
447 mount_ceph_debug("secret is too long (len=%zu max=%zu)!\n", len
, SECRET_BUFSIZE
);
450 if (!cmi
->cmi_mons
&& cci
->cci_mons
[0]) {
451 len
= strnlen(cci
->cci_mons
, MON_LIST_BUFSIZE
);
452 if (len
< MON_LIST_BUFSIZE
)
453 cmi
->cmi_mons
= strndup(cci
->cci_mons
, len
+ 1);
455 if (!cmi
->cmi_fsid
) {
456 len
= strnlen(cci
->cci_fsid
, CLUSTER_FSID_LEN
);
457 if (len
< CLUSTER_FSID_LEN
)
458 cmi
->cmi_fsid
= strndup(cci
->cci_fsid
, len
+ 1);
462 munmap(cci
, sizeof(*cci
));
467 * this one is partially based on parse_options() from cifs.mount.c
469 static int parse_options(const char *data
, struct ceph_mount_info
*cmi
,
472 char * next_keyword
= NULL
;
475 if (data
== EMPTY_STRING
)
478 mount_ceph_debug("parsing options: %s\n", data
);
484 /* check if ends with trailing comma */
487 next_keyword
= strchr(data
,',');
489 /* temporarily null terminate end of keyword=value pair */
493 /* temporarily null terminate keyword to make keyword and value distinct */
494 if ((value
= strchr(data
, '=')) != NULL
) {
499 if (strcmp(data
, "ro") == 0) {
500 cmi
->cmi_flags
|= MS_RDONLY
;
501 } else if (strcmp(data
, "rw") == 0) {
502 cmi
->cmi_flags
&= ~MS_RDONLY
;
503 } else if (strcmp(data
, "nosuid") == 0) {
504 cmi
->cmi_flags
|= MS_NOSUID
;
505 } else if (strcmp(data
, "suid") == 0) {
506 cmi
->cmi_flags
&= ~MS_NOSUID
;
507 } else if (strcmp(data
, "dev") == 0) {
508 cmi
->cmi_flags
&= ~MS_NODEV
;
509 } else if (strcmp(data
, "nodev") == 0) {
510 cmi
->cmi_flags
|= MS_NODEV
;
511 } else if (strcmp(data
, "noexec") == 0) {
512 cmi
->cmi_flags
|= MS_NOEXEC
;
513 } else if (strcmp(data
, "exec") == 0) {
514 cmi
->cmi_flags
&= ~MS_NOEXEC
;
515 } else if (strcmp(data
, "sync") == 0) {
516 cmi
->cmi_flags
|= MS_SYNCHRONOUS
;
517 } else if (strcmp(data
, "remount") == 0) {
518 cmi
->cmi_flags
|= MS_REMOUNT
;
519 } else if (strcmp(data
, "mandlock") == 0) {
520 cmi
->cmi_flags
|= MS_MANDLOCK
;
521 } else if ((strcmp(data
, "nobrl") == 0) ||
522 (strcmp(data
, "nolock") == 0)) {
523 cmi
->cmi_flags
&= ~MS_MANDLOCK
;
524 } else if (strcmp(data
, "noatime") == 0) {
525 cmi
->cmi_flags
|= MS_NOATIME
;
526 } else if (strcmp(data
, "nodiratime") == 0) {
527 cmi
->cmi_flags
|= MS_NODIRATIME
;
528 } else if (strcmp(data
, "relatime") == 0) {
529 cmi
->cmi_flags
|= MS_RELATIME
;
530 } else if (strcmp(data
, "strictatime") == 0) {
531 cmi
->cmi_flags
|= MS_STRICTATIME
;
532 } else if (strcmp(data
, "noauto") == 0) {
534 } else if (strcmp(data
, "_netdev") == 0) {
536 } else if (strcmp(data
, "nofail") == 0) {
538 } else if (strcmp(data
, "fs") == 0) {
539 if (!value
|| !*value
) {
540 fprintf(stderr
, "mount option fs requires a value.\n");
543 data
= "mds_namespace";
545 } else if (strcmp(data
, "nofallback") == 0) {
547 } else if (strcmp(data
, "secretfile") == 0) {
550 if (!value
|| !*value
) {
551 fprintf(stderr
, "keyword secretfile found, but no secret file specified\n");
554 ret
= read_secret_from_file(value
, cmi
->cmi_secret
, sizeof(cmi
->cmi_secret
));
556 fprintf(stderr
, "error reading secret file: %d\n", ret
);
559 } else if (strcmp(data
, "secret") == 0) {
562 if (!value
|| !*value
) {
563 fprintf(stderr
, "mount option secret requires a value.\n");
567 len
= strnlen(value
, sizeof(cmi
->cmi_secret
)) + 1;
568 if (len
<= sizeof(cmi
->cmi_secret
))
569 memcpy(cmi
->cmi_secret
, value
, len
);
570 } else if (strcmp(data
, "conf") == 0) {
571 if (!value
|| !*value
) {
572 fprintf(stderr
, "mount option conf requires a value.\n");
575 /* keep pointer to value */
576 cmi
->cmi_conf
= strdup(value
);
579 } else if (strcmp(data
, "name") == 0) {
580 if (!value
|| !*value
) {
581 fprintf(stderr
, "mount option name requires a value.\n");
584 /* keep pointer to value */
587 } else if (strcmp(data
, "ms_mode") == 0) {
588 if (!value
|| !*value
) {
589 fprintf(stderr
, "mount option ms_mode requires a value.\n");
592 /* Only legacy ms_mode needs v1 addrs */
593 v2_addrs
= strcmp(value
, "legacy");
595 ms_mode_specified
= true;
596 } else if (strcmp(data
, "mon_addr") == 0) {
597 /* monitor address to use for mounting */
598 if (!value
|| !*value
) {
599 fprintf(stderr
, "mount option mon_addr requires a value.\n");
602 cmi
->cmi_mons
= strdup(value
);
605 mon_addr_specified
= true;
607 /* unrecognized mount options, passing to kernel */
611 /* Copy (possibly modified) option to out */
613 append_opt(data
, value
, cmi
, opt_pos
);
619 * set ->cmi_name conditionally -- this gets checked when parsing new
620 * device format. for old device format, ->cmi_name is set to default
621 * user name when name option is not passed in.
624 record_name(name
, cmi
);
626 mount_ceph_debug("mount.ceph: options \"%s\".\n", cmi
->cmi_opts
);
628 if (!cmi
->cmi_opts
) {
629 cmi
->cmi_opts
= strdup(EMPTY_STRING
);
637 static int parse_arguments(int argc
, char *const *const argv
,
638 const char **src
, const char **node
, const char **opts
)
643 // There were no arguments. Just show the usage.
646 if ((!strcmp(argv
[1], "-h")) || (!strcmp(argv
[1], "--help"))) {
647 // The user asked for help.
651 // The first two arguments are positional
657 // Parse the remaining options
658 *opts
= EMPTY_STRING
;
659 for (i
= 3; i
< argc
; ++i
) {
660 if (!strcmp("-h", argv
[i
]))
662 else if (!strcmp("-n", argv
[i
]))
663 skip_mtab_flag
= true;
664 else if (!strcmp("-v", argv
[i
]))
666 else if (!strcmp("-o", argv
[i
])) {
669 fprintf(stderr
, "Option -o requires an argument.\n\n");
674 fprintf(stderr
, "Can't understand option: '%s'\n\n", argv
[i
]);
681 /* modprobe failing doesn't necessarily prevent from working, so this
683 static void modprobe(void)
687 r
= module_load("ceph", NULL
);
689 printf("failed to load ceph kernel module (%d)\n", r
);
692 static void usage(const char *prog_name
)
694 printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n",
696 printf("options:\n");
697 printf("\t-h: Print this help\n");
698 printf("\t-n: Do not update /etc/mtab\n");
699 printf("\t-v: Verbose\n");
700 printf("\tceph-options: refer to mount.ceph(8)\n");
705 * The structure itself lives on the stack, so don't free it. Just the
708 static void ceph_mount_info_free(struct ceph_mount_info
*cmi
)
712 free(cmi
->cmi_fsname
);
719 static int mount_new_device_format(const char *node
, struct ceph_mount_info
*cmi
)
726 if (!cmi
->cmi_fsid
) {
727 fprintf(stderr
, "missing ceph cluster-id");
731 pos
= safe_cat(&rsrc
, &len
, pos
, cmi
->cmi_name
);
732 pos
= safe_cat(&rsrc
, &len
, pos
, "@");
733 pos
= safe_cat(&rsrc
, &len
, pos
, cmi
->cmi_fsid
);
734 pos
= safe_cat(&rsrc
, &len
, pos
, ".");
735 pos
= safe_cat(&rsrc
, &len
, pos
, cmi
->cmi_fsname
);
736 pos
= safe_cat(&rsrc
, &len
, pos
, "=");
738 safe_cat(&rsrc
, &len
, pos
, cmi
->cmi_path
);
740 mount_ceph_debug("mount.ceph: trying mount with new device syntax: %s\n",
743 mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel\n",
745 r
= mount(rsrc
, node
, "ceph", cmi
->cmi_flags
, cmi
->cmi_opts
);
752 static int mount_old_device_format(const char *node
, struct ceph_mount_info
*cmi
)
757 char *mon_addr
= NULL
;
760 r
= remove_opt(cmi
, "mon_addr", &mon_addr
);
762 fprintf(stderr
, "failed to switch using old device format\n");
766 /* if we reach here and still have a v2 addr, we'd need to
767 * refresh with v1 addrs, since we'll be not passing ms_mode
768 * with the old syntax.
770 if (v2_addrs
&& !ms_mode_specified
&& !mon_addr_specified
) {
771 mount_ceph_debug("mount.ceph: switching to using v1 address with old syntax\n");
776 cmi
->cmi_mons
= NULL
;
777 fetch_config_info(cmi
);
778 if (!cmi
->cmi_mons
) {
779 fprintf(stderr
, "unable to determine (v1) mon addresses\n");
782 r
= finalize_src(cmi
, NULL
, &mon_addr
);
784 fprintf(stderr
, "failed to resolve (v1) mon addresses\n");
787 remove_opt(cmi
, "ms_mode", NULL
);
790 pos
= strlen(cmi
->cmi_opts
);
792 append_opt("mds_namespace", cmi
->cmi_fsname
, cmi
, &pos
);
794 append_opt("fsid", cmi
->cmi_fsid
, cmi
, &pos
);
797 resolved_mon_addr_as_mount_dev(mon_addr
);
798 pos
= safe_cat(&rsrc
, &len
, pos
, mon_addr
);
799 pos
= safe_cat(&rsrc
, &len
, pos
, ":");
801 safe_cat(&rsrc
, &len
, pos
, cmi
->cmi_path
);
803 mount_ceph_debug("mount.ceph: trying mount with old device syntax: %s\n",
806 mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel\n",
809 r
= mount(rsrc
, node
, "ceph", cmi
->cmi_flags
, cmi
->cmi_opts
);
817 * check whether to fall-back to using old-style mount syntax (called
818 * when new-style mount syntax fails). this is mostly to catch any
819 * new-style (v2) implementation bugs in the kernel and is primarly
820 * used in teuthology tests.
822 static bool should_fallback()
830 ret
= stat(CEPH_V2_MOUNT_SUPPORT_PATH
, &stbuf
);
832 mount_ceph_debug("mount.ceph: v2 mount support check returned %d\n",
835 mount_ceph_debug("mount.ceph: kernel does not support v2"
837 /* fallback on *all* errors */
841 fprintf(stderr
, "mount.ceph: kernel BUG!\n");
845 static int do_mount(const char *dev
, const char *node
,
846 struct ceph_mount_info
*cmi
) {
849 bool fallback
= true;
851 /* no v2 addresses available via config - try v1 addresses */
854 !ms_mode_specified
&&
855 !mon_addr_specified
) {
856 mount_ceph_debug("mount.ceph: switching to using v1 address\n");
858 fetch_config_info(cmi
);
859 remove_opt(cmi
, "ms_mode", NULL
);
862 if (!cmi
->cmi_mons
) {
863 fprintf(stderr
, "unable to determine mon addresses\n");
867 pos
= strlen(cmi
->cmi_opts
);
868 retval
= finalize_src(cmi
, &pos
, NULL
);
870 fprintf(stderr
, "failed to resolve source\n");
875 if (cmi
->format
== MOUNT_DEV_FORMAT_NEW
) {
876 retval
= mount_new_device_format(node
, cmi
);
878 fallback
= (should_fallback() && retval
== -EINVAL
&& cmi
->cmi_fsid
);
881 /* pass-through or fallback to old-style mount device */
882 if (retval
&& fallback
)
883 retval
= mount_old_device_format(node
, cmi
);
888 fprintf(stderr
, "mount error: ceph filesystem not supported by the system\n");
891 fprintf(stderr
, "mount error: no mds server is up or the cluster is laggy\n");
894 fprintf(stderr
, "mount error %d = %s\n", errno
, strerror(errno
));
898 if (!retval
&& !skip_mtab_flag
) {
899 update_mtab_entry(dev
, node
, "ceph", cmi
->cmi_opts
, cmi
->cmi_flags
, 0, 0);
905 static int append_key_or_secret_option(struct ceph_mount_info
*cmi
)
907 int pos
= strlen(cmi
->cmi_opts
);
909 if (!cmi
->cmi_secret
[0] && !is_kernel_secret(cmi
->cmi_name
))
913 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, ",");
915 /* when parsing kernel options (-o remount) we get '<hidden>' as the secret */
916 if (cmi
->cmi_secret
[0] && (strcmp(cmi
->cmi_secret
, "<hidden>") != 0)) {
917 int ret
= set_kernel_secret(cmi
->cmi_secret
, cmi
->cmi_name
);
919 if (ret
== -ENODEV
|| ret
== -ENOSYS
) {
920 /* old kernel; fall back to secret= in options */
921 pos
= safe_cat(&cmi
->cmi_opts
,
922 &cmi
->cmi_opts_len
, pos
,
924 pos
= safe_cat(&cmi
->cmi_opts
,
925 &cmi
->cmi_opts_len
, pos
,
929 fprintf(stderr
, "adding ceph secret key to kernel failed: %s\n",
935 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, "key=");
936 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, cmi
->cmi_name
);
941 int main(int argc
, char *argv
[])
944 const char *dev
, *node
, *opts
;
946 struct ceph_mount_info cmi
= { 0 };
948 retval
= parse_arguments(argc
, argv
, &dev
, &node
, &opts
);
951 retval
= (retval
> 0) ? 0 : EX_USAGE
;
955 retval
= parse_options(opts
, &cmi
, &opt_pos
);
957 fprintf(stderr
, "failed to parse ceph_options: %d\n", retval
);
962 retval
= parse_dev(dev
, &cmi
, &opt_pos
);
964 fprintf(stderr
, "unable to parse mount device string: %d\n", retval
);
970 * We don't care if this errors out, since this is best-effort.
971 * note that this fetches v1 or v2 addr depending on @v2_addr
974 fetch_config_info(&cmi
);
976 /* Ensure the ceph key_type is available */
979 retval
= append_key_or_secret_option(&cmi
);
981 fprintf(stderr
, "couldn't append secret option: %d\n", retval
);
986 block_signals(SIG_BLOCK
);
987 retval
= do_mount(dev
, node
, &cmi
);
988 block_signals(SIG_UNBLOCK
);
990 ceph_mount_info_free(&cmi
);