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.
16 #include "auth/Auth.h"
17 #include "common/ceph_argparse.h"
18 #include "common/config.h"
19 #include "common/version.h"
20 #include "include/str_list.h"
23 * Ceph argument parsing library
25 * We probably should eventually replace this with something standard like popt.
26 * Until we do that, though, this file is the place for argv parsing
36 struct strict_str_convert
{
39 strict_str_convert(const char *str
, std::string
*err
)
40 : str(str
), err(err
) {}
42 inline operator float() const
44 return strict_strtof(str
, err
);
46 inline operator int() const
48 return strict_strtol(str
, 10, err
);
50 inline operator long long() const
52 return strict_strtoll(str
, 10, err
);
56 void string_to_vec(std::vector
<std::string
>& args
, std::string argstr
)
58 istringstream
iss(argstr
);
67 std::pair
<std::vector
<const char*>, std::vector
<const char*>>
68 split_dashdash(const std::vector
<const char*>& args
) {
69 auto dashdash
= std::find_if(args
.begin(), args
.end(),
71 return strcmp(arg
, "--") == 0;
73 std::vector
<const char*> options
{args
.begin(), dashdash
};
74 if (dashdash
!= args
.end()) {
77 std::vector
<const char*> arguments
{dashdash
, args
.end()};
78 return {std::move(options
), std::move(arguments
)};
81 static std::mutex g_str_vec_lock
;
82 static vector
<string
> g_str_vec
;
84 void clear_g_str_vec()
86 g_str_vec_lock
.lock();
88 g_str_vec_lock
.unlock();
91 void env_to_vec(std::vector
<const char*>& args
, const char *name
)
96 auto [options
, arguments
] = split_dashdash(args
);
99 * We can only populate str_vec once. Other threads could hold pointers into
100 * it, so clearing it out and replacing it is not currently safe.
102 g_str_vec_lock
.lock();
103 if (g_str_vec
.empty()) {
104 char *p
= getenv(name
);
106 g_str_vec_lock
.unlock();
109 get_str_vec(p
, " ", g_str_vec
);
111 g_str_vec_lock
.unlock();
113 std::vector
<const char*> env
;
114 for (const auto& s
: g_str_vec
) {
115 env
.push_back(s
.c_str());
117 auto [env_options
, env_arguments
] = split_dashdash(env
);
120 args
.insert(args
.end(), env_options
.begin(), env_options
.end());
121 args
.insert(args
.end(), options
.begin(), options
.end());
122 if (arguments
.empty() && env_arguments
.empty()) {
125 args
.push_back("--");
126 args
.insert(args
.end(), env_arguments
.begin(), env_arguments
.end());
127 args
.insert(args
.end(), arguments
.begin(), arguments
.end());
130 void argv_to_vec(int argc
, const char **argv
,
131 std::vector
<const char*>& args
)
133 args
.insert(args
.end(), argv
+ 1, argv
+ argc
);
136 void vec_to_argv(const char *argv0
, std::vector
<const char*>& args
,
137 int *argc
, const char ***argv
)
139 *argv
= (const char**)malloc(sizeof(char*) * (args
.size() + 1));
145 for (unsigned i
=0; i
<args
.size(); i
++)
146 (*argv
)[(*argc
)++] = args
[i
];
149 void ceph_arg_value_type(const char * nextargstr
, bool *bool_option
, bool *bool_numeric
)
151 bool is_numeric
= true;
152 bool is_float
= false;
155 if (nextargstr
== NULL
) {
159 if (strlen(nextargstr
) < 2) {
162 is_option
= (nextargstr
[0] == '-') && (nextargstr
[1] == '-');
165 for (unsigned int i
= 0; i
< strlen(nextargstr
); i
++) {
166 if (!(nextargstr
[i
] >= '0' && nextargstr
[i
] <= '9')) {
167 // May be negative numeral value
168 if ((i
== 0) && (strlen(nextargstr
) >= 2)) {
169 if (nextargstr
[0] == '-')
172 if ( (nextargstr
[i
] == '.') && (is_float
== false) ) {
183 if (nextargstr
[0] == '-' && is_numeric
== false) {
187 *bool_option
= is_option
;
188 *bool_numeric
= is_numeric
;
194 bool parse_ip_port_vec(const char *s
, vector
<entity_addrvec_t
>& vec
, int type
)
196 // first split by [ ;], which are not valid for an addrvec
198 get_str_list(s
, " ;", items
);
200 for (auto& i
: items
) {
201 const char *s
= i
.c_str();
205 // try parsing as an addr
207 if (a
.parse(s
, &end
, type
)) {
208 vec
.push_back(entity_addrvec_t(a
));
216 // ok, try parsing as an addrvec
218 if (!av
.parse(s
, &end
)) {
231 // The defaults for CephInitParameters
232 CephInitParameters::CephInitParameters(uint32_t module_type_
)
233 : module_type(module_type_
)
235 name
.set(module_type
, "admin");
238 static void dashes_to_underscores(const char *input
, char *output
)
242 const char *i
= input
;
243 // first two characters are copied as-is
250 for (; ((c
= *i
)); ++i
) {
263 /** Once we see a standalone double dash, '--', we should remove it and stop
264 * looking for any other options and flags. */
265 bool ceph_argparse_double_dash(std::vector
<const char*> &args
,
266 std::vector
<const char*>::iterator
&i
)
268 if (strcmp(*i
, "--") == 0) {
275 bool ceph_argparse_flag(std::vector
<const char*> &args
,
276 std::vector
<const char*>::iterator
&i
, ...)
278 const char *first
= *i
;
279 char tmp
[strlen(first
)+1];
280 dashes_to_underscores(first
, tmp
);
286 const char *a
= va_arg(ap
, char*);
291 char a2
[strlen(a
)+1];
292 dashes_to_underscores(a
, a2
);
293 if (strcmp(a2
, first
) == 0) {
301 static bool check_bool_str(const char *val
, int *ret
)
303 if ((strcmp(val
, "true") == 0) || (strcmp(val
, "1") == 0)) {
306 } else if ((strcmp(val
, "false") == 0) || (strcmp(val
, "0") == 0)) {
313 static bool va_ceph_argparse_binary_flag(std::vector
<const char*> &args
,
314 std::vector
<const char*>::iterator
&i
, int *ret
,
315 std::ostream
*oss
, va_list ap
)
317 const char *first
= *i
;
318 char tmp
[strlen(first
)+1];
319 dashes_to_underscores(first
, tmp
);
322 // does this argument match any of the possibilities?
324 const char *a
= va_arg(ap
, char*);
327 int strlen_a
= strlen(a
);
329 dashes_to_underscores(a
, a2
);
330 if (strncmp(a2
, first
, strlen(a2
)) == 0) {
331 if (first
[strlen_a
] == '=') {
333 const char *val
= first
+ strlen_a
+ 1;
334 if (check_bool_str(val
, ret
)) {
338 (*oss
) << "Parse error parsing binary flag " << a
339 << ". Expected true or false, but got '" << val
<< "'\n";
344 else if (first
[strlen_a
] == '\0') {
346 if (next
!= args
.end() &&
349 if (check_bool_str(*next
, ret
)) {
363 bool ceph_argparse_binary_flag(std::vector
<const char*> &args
,
364 std::vector
<const char*>::iterator
&i
, int *ret
,
365 std::ostream
*oss
, ...)
370 r
= va_ceph_argparse_binary_flag(args
, i
, ret
, oss
, ap
);
375 static int va_ceph_argparse_witharg(std::vector
<const char*> &args
,
376 std::vector
<const char*>::iterator
&i
, std::string
*ret
,
377 std::ostream
&oss
, va_list ap
)
379 const char *first
= *i
;
380 char tmp
[strlen(first
)+1];
381 dashes_to_underscores(first
, tmp
);
384 // does this argument match any of the possibilities?
386 const char *a
= va_arg(ap
, char*);
389 int strlen_a
= strlen(a
);
391 dashes_to_underscores(a
, a2
);
392 if (strncmp(a2
, first
, strlen(a2
)) == 0) {
393 if (first
[strlen_a
] == '=') {
394 *ret
= first
+ strlen_a
+ 1;
398 else if (first
[strlen_a
] == '\0') {
399 // find second part (or not)
400 if (i
+1 == args
.end()) {
401 oss
<< "Option " << *i
<< " requires an argument." << std::endl
;
415 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
416 std::vector
<const char*>::iterator
&i
, T
*ret
,
417 std::ostream
&oss
, ...)
421 bool is_option
= false;
422 bool is_numeric
= true;
425 r
= va_ceph_argparse_witharg(args
, i
, &str
, oss
, ap
);
433 ceph_arg_value_type(str
.c_str(), &is_option
, &is_numeric
);
434 if ((is_option
== true) || (is_numeric
== false)) {
436 if (is_option
== true) {
437 oss
<< "Missing option value";
439 oss
<< "The option value '" << str
<< "' is invalid";
445 T myret
= strict_str_convert(str
.c_str(), &err
);
453 template bool ceph_argparse_witharg
<int>(std::vector
<const char*> &args
,
454 std::vector
<const char*>::iterator
&i
, int *ret
,
455 std::ostream
&oss
, ...);
457 template bool ceph_argparse_witharg
<long long>(std::vector
<const char*> &args
,
458 std::vector
<const char*>::iterator
&i
, long long *ret
,
459 std::ostream
&oss
, ...);
461 template bool ceph_argparse_witharg
<float>(std::vector
<const char*> &args
,
462 std::vector
<const char*>::iterator
&i
, float *ret
,
463 std::ostream
&oss
, ...);
465 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
466 std::vector
<const char*>::iterator
&i
, std::string
*ret
,
467 std::ostream
&oss
, ...)
472 r
= va_ceph_argparse_witharg(args
, i
, ret
, oss
, ap
);
477 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
478 std::vector
<const char*>::iterator
&i
, std::string
*ret
, ...)
483 r
= va_ceph_argparse_witharg(args
, i
, ret
, cerr
, ap
);
490 CephInitParameters ceph_argparse_early_args
491 (std::vector
<const char*>& args
, uint32_t module_type
,
492 std::string
*cluster
, std::string
*conf_file_list
)
494 CephInitParameters
iparams(module_type
);
497 vector
<const char *> orig_args
= args
;
499 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
500 if (strcmp(*i
, "--") == 0) {
501 /* Normally we would use ceph_argparse_double_dash. However, in this
502 * function we *don't* want to remove the double dash, because later
503 * argument parses will still need to see it. */
506 else if (ceph_argparse_flag(args
, i
, "--version", "-v", (char*)NULL
)) {
507 cout
<< pretty_version_to_str() << std::endl
;
510 else if (ceph_argparse_witharg(args
, i
, &val
, "--conf", "-c", (char*)NULL
)) {
511 *conf_file_list
= val
;
513 else if (ceph_argparse_flag(args
, i
, "--no-config-file", (char*)NULL
)) {
514 iparams
.no_config_file
= true;
516 else if (ceph_argparse_witharg(args
, i
, &val
, "--cluster", (char*)NULL
)) {
519 else if ((module_type
!= CEPH_ENTITY_TYPE_CLIENT
) &&
520 (ceph_argparse_witharg(args
, i
, &val
, "-i", (char*)NULL
))) {
521 iparams
.name
.set_id(val
);
523 else if (ceph_argparse_witharg(args
, i
, &val
, "--id", "--user", (char*)NULL
)) {
524 iparams
.name
.set_id(val
);
526 else if (ceph_argparse_witharg(args
, i
, &val
, "--name", "-n", (char*)NULL
)) {
527 if (!iparams
.name
.from_str(val
)) {
528 cerr
<< "error parsing '" << val
<< "': expected string of the form TYPE.ID, "
529 << "valid types are: " << EntityName::get_valid_types_as_str()
534 else if (ceph_argparse_flag(args
, i
, "--show_args", (char*)NULL
)) {
536 for (std::vector
<const char *>::iterator ci
= orig_args
.begin(); ci
!= orig_args
.end(); ++ci
) {
537 if (ci
!= orig_args
.begin())
551 static void generic_usage(bool is_server
)
554 " --conf/-c FILE read configuration from the given configuration file" << std::endl
<<
556 " --id/-i ID set ID portion of my name" :
557 " --id ID set ID portion of my name") << std::endl
<<
558 " --name/-n TYPE.ID set name" << std::endl
<<
559 " --cluster NAME set cluster name (default: ceph)" << std::endl
<<
560 " --setuser USER set uid to user or uid (and gid to user's gid)" << std::endl
<<
561 " --setgroup GROUP set gid to group or gid" << std::endl
<<
562 " --version show version and quit" << std::endl
567 " -d run in foreground, log to stderr" << std::endl
<<
568 " -f run in foreground, log to usual location" << std::endl
<<
570 " --debug_ms N set message debug level (e.g. 1)" << std::endl
;
576 bool ceph_argparse_need_usage(const std::vector
<const char*>& args
)
581 for (auto a
: args
) {
582 if (strcmp(a
, "-h") == 0 ||
583 strcmp(a
, "--help") == 0) {
590 void generic_server_usage()
595 void generic_client_usage()
597 generic_usage(false);