]>
git.proxmox.com Git - ceph.git/blob - ceph/src/mount/mount.ceph.c
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;
22 static const char * const EMPTY_STRING
= "";
24 /* TODO duplicates logic from kernel */
25 #define CEPH_AUTH_NAME_DEFAULT "guest"
29 struct ceph_mount_info
{
30 unsigned long cmi_flags
;
37 char cmi_secret
[SECRET_BUFSIZE
];
40 static void block_signals (int how
)
45 sigdelset(&sigs
, SIGTRAP
);
46 sigdelset(&sigs
, SIGSEGV
);
47 sigprocmask (how
, &sigs
, (sigset_t
*) 0);
50 void mount_ceph_debug(const char *fmt
, ...)
61 static int parse_src(const char *orig_str
, struct ceph_mount_info
*cmi
)
66 mount_path
= strstr(orig_str
, ":/");
68 fprintf(stderr
, "source mount path was not specified\n");
72 len
= mount_path
- orig_str
;
74 cmi
->cmi_mons
= strndup(orig_str
, len
);
80 cmi
->cmi_path
= strdup(mount_path
);
86 static char *finalize_src(struct ceph_mount_info
*cmi
)
91 src
= resolve_addrs(cmi
->cmi_mons
);
96 pos
= safe_cat(&src
, &len
, len
, ":");
97 safe_cat(&src
, &len
, pos
, cmi
->cmi_path
);
105 capng_setpid(getpid());
106 capng_clear(CAPNG_SELECT_BOTH
);
107 if (capng_update(CAPNG_ADD
, CAPNG_PERMITTED
, CAP_DAC_READ_SEARCH
)) {
108 fprintf(stderr
, "Unable to update permitted capability set.\n");
111 if (capng_update(CAPNG_ADD
, CAPNG_EFFECTIVE
, CAP_DAC_READ_SEARCH
)) {
112 fprintf(stderr
, "Unable to update effective capability set.\n");
115 if (capng_apply(CAPNG_SELECT_BOTH
)) {
116 fprintf(stderr
, "Unable to apply new capability set.\n");
123 * Attempt to fetch info from the local config file, if one is present. Since
124 * this involves activity that may be dangerous for a privileged task, we
125 * fork(), have the child drop privileges and do the processing and then hand
126 * back the results via memory shared with the parent.
128 static int fetch_config_info(struct ceph_mount_info
*cmi
)
132 struct ceph_config_info
*cci
;
134 /* Don't do anything if we already have requisite info */
135 if (cmi
->cmi_secret
[0] && cmi
->cmi_mons
)
138 cci
= mmap((void *)0, sizeof(*cci
), PROT_READ
| PROT_WRITE
,
139 MAP_ANONYMOUS
| MAP_SHARED
, -1, 0);
140 if (cci
== MAP_FAILED
) {
141 mount_ceph_debug("Unable to allocate memory: %s\n",
148 mount_ceph_debug("fork() failure: %s\n", strerror(errno
));
155 ret
= drop_capabilities();
158 mount_ceph_get_config_info(cmi
->cmi_conf
, cmi
->cmi_name
, cci
);
163 if (!WIFEXITED(ret
)) {
164 mount_ceph_debug("Child process terminated abnormally.\n");
168 ret
= WEXITSTATUS(ret
);
170 mount_ceph_debug("Child exited with status %d\n", ret
);
176 * Copy values from MAP_SHARED buffer to cmi if we didn't
177 * already find anything and we got something from the child.
180 if (!cmi
->cmi_secret
[0] && cci
->cci_secret
[0]) {
182 len
= strnlen(cci
->cci_secret
, SECRET_BUFSIZE
);
183 if (len
< SECRET_BUFSIZE
) {
184 memcpy(cmi
->cmi_secret
, cci
->cci_secret
, len
+ 1);
186 mount_ceph_debug("secret is too long (len=%zu max=%zu)!\n", len
, SECRET_BUFSIZE
);
189 if (!cmi
->cmi_mons
&& cci
->cci_mons
[0]) {
190 len
= strnlen(cci
->cci_mons
, MON_LIST_BUFSIZE
);
191 if (len
< MON_LIST_BUFSIZE
)
192 cmi
->cmi_mons
= strndup(cci
->cci_mons
, len
+ 1);
196 munmap(cci
, sizeof(*cci
));
201 * this one is partially based on parse_options() from cifs.mount.c
203 static int parse_options(const char *data
, struct ceph_mount_info
*cmi
)
205 char * next_keyword
= NULL
;
211 mount_ceph_debug("parsing options: %s\n", data
);
217 /* check if ends with trailing comma */
220 next_keyword
= strchr(data
,',');
222 /* temporarily null terminate end of keyword=value pair */
226 /* temporarily null terminate keyword to make keyword and value distinct */
227 if ((value
= strchr(data
, '=')) != NULL
) {
232 if (strcmp(data
, "ro") == 0) {
233 cmi
->cmi_flags
|= MS_RDONLY
;
234 } else if (strcmp(data
, "rw") == 0) {
235 cmi
->cmi_flags
&= ~MS_RDONLY
;
236 } else if (strcmp(data
, "nosuid") == 0) {
237 cmi
->cmi_flags
|= MS_NOSUID
;
238 } else if (strcmp(data
, "suid") == 0) {
239 cmi
->cmi_flags
&= ~MS_NOSUID
;
240 } else if (strcmp(data
, "dev") == 0) {
241 cmi
->cmi_flags
&= ~MS_NODEV
;
242 } else if (strcmp(data
, "nodev") == 0) {
243 cmi
->cmi_flags
|= MS_NODEV
;
244 } else if (strcmp(data
, "noexec") == 0) {
245 cmi
->cmi_flags
|= MS_NOEXEC
;
246 } else if (strcmp(data
, "exec") == 0) {
247 cmi
->cmi_flags
&= ~MS_NOEXEC
;
248 } else if (strcmp(data
, "sync") == 0) {
249 cmi
->cmi_flags
|= MS_SYNCHRONOUS
;
250 } else if (strcmp(data
, "remount") == 0) {
251 cmi
->cmi_flags
|= MS_REMOUNT
;
252 } else if (strcmp(data
, "mandlock") == 0) {
253 cmi
->cmi_flags
|= MS_MANDLOCK
;
254 } else if ((strcmp(data
, "nobrl") == 0) ||
255 (strcmp(data
, "nolock") == 0)) {
256 cmi
->cmi_flags
&= ~MS_MANDLOCK
;
257 } else if (strcmp(data
, "noatime") == 0) {
258 cmi
->cmi_flags
|= MS_NOATIME
;
259 } else if (strcmp(data
, "nodiratime") == 0) {
260 cmi
->cmi_flags
|= MS_NODIRATIME
;
261 } else if (strcmp(data
, "relatime") == 0) {
262 cmi
->cmi_flags
|= MS_RELATIME
;
263 } else if (strcmp(data
, "strictatime") == 0) {
264 cmi
->cmi_flags
|= MS_STRICTATIME
;
265 } else if (strcmp(data
, "noauto") == 0) {
267 } else if (strcmp(data
, "_netdev") == 0) {
269 } else if (strcmp(data
, "nofail") == 0) {
271 } else if (strcmp(data
, "fs") == 0) {
272 if (!value
|| !*value
) {
273 fprintf(stderr
, "mount option fs requires a value.\n");
276 data
= "mds_namespace";
278 } else if (strcmp(data
, "secretfile") == 0) {
281 if (!value
|| !*value
) {
282 fprintf(stderr
, "keyword secretfile found, but no secret file specified\n");
285 ret
= read_secret_from_file(value
, cmi
->cmi_secret
, sizeof(cmi
->cmi_secret
));
287 fprintf(stderr
, "error reading secret file: %d\n", ret
);
290 } else if (strcmp(data
, "secret") == 0) {
293 if (!value
|| !*value
) {
294 fprintf(stderr
, "mount option secret requires a value.\n");
298 len
= strnlen(value
, sizeof(cmi
->cmi_secret
)) + 1;
299 if (len
<= sizeof(cmi
->cmi_secret
))
300 memcpy(cmi
->cmi_secret
, value
, len
);
301 } else if (strcmp(data
, "conf") == 0) {
302 if (!value
|| !*value
) {
303 fprintf(stderr
, "mount option conf requires a value.\n");
306 /* keep pointer to value */
307 cmi
->cmi_conf
= strdup(value
);
310 } else if (strcmp(data
, "name") == 0) {
311 if (!value
|| !*value
) {
312 fprintf(stderr
, "mount option name requires a value.\n");
315 /* keep pointer to value */
320 mount_ceph_debug("mount.ceph: unrecognized mount option \"%s\", passing to kernel.\n",
324 /* Copy (possibly modified) option to out */
327 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, ",");
330 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, data
);
331 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, "=");
332 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, value
);
334 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, data
);
340 name_pos
= safe_cat(&cmi
->cmi_name
, &name_len
, name_pos
, "client.");
341 name_pos
= safe_cat(&cmi
->cmi_name
, &name_len
, name_pos
,
342 name
? name
: CEPH_AUTH_NAME_DEFAULT
);
344 if (!cmi
->cmi_opts
) {
345 cmi
->cmi_opts
= strdup(EMPTY_STRING
);
353 static int parse_arguments(int argc
, char *const *const argv
,
354 const char **src
, const char **node
, const char **opts
)
359 // There were no arguments. Just show the usage.
362 if ((!strcmp(argv
[1], "-h")) || (!strcmp(argv
[1], "--help"))) {
363 // The user asked for help.
367 // The first two arguments are positional
373 // Parse the remaining options
374 *opts
= EMPTY_STRING
;
375 for (i
= 3; i
< argc
; ++i
) {
376 if (!strcmp("-h", argv
[i
]))
378 else if (!strcmp("-n", argv
[i
]))
379 skip_mtab_flag
= true;
380 else if (!strcmp("-v", argv
[i
]))
382 else if (!strcmp("-o", argv
[i
])) {
385 fprintf(stderr
, "Option -o requires an argument.\n\n");
391 fprintf(stderr
, "Can't understand option: '%s'\n\n", argv
[i
]);
398 /* modprobe failing doesn't necessarily prevent from working, so this
400 static void modprobe(void)
404 r
= module_load("ceph", NULL
);
406 printf("failed to load ceph kernel module (%d)\n", r
);
409 static void usage(const char *prog_name
)
411 printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n",
413 printf("options:\n");
414 printf("\t-h: Print this help\n");
415 printf("\t-n: Do not update /etc/mtab\n");
416 printf("\t-v: Verbose\n");
417 printf("\tceph-options: refer to mount.ceph(8)\n");
422 * The structure itself lives on the stack, so don't free it. Just the
425 static void ceph_mount_info_free(struct ceph_mount_info
*cmi
)
434 static int append_key_or_secret_option(struct ceph_mount_info
*cmi
)
436 int pos
= strlen(cmi
->cmi_opts
);
438 if (!cmi
->cmi_secret
[0] && !is_kernel_secret(cmi
->cmi_name
))
442 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, ",");
444 /* when parsing kernel options (-o remount) we get '<hidden>' as the secret */
445 if (cmi
->cmi_secret
[0] && (strcmp(cmi
->cmi_secret
, "<hidden>") != 0)) {
446 int ret
= set_kernel_secret(cmi
->cmi_secret
, cmi
->cmi_name
);
448 if (ret
== -ENODEV
|| ret
== -ENOSYS
) {
449 /* old kernel; fall back to secret= in options */
450 pos
= safe_cat(&cmi
->cmi_opts
,
451 &cmi
->cmi_opts_len
, pos
,
453 pos
= safe_cat(&cmi
->cmi_opts
,
454 &cmi
->cmi_opts_len
, pos
,
458 fprintf(stderr
, "adding ceph secret key to kernel failed: %s\n",
464 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, "key=");
465 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, cmi
->cmi_name
);
470 int main(int argc
, char *argv
[])
472 const char *src
, *node
, *opts
;
475 struct ceph_mount_info cmi
= { 0 };
477 retval
= parse_arguments(argc
, argv
, &src
, &node
, &opts
);
480 retval
= (retval
> 0) ? 0 : EX_USAGE
;
484 retval
= parse_options(opts
, &cmi
);
486 fprintf(stderr
, "failed to parse ceph_options: %d\n", retval
);
491 retval
= parse_src(src
, &cmi
);
493 fprintf(stderr
, "unable to parse mount source: %d\n", retval
);
498 /* We don't care if this errors out, since this is best-effort */
499 fetch_config_info(&cmi
);
502 fprintf(stderr
, "unable to determine mon addresses\n");
507 rsrc
= finalize_src(&cmi
);
509 fprintf(stderr
, "failed to resolve source\n");
514 /* Ensure the ceph key_type is available */
517 retval
= append_key_or_secret_option(&cmi
);
519 fprintf(stderr
, "couldn't append secret option: %d\n", retval
);
524 block_signals(SIG_BLOCK
);
526 if (mount(rsrc
, node
, "ceph", cmi
.cmi_flags
, cmi
.cmi_opts
)) {
530 fprintf(stderr
, "mount error: ceph filesystem not supported by the system\n");
533 fprintf(stderr
, "mount error: no mds server is up or the cluster is laggy\n");
536 fprintf(stderr
, "mount error %d = %s\n",errno
,strerror(errno
));
539 if (!skip_mtab_flag
) {
540 update_mtab_entry(rsrc
, node
, "ceph", cmi
.cmi_opts
, cmi
.cmi_flags
, 0, 0);
544 block_signals(SIG_UNBLOCK
);
546 ceph_mount_info_free(&cmi
);