Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / mount / mount.ceph.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <sys/mount.h>
6
7 #include "common/module.h"
8 #include "common/secret.h"
9 #include "include/addr_parsing.h"
10
11 #ifndef MS_RELATIME
12 # define MS_RELATIME (1<<21)
13 #endif
14
15 #define MAX_SECRET_LEN 1000
16 #define MAX_SECRET_OPTION_LEN (MAX_SECRET_LEN + 7)
17
18 int verboseflag = 0;
19 int skip_mtab_flag = 0;
20 static const char * const EMPTY_STRING = "";
21
22 /* TODO duplicates logic from kernel */
23 #define CEPH_AUTH_NAME_DEFAULT "guest"
24
25 #include "mtab.c"
26
27 static void block_signals (int how)
28 {
29      sigset_t sigs;
30
31      sigfillset (&sigs);
32      sigdelset(&sigs, SIGTRAP);
33      sigdelset(&sigs, SIGSEGV);
34      sigprocmask (how, &sigs, (sigset_t *) 0);
35 }
36
37 static char *mount_resolve_src(const char *orig_str)
38 {
39         int len, pos;
40         char *mount_path;
41         char *src;
42         char *buf = strdup(orig_str);
43
44         mount_path = strstr(buf, ":/");
45         if (!mount_path) {
46                 printf("source mount path was not specified\n");
47                 free(buf);
48                 return NULL;
49         }
50         if (mount_path == buf) {
51                 printf("server address expected\n");
52                 free(buf);
53                 return NULL;
54         }
55
56         *mount_path = '\0';
57         mount_path++;
58
59         if (!*mount_path) {
60                 printf("incorrect source mount path\n");
61                 free(buf);
62                 return NULL;
63         }
64
65         src = resolve_addrs(buf);
66         if (!src) {
67                 free(buf);
68                 return NULL;
69         }
70
71         len = strlen(src);
72         pos = safe_cat(&src, &len, len, ":");
73         safe_cat(&src, &len, pos, mount_path);
74
75         free(buf);
76         return src;
77 }
78
79 /*
80  * this one is partialy based on parse_options() from cifs.mount.c
81  */
82 static char *parse_options(const char *data, int *filesys_flags)
83 {
84         char * next_keyword = NULL;
85         char * out = NULL;
86         int out_len = 0;
87         int pos = 0;
88         char *name = NULL;
89         int name_len = 0;
90         int name_pos = 0;
91         char secret[MAX_SECRET_LEN];
92         char *saw_name = NULL;
93         char *saw_secret = NULL;
94
95         if(verboseflag)
96                 printf("parsing options: %s\n", data);
97
98         do {
99                 char * value = NULL;
100                 /*  check if ends with trailing comma */
101                 if(*data == 0)
102                         break;
103                 next_keyword = strchr(data,',');
104         
105                 /* temporarily null terminate end of keyword=value pair */
106                 if(next_keyword)
107                         *next_keyword++ = 0;
108
109                 /* temporarily null terminate keyword to make keyword and value distinct */
110                 if ((value = strchr(data, '=')) != NULL) {
111                         *value = '\0';
112                         value++;
113                 }
114
115                 int skip = 1;
116
117                 if (strncmp(data, "ro", 2) == 0) {
118                         *filesys_flags |= MS_RDONLY;
119                 } else if (strncmp(data, "rw", 2) == 0) {
120                         *filesys_flags &= ~MS_RDONLY;
121                 } else if (strncmp(data, "nosuid", 6) == 0) {
122                         *filesys_flags |= MS_NOSUID;
123                 } else if (strncmp(data, "suid", 4) == 0) {
124                         *filesys_flags &= ~MS_NOSUID;
125                 } else if (strncmp(data, "dev", 3) == 0) {
126                         *filesys_flags &= ~MS_NODEV;
127                 } else if (strncmp(data, "nodev", 5) == 0) {
128                         *filesys_flags |= MS_NODEV;
129                 } else if (strncmp(data, "noexec", 6) == 0) {
130                         *filesys_flags |= MS_NOEXEC;
131                 } else if (strncmp(data, "exec", 4) == 0) {
132                         *filesys_flags &= ~MS_NOEXEC;
133                 } else if (strncmp(data, "sync", 4) == 0) {
134                         *filesys_flags |= MS_SYNCHRONOUS;
135                 } else if (strncmp(data, "remount", 7) == 0) {
136                         *filesys_flags |= MS_REMOUNT;
137                 } else if (strncmp(data, "mandlock", 8) == 0) {
138                         *filesys_flags |= MS_MANDLOCK;
139                 } else if ((strncmp(data, "nobrl", 5) == 0) || 
140                            (strncmp(data, "nolock", 6) == 0)) {
141                         *filesys_flags &= ~MS_MANDLOCK;
142                 } else if (strncmp(data, "noatime", 7) == 0) {
143                         *filesys_flags |= MS_NOATIME;
144                 } else if (strncmp(data, "nodiratime", 10) == 0) {
145                         *filesys_flags |= MS_NODIRATIME;
146                 } else if (strncmp(data, "relatime", 8) == 0) {
147                         *filesys_flags |= MS_RELATIME;
148
149                 } else if (strncmp(data, "noauto", 6) == 0) {
150                         skip = 1;  /* ignore */
151                 } else if (strncmp(data, "_netdev", 7) == 0) {
152                         skip = 1;  /* ignore */
153
154                 } else if (strncmp(data, "secretfile", 10) == 0) {
155                         if (!value || !*value) {
156                                 printf("keyword secretfile found, but no secret file specified\n");
157                                 free(saw_name);
158                                 return NULL;
159                         }
160
161                         if (read_secret_from_file(value, secret, sizeof(secret)) < 0) {
162                                 printf("error reading secret file\n");
163                                 return NULL;
164                         }
165
166                         /* see comment for "secret" */
167                         saw_secret = secret;
168                         skip = 1;
169                 } else if (strncmp(data, "secret", 6) == 0) {
170                         if (!value || !*value) {
171                                 printf("mount option secret requires a value.\n");
172                                 free(saw_name);
173                                 return NULL;
174                         }
175
176                         /* secret is only added to kernel options as
177                            backwards compatibility, if add_key doesn't
178                            recognize our keytype; hence, it is skipped
179                            here and appended to options on add_key
180                            failure */
181                         size_t len = sizeof(secret);
182                         strncpy(secret, value, len-1);
183                         secret[len-1] = '\0';
184                         saw_secret = secret;
185                         skip = 1;
186                 } else if (strncmp(data, "name", 4) == 0) {
187                         if (!value || !*value) {
188                                 printf("mount option name requires a value.\n");
189                                 return NULL;
190                         }
191
192                         /* take a copy of the name, to be used for
193                            naming the keys that we add to kernel; */
194                         free(saw_name);
195                         saw_name = strdup(value);
196                         if (!saw_name) {
197                                 printf("out of memory.\n");
198                                 return NULL;
199                         }
200                         skip = 0;
201                 } else {
202                         skip = 0;
203                         if (verboseflag) {
204                           fprintf(stderr, "mount.ceph: unrecognized mount option \"%s\", "
205                                           "passing to kernel.\n", data);
206             }
207                 }
208
209                 /* Copy (possibly modified) option to out */
210                 if (!skip) {
211                         if (pos)
212                                 pos = safe_cat(&out, &out_len, pos, ",");
213
214                         if (value) {
215                                 pos = safe_cat(&out, &out_len, pos, data);
216                                 pos = safe_cat(&out, &out_len, pos, "=");
217                                 pos = safe_cat(&out, &out_len, pos, value);
218                         } else {
219                                 pos = safe_cat(&out, &out_len, pos, data);
220                         }
221                         
222                 }
223                 data = next_keyword;
224         } while (data);
225
226         name_pos = safe_cat(&name, &name_len, name_pos, "client.");
227         if (!saw_name) {
228                 name_pos = safe_cat(&name, &name_len, name_pos, CEPH_AUTH_NAME_DEFAULT);
229         } else {
230                 name_pos = safe_cat(&name, &name_len, name_pos, saw_name);
231         }
232         if (saw_secret || is_kernel_secret(name)) {
233                 int ret;
234                 char secret_option[MAX_SECRET_OPTION_LEN];
235                 ret = get_secret_option(saw_secret, name, secret_option, sizeof(secret_option));
236                 if (ret < 0) {
237                         free(saw_name);
238                         return NULL;
239                 } else {
240                         if (pos) {
241                                 pos = safe_cat(&out, &out_len, pos, ",");
242                         }
243                         pos = safe_cat(&out, &out_len, pos, secret_option);
244                 }
245         }
246
247         free(saw_name);
248         if (!out)
249                 return strdup(EMPTY_STRING);
250         return out;
251 }
252
253
254 static int parse_arguments(int argc, char *const *const argv,
255                 const char **src, const char **node, const char **opts)
256 {
257         int i;
258
259         if (argc < 2) {
260                 // There were no arguments. Just show the usage.
261                 return 1;
262         }
263         if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
264                 // The user asked for help.
265                 return 1;
266         }
267
268         // The first two arguments are positional
269         if (argc < 3)
270                 return -EINVAL;
271         *src = argv[1];
272         *node = argv[2];
273
274         // Parse the remaining options
275         *opts = EMPTY_STRING;
276         for (i = 3; i < argc; ++i) {
277                 if (!strcmp("-h", argv[i]))
278                         return 1;
279                 else if (!strcmp("-n", argv[i]))
280                         skip_mtab_flag = 1;
281                 else if (!strcmp("-v", argv[i]))
282                         verboseflag = 1;
283                 else if (!strcmp("-o", argv[i])) {
284                         ++i;
285                         if (i >= argc) {
286                                 printf("Option -o requires an argument.\n\n");
287                                 return -EINVAL;
288                         }
289                         *opts = argv[i];
290                 }
291                 else {
292                         printf("Can't understand option: '%s'\n\n", argv[i]);
293                         return -EINVAL;
294                 }
295         }
296         return 0;
297 }
298
299 /* modprobe failing doesn't necessarily prevent from working, so this
300    returns void */
301 static void modprobe(void)
302 {
303         int r;
304
305         r = module_load("ceph", NULL);
306         if (r)
307                 printf("failed to load ceph kernel module (%d)\n", r);
308 }
309
310 static void usage(const char *prog_name)
311 {
312         printf("usage: %s [src] [mount-point] [-n] [-v] [-o ceph-options]\n",
313                 prog_name);
314         printf("options:\n");
315         printf("\t-h: Print this help\n");
316         printf("\t-n: Do not update /etc/mtab\n");
317         printf("\t-v: Verbose\n");
318         printf("\tceph-options: refer to mount.ceph(8)\n");
319         printf("\n");
320 }
321
322 int main(int argc, char *argv[])
323 {
324         const char *src, *node, *opts;
325         char *rsrc = NULL;
326         char *popts = NULL;
327         int flags = 0;
328         int retval = 0;
329
330         retval = parse_arguments(argc, argv, &src, &node, &opts);
331         if (retval) {
332                 usage(argv[0]);
333                 exit((retval > 0) ? EXIT_SUCCESS : EXIT_FAILURE);
334         }
335
336         rsrc = mount_resolve_src(src);
337         if (!rsrc) {
338                 printf("failed to resolve source\n");
339                 exit(1);
340         }
341
342         modprobe();
343
344         popts = parse_options(opts, &flags);
345         if (!popts) {
346                 printf("failed to parse ceph_options\n");
347                 exit(1);
348         }
349
350         block_signals(SIG_BLOCK);
351
352         if (mount(rsrc, node, "ceph", flags, popts)) {
353                 retval = errno;
354                 switch (errno) {
355                 case ENODEV:
356                         printf("mount error: ceph filesystem not supported by the system\n");
357                         break;
358                 default:
359                         printf("mount error %d = %s\n",errno,strerror(errno));
360                 }
361         } else {
362                 if (!skip_mtab_flag) {
363                         update_mtab_entry(rsrc, node, "ceph", popts, flags, 0, 0);
364                 }
365         }
366
367         block_signals(SIG_UNBLOCK);
368
369         free(popts);
370         free(rsrc);
371         exit(retval);
372 }
373