1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "auth/Auth.h"
16 #include "common/ceph_argparse.h"
17 #include "common/config.h"
18 #include "common/version.h"
19 #include "include/str_list.h"
22 * Ceph argument parsing library
24 * We probably should eventually replace this with something standard like popt.
25 * Until we do that, though, this file is the place for argv parsing
35 struct strict_str_convert {
38 strict_str_convert(const char *str, std::string *err)
39 : str(str), err(err) {}
41 inline operator float() const
43 return strict_strtof(str, err);
45 inline operator int() const
47 return strict_strtol(str, 10, err);
49 inline operator long long() const
51 return strict_strtoll(str, 10, err);
55 void string_to_vec(std::vector<std::string>& args, std::string argstr)
57 istringstream iss(argstr);
66 bool split_dashdash(const std::vector<const char*>& args,
67 std::vector<const char*>& options,
68 std::vector<const char*>& arguments) {
69 bool dashdash = false;
70 for (std::vector<const char*>::const_iterator i = args.begin();
74 arguments.push_back(*i);
76 if (strcmp(*i, "--") == 0)
79 options.push_back(*i);
85 void env_to_vec(std::vector<const char*>& args, const char *name)
89 char *p = getenv(name);
93 bool dashdash = false;
94 std::vector<const char*> options;
95 std::vector<const char*> arguments;
96 if (split_dashdash(args, options, arguments))
99 std::vector<const char*> env_options;
100 std::vector<const char*> env_arguments;
101 static vector<string> str_vec;
102 std::vector<const char*> env;
104 get_str_vec(p, " ", str_vec);
105 for (vector<string>::iterator i = str_vec.begin();
108 env.push_back(i->c_str());
109 if (split_dashdash(env, env_options, env_arguments))
113 args.insert(args.end(), options.begin(), options.end());
114 args.insert(args.end(), env_options.begin(), env_options.end());
116 args.push_back("--");
117 args.insert(args.end(), arguments.begin(), arguments.end());
118 args.insert(args.end(), env_arguments.begin(), env_arguments.end());
121 void argv_to_vec(int argc, const char **argv,
122 std::vector<const char*>& args)
124 args.insert(args.end(), argv + 1, argv + argc);
127 void vec_to_argv(const char *argv0, std::vector<const char*>& args,
128 int *argc, const char ***argv)
130 *argv = (const char**)malloc(sizeof(char*) * (args.size() + 1));
136 for (unsigned i=0; i<args.size(); i++)
137 (*argv)[(*argc)++] = args[i];
140 void ceph_arg_value_type(const char * nextargstr, bool *bool_option, bool *bool_numeric)
142 bool is_numeric = true;
143 bool is_float = false;
146 if (nextargstr == NULL) {
150 if (strlen(nextargstr) < 2) {
153 is_option = (nextargstr[0] == '-') && (nextargstr[1] == '-');
156 for (unsigned int i = 0; i < strlen(nextargstr); i++) {
157 if (!(nextargstr[i] >= '0' && nextargstr[i] <= '9')) {
158 // May be negative numeral value
159 if ((i == 0) && (strlen(nextargstr) >= 2)) {
160 if (nextargstr[0] == '-')
163 if ( (nextargstr[i] == '.') && (is_float == false) ) {
174 if (nextargstr[0] == '-' && is_numeric == false) {
178 *bool_option = is_option;
179 *bool_numeric = is_numeric;
184 bool parse_ip_port_vec(const char *s, vector<entity_addr_t>& vec)
187 const char *end = p + strlen(p);
190 //cout << " parse at '" << p << "'" << std::endl;
191 if (!a.parse(p, &p)) {
192 //dout(0) << " failed to parse address '" << p << "'" << dendl;
195 //cout << " got " << a << ", rest is '" << p << "'" << std::endl;
197 while (*p == ',' || *p == ' ' || *p == ';')
203 // The defaults for CephInitParameters
204 CephInitParameters::CephInitParameters(uint32_t module_type_)
205 : module_type(module_type_)
207 name.set(module_type, "admin");
210 static void dashes_to_underscores(const char *input, char *output)
214 const char *i = input;
215 // first two characters are copied as-is
222 for (; ((c = *i)); ++i) {
235 /** Once we see a standalone double dash, '--', we should remove it and stop
236 * looking for any other options and flags. */
237 bool ceph_argparse_double_dash(std::vector<const char*> &args,
238 std::vector<const char*>::iterator &i)
240 if (strcmp(*i, "--") == 0) {
247 bool ceph_argparse_flag(std::vector<const char*> &args,
248 std::vector<const char*>::iterator &i, ...)
250 const char *first = *i;
251 char tmp[strlen(first)+1];
252 dashes_to_underscores(first, tmp);
258 const char *a = va_arg(ap, char*);
263 char a2[strlen(a)+1];
264 dashes_to_underscores(a, a2);
265 if (strcmp(a2, first) == 0) {
273 static bool va_ceph_argparse_binary_flag(std::vector<const char*> &args,
274 std::vector<const char*>::iterator &i, int *ret,
275 std::ostream *oss, va_list ap)
277 const char *first = *i;
278 char tmp[strlen(first)+1];
279 dashes_to_underscores(first, tmp);
282 // does this argument match any of the possibilities?
284 const char *a = va_arg(ap, char*);
287 int strlen_a = strlen(a);
289 dashes_to_underscores(a, a2);
290 if (strncmp(a2, first, strlen(a2)) == 0) {
291 if (first[strlen_a] == '=') {
293 const char *val = first + strlen_a + 1;
294 if ((strcmp(val, "true") == 0) || (strcmp(val, "1") == 0)) {
298 else if ((strcmp(val, "false") == 0) || (strcmp(val, "0") == 0)) {
303 (*oss) << "Parse error parsing binary flag " << a
304 << ". Expected true or false, but got '" << val << "'\n";
309 else if (first[strlen_a] == '\0') {
318 bool ceph_argparse_binary_flag(std::vector<const char*> &args,
319 std::vector<const char*>::iterator &i, int *ret,
320 std::ostream *oss, ...)
325 r = va_ceph_argparse_binary_flag(args, i, ret, oss, ap);
330 static int va_ceph_argparse_witharg(std::vector<const char*> &args,
331 std::vector<const char*>::iterator &i, std::string *ret,
332 std::ostream &oss, va_list ap)
334 const char *first = *i;
335 char tmp[strlen(first)+1];
336 dashes_to_underscores(first, tmp);
339 // does this argument match any of the possibilities?
341 const char *a = va_arg(ap, char*);
344 int strlen_a = strlen(a);
346 dashes_to_underscores(a, a2);
347 if (strncmp(a2, first, strlen(a2)) == 0) {
348 if (first[strlen_a] == '=') {
349 *ret = first + strlen_a + 1;
353 else if (first[strlen_a] == '\0') {
354 // find second part (or not)
355 if (i+1 == args.end()) {
356 oss << "Option " << *i << " requires an argument." << std::endl;
370 bool ceph_argparse_witharg(std::vector<const char*> &args,
371 std::vector<const char*>::iterator &i, T *ret,
372 std::ostream &oss, ...)
376 bool is_option = false;
377 bool is_numeric = true;
380 r = va_ceph_argparse_witharg(args, i, &str, oss, ap);
388 ceph_arg_value_type(str.c_str(), &is_option, &is_numeric);
389 if ((is_option == true) || (is_numeric == false)) {
391 if (is_option == true) {
392 oss << "Missing option value";
394 oss << "The option value '" << str << "' is invalid";
400 T myret = strict_str_convert(str.c_str(), &err);
408 template bool ceph_argparse_witharg<int>(std::vector<const char*> &args,
409 std::vector<const char*>::iterator &i, int *ret,
410 std::ostream &oss, ...);
412 template bool ceph_argparse_witharg<long long>(std::vector<const char*> &args,
413 std::vector<const char*>::iterator &i, long long *ret,
414 std::ostream &oss, ...);
416 template bool ceph_argparse_witharg<float>(std::vector<const char*> &args,
417 std::vector<const char*>::iterator &i, float *ret,
418 std::ostream &oss, ...);
420 bool ceph_argparse_witharg(std::vector<const char*> &args,
421 std::vector<const char*>::iterator &i, std::string *ret,
422 std::ostream &oss, ...)
427 r = va_ceph_argparse_witharg(args, i, ret, oss, ap);
432 bool ceph_argparse_witharg(std::vector<const char*> &args,
433 std::vector<const char*>::iterator &i, std::string *ret, ...)
438 r = va_ceph_argparse_witharg(args, i, ret, cerr, ap);
445 CephInitParameters ceph_argparse_early_args
446 (std::vector<const char*>& args, uint32_t module_type,
447 std::string *cluster, std::string *conf_file_list)
449 CephInitParameters iparams(module_type);
452 vector<const char *> orig_args = args;
454 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
455 if (strcmp(*i, "--") == 0) {
456 /* Normally we would use ceph_argparse_double_dash. However, in this
457 * function we *don't* want to remove the double dash, because later
458 * argument parses will still need to see it. */
461 else if (ceph_argparse_flag(args, i, "--version", "-v", (char*)NULL)) {
462 cout << pretty_version_to_str() << std::endl;
465 else if (ceph_argparse_witharg(args, i, &val, "--conf", "-c", (char*)NULL)) {
466 *conf_file_list = val;
468 else if (ceph_argparse_witharg(args, i, &val, "--cluster", (char*)NULL)) {
471 else if ((module_type != CEPH_ENTITY_TYPE_CLIENT) &&
472 (ceph_argparse_witharg(args, i, &val, "-i", (char*)NULL))) {
473 iparams.name.set_id(val);
475 else if (ceph_argparse_witharg(args, i, &val, "--id", "--user", (char*)NULL)) {
476 iparams.name.set_id(val);
478 else if (ceph_argparse_witharg(args, i, &val, "--name", "-n", (char*)NULL)) {
479 if (!iparams.name.from_str(val)) {
480 cerr << "error parsing '" << val << "': expected string of the form TYPE.ID, "
481 << "valid types are: " << EntityName::get_valid_types_as_str()
486 else if (ceph_argparse_flag(args, i, "--show_args", (char*)NULL)) {
488 for (std::vector<const char *>::iterator ci = orig_args.begin(); ci != orig_args.end(); ++ci) {
489 if (ci != orig_args.begin())
503 static void generic_usage(bool is_server)
506 --conf/-c FILE read configuration from the given configuration file\n\
507 --id/-i ID set ID portion of my name\n\
508 --name/-n TYPE.ID set name\n\
509 --cluster NAME set cluster name (default: ceph)\n\
510 --setuser USER set uid to user or uid (and gid to user's gid)\n\
511 --setgroup GROUP set gid to group or gid\n\
512 --version show version and quit\n\
517 -d run in foreground, log to stderr.\n\
518 -f run in foreground, log to usual location.\n";
520 --debug_ms N set message debug level (e.g. 1)\n";
526 void generic_server_usage()
531 void generic_client_usage()
533 generic_usage(false);