mirror of
https://github.com/ceph/ceph
synced 2025-01-16 16:03:29 +00:00
766528ee9c
Fixes: http://tracker.ceph.com/issues/19883 (Partially) Signed-off-by: Brad Hubbard <bhubbard@redhat.com>
374 lines
8.6 KiB
C
374 lines
8.6 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <sys/mount.h>
|
|
|
|
#include "common/module.h"
|
|
#include "common/secret.h"
|
|
#include "include/addr_parsing.h"
|
|
|
|
#ifndef MS_RELATIME
|
|
# define MS_RELATIME (1<<21)
|
|
#endif
|
|
|
|
#define MAX_SECRET_LEN 1000
|
|
#define MAX_SECRET_OPTION_LEN (MAX_SECRET_LEN + 7)
|
|
|
|
int verboseflag = 0;
|
|
int skip_mtab_flag = 0;
|
|
static const char * const EMPTY_STRING = "";
|
|
|
|
/* TODO duplicates logic from kernel */
|
|
#define CEPH_AUTH_NAME_DEFAULT "guest"
|
|
|
|
#include "mtab.c"
|
|
|
|
static void block_signals (int how)
|
|
{
|
|
sigset_t sigs;
|
|
|
|
sigfillset (&sigs);
|
|
sigdelset(&sigs, SIGTRAP);
|
|
sigdelset(&sigs, SIGSEGV);
|
|
sigprocmask (how, &sigs, (sigset_t *) 0);
|
|
}
|
|
|
|
static char *mount_resolve_src(const char *orig_str)
|
|
{
|
|
int len, pos;
|
|
char *mount_path;
|
|
char *src;
|
|
char *buf = strdup(orig_str);
|
|
|
|
mount_path = strstr(buf, ":/");
|
|
if (!mount_path) {
|
|
printf("source mount path was not specified\n");
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
if (mount_path == buf) {
|
|
printf("server address expected\n");
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
*mount_path = '\0';
|
|
mount_path++;
|
|
|
|
if (!*mount_path) {
|
|
printf("incorrect source mount path\n");
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
src = resolve_addrs(buf);
|
|
if (!src) {
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
len = strlen(src);
|
|
pos = safe_cat(&src, &len, len, ":");
|
|
safe_cat(&src, &len, pos, mount_path);
|
|
|
|
free(buf);
|
|
return src;
|
|
}
|
|
|
|
/*
|
|
* this one is partialy based on parse_options() from cifs.mount.c
|
|
*/
|
|
static char *parse_options(const char *data, int *filesys_flags)
|
|
{
|
|
char * next_keyword = NULL;
|
|
char * out = NULL;
|
|
int out_len = 0;
|
|
int pos = 0;
|
|
char *name = NULL;
|
|
int name_len = 0;
|
|
int name_pos = 0;
|
|
char secret[MAX_SECRET_LEN];
|
|
char *saw_name = NULL;
|
|
char *saw_secret = NULL;
|
|
|
|
if(verboseflag)
|
|
printf("parsing options: %s\n", data);
|
|
|
|
do {
|
|
char * value = NULL;
|
|
/* check if ends with trailing comma */
|
|
if(*data == 0)
|
|
break;
|
|
next_keyword = strchr(data,',');
|
|
|
|
/* temporarily null terminate end of keyword=value pair */
|
|
if(next_keyword)
|
|
*next_keyword++ = 0;
|
|
|
|
/* temporarily null terminate keyword to make keyword and value distinct */
|
|
if ((value = strchr(data, '=')) != NULL) {
|
|
*value = '\0';
|
|
value++;
|
|
}
|
|
|
|
int skip = 1;
|
|
|
|
if (strncmp(data, "ro", 2) == 0) {
|
|
*filesys_flags |= MS_RDONLY;
|
|
} else if (strncmp(data, "rw", 2) == 0) {
|
|
*filesys_flags &= ~MS_RDONLY;
|
|
} else if (strncmp(data, "nosuid", 6) == 0) {
|
|
*filesys_flags |= MS_NOSUID;
|
|
} else if (strncmp(data, "suid", 4) == 0) {
|
|
*filesys_flags &= ~MS_NOSUID;
|
|
} else if (strncmp(data, "dev", 3) == 0) {
|
|
*filesys_flags &= ~MS_NODEV;
|
|
} else if (strncmp(data, "nodev", 5) == 0) {
|
|
*filesys_flags |= MS_NODEV;
|
|
} else if (strncmp(data, "noexec", 6) == 0) {
|
|
*filesys_flags |= MS_NOEXEC;
|
|
} else if (strncmp(data, "exec", 4) == 0) {
|
|
*filesys_flags &= ~MS_NOEXEC;
|
|
} else if (strncmp(data, "sync", 4) == 0) {
|
|
*filesys_flags |= MS_SYNCHRONOUS;
|
|
} else if (strncmp(data, "remount", 7) == 0) {
|
|
*filesys_flags |= MS_REMOUNT;
|
|
} else if (strncmp(data, "mandlock", 8) == 0) {
|
|
*filesys_flags |= MS_MANDLOCK;
|
|
} else if ((strncmp(data, "nobrl", 5) == 0) ||
|
|
(strncmp(data, "nolock", 6) == 0)) {
|
|
*filesys_flags &= ~MS_MANDLOCK;
|
|
} else if (strncmp(data, "noatime", 7) == 0) {
|
|
*filesys_flags |= MS_NOATIME;
|
|
} else if (strncmp(data, "nodiratime", 10) == 0) {
|
|
*filesys_flags |= MS_NODIRATIME;
|
|
} else if (strncmp(data, "relatime", 8) == 0) {
|
|
*filesys_flags |= MS_RELATIME;
|
|
|
|
} else if (strncmp(data, "noauto", 6) == 0) {
|
|
skip = 1; /* ignore */
|
|
} else if (strncmp(data, "_netdev", 7) == 0) {
|
|
skip = 1; /* ignore */
|
|
|
|
} else if (strncmp(data, "secretfile", 10) == 0) {
|
|
if (!value || !*value) {
|
|
printf("keyword secretfile found, but no secret file specified\n");
|
|
free(saw_name);
|
|
return NULL;
|
|
}
|
|
|
|
if (read_secret_from_file(value, secret, sizeof(secret)) < 0) {
|
|
printf("error reading secret file\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* see comment for "secret" */
|
|
saw_secret = secret;
|
|
skip = 1;
|
|
} else if (strncmp(data, "secret", 6) == 0) {
|
|
if (!value || !*value) {
|
|
printf("mount option secret requires a value.\n");
|
|
free(saw_name);
|
|
return NULL;
|
|
}
|
|
|
|
/* secret is only added to kernel options as
|
|
backwards compatibility, if add_key doesn't
|
|
recognize our keytype; hence, it is skipped
|
|
here and appended to options on add_key
|
|
failure */
|
|
size_t len = sizeof(secret);
|
|
strncpy(secret, value, len-1);
|
|
secret[len-1] = '\0';
|
|
saw_secret = secret;
|
|
skip = 1;
|
|
} else if (strncmp(data, "name", 4) == 0) {
|
|
if (!value || !*value) {
|
|
printf("mount option name requires a value.\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* take a copy of the name, to be used for
|
|
naming the keys that we add to kernel; */
|
|
free(saw_name);
|
|
saw_name = strdup(value);
|
|
if (!saw_name) {
|
|
printf("out of memory.\n");
|
|
return NULL;
|
|
}
|
|
skip = 0;
|
|
} else {
|
|
skip = 0;
|
|
if (verboseflag) {
|
|
fprintf(stderr, "mount.ceph: unrecognized mount option \"%s\", "
|
|
"passing to kernel.\n", data);
|
|
}
|
|
}
|
|
|
|
/* Copy (possibly modified) option to out */
|
|
if (!skip) {
|
|
if (pos)
|
|
pos = safe_cat(&out, &out_len, pos, ",");
|
|
|
|
if (value) {
|
|
pos = safe_cat(&out, &out_len, pos, data);
|
|
pos = safe_cat(&out, &out_len, pos, "=");
|
|
pos = safe_cat(&out, &out_len, pos, value);
|
|
} else {
|
|
pos = safe_cat(&out, &out_len, pos, data);
|
|
}
|
|
|
|
}
|
|
data = next_keyword;
|
|
} while (data);
|
|
|
|
name_pos = safe_cat(&name, &name_len, name_pos, "client.");
|
|
if (!saw_name) {
|
|
name_pos = safe_cat(&name, &name_len, name_pos, CEPH_AUTH_NAME_DEFAULT);
|
|
} else {
|
|
name_pos = safe_cat(&name, &name_len, name_pos, saw_name);
|
|
}
|
|
if (saw_secret || is_kernel_secret(name)) {
|
|
int ret;
|
|
char secret_option[MAX_SECRET_OPTION_LEN];
|
|
ret = get_secret_option(saw_secret, name, secret_option, sizeof(secret_option));
|
|
if (ret < 0) {
|
|
free(saw_name);
|
|
return NULL;
|
|
} else {
|
|
if (pos) {
|
|
pos = safe_cat(&out, &out_len, pos, ",");
|
|
}
|
|
pos = safe_cat(&out, &out_len, pos, secret_option);
|
|
}
|
|
}
|
|
|
|
free(saw_name);
|
|
if (!out)
|
|
return strdup(EMPTY_STRING);
|
|
return out;
|
|
}
|
|
|
|
|
|
static int parse_arguments(int argc, char *const *const argv,
|
|
const char **src, const char **node, const char **opts)
|
|
{
|
|
int i;
|
|
|
|
if (argc < 2) {
|
|
// There were no arguments. Just show the usage.
|
|
return 1;
|
|
}
|
|
if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
|
|
// The user asked for help.
|
|
return 1;
|
|
}
|
|
|
|
// The first two arguments are positional
|
|
if (argc < 3)
|
|
return -EINVAL;
|
|
*src = argv[1];
|
|
*node = argv[2];
|
|
|
|
// Parse the remaining options
|
|
*opts = EMPTY_STRING;
|
|
for (i = 3; i < argc; ++i) {
|
|
if (!strcmp("-h", argv[i]))
|
|
return 1;
|
|
else if (!strcmp("-n", argv[i]))
|
|
skip_mtab_flag = 1;
|
|
else if (!strcmp("-v", argv[i]))
|
|
verboseflag = 1;
|
|
else if (!strcmp("-o", argv[i])) {
|
|
++i;
|
|
if (i >= argc) {
|
|
printf("Option -o requires an argument.\n\n");
|
|
return -EINVAL;
|
|
}
|
|
*opts = argv[i];
|
|
}
|
|
else {
|
|
printf("Can't understand option: '%s'\n\n", argv[i]);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* modprobe failing doesn't necessarily prevent from working, so this
|
|
returns void */
|
|
static void modprobe(void)
|
|
{
|
|
int r;
|
|
|
|
r = module_load("ceph", NULL);
|
|
if (r)
|
|
printf("failed to load ceph kernel module (%d)\n", r);
|
|
}
|
|
|
|
static void usage(const char *prog_name)
|
|
{
|
|
printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n",
|
|
prog_name);
|
|
printf("options:\n");
|
|
printf("\t-h: Print this help\n");
|
|
printf("\t-n: Do not update /etc/mtab\n");
|
|
printf("\t-v: Verbose\n");
|
|
printf("\tceph-options: refer to mount.ceph(8)\n");
|
|
printf("\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
const char *src, *node, *opts;
|
|
char *rsrc = NULL;
|
|
char *popts = NULL;
|
|
int flags = 0;
|
|
int retval = 0;
|
|
|
|
retval = parse_arguments(argc, argv, &src, &node, &opts);
|
|
if (retval) {
|
|
usage(argv[0]);
|
|
exit((retval > 0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
}
|
|
|
|
rsrc = mount_resolve_src(src);
|
|
if (!rsrc) {
|
|
printf("failed to resolve source\n");
|
|
exit(1);
|
|
}
|
|
|
|
modprobe();
|
|
|
|
popts = parse_options(opts, &flags);
|
|
if (!popts) {
|
|
printf("failed to parse ceph_options\n");
|
|
exit(1);
|
|
}
|
|
|
|
block_signals(SIG_BLOCK);
|
|
|
|
if (mount(rsrc, node, "ceph", flags, popts)) {
|
|
retval = errno;
|
|
switch (errno) {
|
|
case ENODEV:
|
|
printf("mount error: ceph filesystem not supported by the system\n");
|
|
break;
|
|
default:
|
|
printf("mount error %d = %s\n",errno,strerror(errno));
|
|
}
|
|
} else {
|
|
if (!skip_mtab_flag) {
|
|
update_mtab_entry(rsrc, node, "ceph", popts, flags, 0, 0);
|
|
}
|
|
}
|
|
|
|
block_signals(SIG_UNBLOCK);
|
|
|
|
free(popts);
|
|
free(rsrc);
|
|
exit(retval);
|
|
}
|
|
|