]>
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 bool v2_addrs
= false;
23 static const char * const EMPTY_STRING
= "";
25 /* TODO duplicates logic from kernel */
26 #define CEPH_AUTH_NAME_DEFAULT "guest"
30 struct ceph_mount_info
{
31 unsigned long cmi_flags
;
38 char cmi_secret
[SECRET_BUFSIZE
];
41 static void block_signals (int how
)
46 sigdelset(&sigs
, SIGTRAP
);
47 sigdelset(&sigs
, SIGSEGV
);
48 sigprocmask (how
, &sigs
, (sigset_t
*) 0);
51 void mount_ceph_debug(const char *fmt
, ...)
62 static int parse_src(const char *orig_str
, struct ceph_mount_info
*cmi
)
67 mount_path
= strstr(orig_str
, ":/");
69 fprintf(stderr
, "source mount path was not specified\n");
73 len
= mount_path
- orig_str
;
75 cmi
->cmi_mons
= strndup(orig_str
, len
);
81 cmi
->cmi_path
= strdup(mount_path
);
87 static char *finalize_src(struct ceph_mount_info
*cmi
)
92 src
= resolve_addrs(cmi
->cmi_mons
);
97 pos
= safe_cat(&src
, &len
, len
, ":");
98 safe_cat(&src
, &len
, pos
, cmi
->cmi_path
);
106 capng_setpid(getpid());
107 capng_clear(CAPNG_SELECT_BOTH
);
108 if (capng_update(CAPNG_ADD
, CAPNG_PERMITTED
, CAP_DAC_READ_SEARCH
)) {
109 fprintf(stderr
, "Unable to update permitted capability set.\n");
112 if (capng_update(CAPNG_ADD
, CAPNG_EFFECTIVE
, CAP_DAC_READ_SEARCH
)) {
113 fprintf(stderr
, "Unable to update effective capability set.\n");
116 if (capng_apply(CAPNG_SELECT_BOTH
)) {
117 fprintf(stderr
, "Unable to apply new capability set.\n");
124 * Attempt to fetch info from the local config file, if one is present. Since
125 * this involves activity that may be dangerous for a privileged task, we
126 * fork(), have the child drop privileges and do the processing and then hand
127 * back the results via memory shared with the parent.
129 static int fetch_config_info(struct ceph_mount_info
*cmi
)
133 struct ceph_config_info
*cci
;
135 /* Don't do anything if we already have requisite info */
136 if (cmi
->cmi_secret
[0] && cmi
->cmi_mons
)
139 cci
= mmap((void *)0, sizeof(*cci
), PROT_READ
| PROT_WRITE
,
140 MAP_ANONYMOUS
| MAP_SHARED
, -1, 0);
141 if (cci
== MAP_FAILED
) {
142 mount_ceph_debug("Unable to allocate memory: %s\n",
149 mount_ceph_debug("fork() failure: %s\n", strerror(errno
));
156 ret
= drop_capabilities();
159 mount_ceph_get_config_info(cmi
->cmi_conf
, cmi
->cmi_name
, v2_addrs
, cci
);
164 if (!WIFEXITED(ret
)) {
165 mount_ceph_debug("Child process terminated abnormally.\n");
169 ret
= WEXITSTATUS(ret
);
171 mount_ceph_debug("Child exited with status %d\n", ret
);
177 * Copy values from MAP_SHARED buffer to cmi if we didn't
178 * already find anything and we got something from the child.
181 if (!cmi
->cmi_secret
[0] && cci
->cci_secret
[0]) {
183 len
= strnlen(cci
->cci_secret
, SECRET_BUFSIZE
);
184 if (len
< SECRET_BUFSIZE
) {
185 memcpy(cmi
->cmi_secret
, cci
->cci_secret
, len
+ 1);
187 mount_ceph_debug("secret is too long (len=%zu max=%zu)!\n", len
, SECRET_BUFSIZE
);
190 if (!cmi
->cmi_mons
&& cci
->cci_mons
[0]) {
191 len
= strnlen(cci
->cci_mons
, MON_LIST_BUFSIZE
);
192 if (len
< MON_LIST_BUFSIZE
)
193 cmi
->cmi_mons
= strndup(cci
->cci_mons
, len
+ 1);
197 munmap(cci
, sizeof(*cci
));
202 * this one is partially based on parse_options() from cifs.mount.c
204 static int parse_options(const char *data
, struct ceph_mount_info
*cmi
)
206 char * next_keyword
= NULL
;
212 if (data
== EMPTY_STRING
)
215 mount_ceph_debug("parsing options: %s\n", data
);
221 /* check if ends with trailing comma */
224 next_keyword
= strchr(data
,',');
226 /* temporarily null terminate end of keyword=value pair */
230 /* temporarily null terminate keyword to make keyword and value distinct */
231 if ((value
= strchr(data
, '=')) != NULL
) {
236 if (strcmp(data
, "ro") == 0) {
237 cmi
->cmi_flags
|= MS_RDONLY
;
238 } else if (strcmp(data
, "rw") == 0) {
239 cmi
->cmi_flags
&= ~MS_RDONLY
;
240 } else if (strcmp(data
, "nosuid") == 0) {
241 cmi
->cmi_flags
|= MS_NOSUID
;
242 } else if (strcmp(data
, "suid") == 0) {
243 cmi
->cmi_flags
&= ~MS_NOSUID
;
244 } else if (strcmp(data
, "dev") == 0) {
245 cmi
->cmi_flags
&= ~MS_NODEV
;
246 } else if (strcmp(data
, "nodev") == 0) {
247 cmi
->cmi_flags
|= MS_NODEV
;
248 } else if (strcmp(data
, "noexec") == 0) {
249 cmi
->cmi_flags
|= MS_NOEXEC
;
250 } else if (strcmp(data
, "exec") == 0) {
251 cmi
->cmi_flags
&= ~MS_NOEXEC
;
252 } else if (strcmp(data
, "sync") == 0) {
253 cmi
->cmi_flags
|= MS_SYNCHRONOUS
;
254 } else if (strcmp(data
, "remount") == 0) {
255 cmi
->cmi_flags
|= MS_REMOUNT
;
256 } else if (strcmp(data
, "mandlock") == 0) {
257 cmi
->cmi_flags
|= MS_MANDLOCK
;
258 } else if ((strcmp(data
, "nobrl") == 0) ||
259 (strcmp(data
, "nolock") == 0)) {
260 cmi
->cmi_flags
&= ~MS_MANDLOCK
;
261 } else if (strcmp(data
, "noatime") == 0) {
262 cmi
->cmi_flags
|= MS_NOATIME
;
263 } else if (strcmp(data
, "nodiratime") == 0) {
264 cmi
->cmi_flags
|= MS_NODIRATIME
;
265 } else if (strcmp(data
, "relatime") == 0) {
266 cmi
->cmi_flags
|= MS_RELATIME
;
267 } else if (strcmp(data
, "strictatime") == 0) {
268 cmi
->cmi_flags
|= MS_STRICTATIME
;
269 } else if (strcmp(data
, "noauto") == 0) {
271 } else if (strcmp(data
, "_netdev") == 0) {
273 } else if (strcmp(data
, "nofail") == 0) {
275 } else if (strcmp(data
, "fs") == 0) {
276 if (!value
|| !*value
) {
277 fprintf(stderr
, "mount option fs requires a value.\n");
280 data
= "mds_namespace";
282 } else if (strcmp(data
, "secretfile") == 0) {
285 if (!value
|| !*value
) {
286 fprintf(stderr
, "keyword secretfile found, but no secret file specified\n");
289 ret
= read_secret_from_file(value
, cmi
->cmi_secret
, sizeof(cmi
->cmi_secret
));
291 fprintf(stderr
, "error reading secret file: %d\n", ret
);
294 } else if (strcmp(data
, "secret") == 0) {
297 if (!value
|| !*value
) {
298 fprintf(stderr
, "mount option secret requires a value.\n");
302 len
= strnlen(value
, sizeof(cmi
->cmi_secret
)) + 1;
303 if (len
<= sizeof(cmi
->cmi_secret
))
304 memcpy(cmi
->cmi_secret
, value
, len
);
305 } else if (strcmp(data
, "conf") == 0) {
306 if (!value
|| !*value
) {
307 fprintf(stderr
, "mount option conf requires a value.\n");
310 /* keep pointer to value */
311 cmi
->cmi_conf
= strdup(value
);
314 } else if (strcmp(data
, "name") == 0) {
315 if (!value
|| !*value
) {
316 fprintf(stderr
, "mount option name requires a value.\n");
319 /* keep pointer to value */
322 } else if (strcmp(data
, "ms_mode") == 0) {
323 if (!value
|| !*value
) {
324 fprintf(stderr
, "mount option ms_mode requires a value.\n");
327 /* Only legacy ms_mode needs v1 addrs */
328 v2_addrs
= strcmp(value
, "legacy");
331 /* unrecognized mount options, passing to kernel */
335 /* Copy (possibly modified) option to out */
338 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, ",");
341 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, data
);
342 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, "=");
343 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, value
);
345 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, data
);
352 name_pos
= safe_cat(&cmi
->cmi_name
, &name_len
, name_pos
, "client.");
353 name_pos
= safe_cat(&cmi
->cmi_name
, &name_len
, name_pos
,
354 name
? name
: CEPH_AUTH_NAME_DEFAULT
);
357 mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel.\n",
360 if (!cmi
->cmi_opts
) {
361 cmi
->cmi_opts
= strdup(EMPTY_STRING
);
369 static int parse_arguments(int argc
, char *const *const argv
,
370 const char **src
, const char **node
, const char **opts
)
375 // There were no arguments. Just show the usage.
378 if ((!strcmp(argv
[1], "-h")) || (!strcmp(argv
[1], "--help"))) {
379 // The user asked for help.
383 // The first two arguments are positional
389 // Parse the remaining options
390 *opts
= EMPTY_STRING
;
391 for (i
= 3; i
< argc
; ++i
) {
392 if (!strcmp("-h", argv
[i
]))
394 else if (!strcmp("-n", argv
[i
]))
395 skip_mtab_flag
= true;
396 else if (!strcmp("-v", argv
[i
]))
398 else if (!strcmp("-o", argv
[i
])) {
401 fprintf(stderr
, "Option -o requires an argument.\n\n");
407 fprintf(stderr
, "Can't understand option: '%s'\n\n", argv
[i
]);
414 /* modprobe failing doesn't necessarily prevent from working, so this
416 static void modprobe(void)
420 r
= module_load("ceph", NULL
);
422 printf("failed to load ceph kernel module (%d)\n", r
);
425 static void usage(const char *prog_name
)
427 printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n",
429 printf("options:\n");
430 printf("\t-h: Print this help\n");
431 printf("\t-n: Do not update /etc/mtab\n");
432 printf("\t-v: Verbose\n");
433 printf("\tceph-options: refer to mount.ceph(8)\n");
438 * The structure itself lives on the stack, so don't free it. Just the
441 static void ceph_mount_info_free(struct ceph_mount_info
*cmi
)
450 static int append_key_or_secret_option(struct ceph_mount_info
*cmi
)
452 int pos
= strlen(cmi
->cmi_opts
);
454 if (!cmi
->cmi_secret
[0] && !is_kernel_secret(cmi
->cmi_name
))
458 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, ",");
460 /* when parsing kernel options (-o remount) we get '<hidden>' as the secret */
461 if (cmi
->cmi_secret
[0] && (strcmp(cmi
->cmi_secret
, "<hidden>") != 0)) {
462 int ret
= set_kernel_secret(cmi
->cmi_secret
, cmi
->cmi_name
);
464 if (ret
== -ENODEV
|| ret
== -ENOSYS
) {
465 /* old kernel; fall back to secret= in options */
466 pos
= safe_cat(&cmi
->cmi_opts
,
467 &cmi
->cmi_opts_len
, pos
,
469 pos
= safe_cat(&cmi
->cmi_opts
,
470 &cmi
->cmi_opts_len
, pos
,
474 fprintf(stderr
, "adding ceph secret key to kernel failed: %s\n",
480 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, "key=");
481 pos
= safe_cat(&cmi
->cmi_opts
, &cmi
->cmi_opts_len
, pos
, cmi
->cmi_name
);
486 int main(int argc
, char *argv
[])
488 const char *src
, *node
, *opts
;
491 struct ceph_mount_info cmi
= { 0 };
493 retval
= parse_arguments(argc
, argv
, &src
, &node
, &opts
);
496 retval
= (retval
> 0) ? 0 : EX_USAGE
;
500 retval
= parse_options(opts
, &cmi
);
502 fprintf(stderr
, "failed to parse ceph_options: %d\n", retval
);
507 retval
= parse_src(src
, &cmi
);
509 fprintf(stderr
, "unable to parse mount source: %d\n", retval
);
514 /* We don't care if this errors out, since this is best-effort */
515 fetch_config_info(&cmi
);
518 fprintf(stderr
, "unable to determine mon addresses\n");
523 rsrc
= finalize_src(&cmi
);
525 fprintf(stderr
, "failed to resolve source\n");
530 /* Ensure the ceph key_type is available */
533 retval
= append_key_or_secret_option(&cmi
);
535 fprintf(stderr
, "couldn't append secret option: %d\n", retval
);
540 block_signals(SIG_BLOCK
);
542 if (mount(rsrc
, node
, "ceph", cmi
.cmi_flags
, cmi
.cmi_opts
)) {
546 fprintf(stderr
, "mount error: ceph filesystem not supported by the system\n");
549 fprintf(stderr
, "mount error: no mds server is up or the cluster is laggy\n");
552 fprintf(stderr
, "mount error %d = %s\n",errno
,strerror(errno
));
555 if (!skip_mtab_flag
) {
556 update_mtab_entry(rsrc
, node
, "ceph", cmi
.cmi_opts
, cmi
.cmi_flags
, 0, 0);
560 block_signals(SIG_UNBLOCK
);
562 ceph_mount_info_free(&cmi
);