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 static std::mutex g_str_vec_lock
;
86 static vector
<string
> g_str_vec
;
88 void clear_g_str_vec()
90 g_str_vec_lock
.lock();
92 g_str_vec_lock
.unlock();
95 void env_to_vec(std::vector
<const char*>& args
, const char *name
)
100 bool dashdash
= false;
101 std::vector
<const char*> options
;
102 std::vector
<const char*> arguments
;
103 if (split_dashdash(args
, options
, arguments
))
106 std::vector
<const char*> env_options
;
107 std::vector
<const char*> env_arguments
;
108 std::vector
<const char*> env
;
111 * We can only populate str_vec once. Other threads could hold pointers into
112 * it, so clearing it out and replacing it is not currently safe.
114 g_str_vec_lock
.lock();
115 if (g_str_vec
.empty()) {
116 char *p
= getenv(name
);
118 g_str_vec_lock
.unlock();
121 get_str_vec(p
, " ", g_str_vec
);
123 g_str_vec_lock
.unlock();
125 vector
<string
>::iterator i
;
126 for (i
= g_str_vec
.begin(); i
!= g_str_vec
.end(); ++i
)
127 env
.push_back(i
->c_str());
128 if (split_dashdash(env
, env_options
, env_arguments
))
132 args
.insert(args
.end(), options
.begin(), options
.end());
133 args
.insert(args
.end(), env_options
.begin(), env_options
.end());
135 args
.push_back("--");
136 args
.insert(args
.end(), arguments
.begin(), arguments
.end());
137 args
.insert(args
.end(), env_arguments
.begin(), env_arguments
.end());
140 void argv_to_vec(int argc
, const char **argv
,
141 std::vector
<const char*>& args
)
143 args
.insert(args
.end(), argv
+ 1, argv
+ argc
);
146 void vec_to_argv(const char *argv0
, std::vector
<const char*>& args
,
147 int *argc
, const char ***argv
)
149 *argv
= (const char**)malloc(sizeof(char*) * (args
.size() + 1));
155 for (unsigned i
=0; i
<args
.size(); i
++)
156 (*argv
)[(*argc
)++] = args
[i
];
159 void ceph_arg_value_type(const char * nextargstr
, bool *bool_option
, bool *bool_numeric
)
161 bool is_numeric
= true;
162 bool is_float
= false;
165 if (nextargstr
== NULL
) {
169 if (strlen(nextargstr
) < 2) {
172 is_option
= (nextargstr
[0] == '-') && (nextargstr
[1] == '-');
175 for (unsigned int i
= 0; i
< strlen(nextargstr
); i
++) {
176 if (!(nextargstr
[i
] >= '0' && nextargstr
[i
] <= '9')) {
177 // May be negative numeral value
178 if ((i
== 0) && (strlen(nextargstr
) >= 2)) {
179 if (nextargstr
[0] == '-')
182 if ( (nextargstr
[i
] == '.') && (is_float
== false) ) {
193 if (nextargstr
[0] == '-' && is_numeric
== false) {
197 *bool_option
= is_option
;
198 *bool_numeric
= is_numeric
;
203 bool parse_ip_port_vec(const char *s
, vector
<entity_addr_t
>& vec
)
206 const char *end
= p
+ strlen(p
);
209 //cout << " parse at '" << p << "'" << std::endl;
210 if (!a
.parse(p
, &p
)) {
211 //dout(0) << " failed to parse address '" << p << "'" << dendl;
214 //cout << " got " << a << ", rest is '" << p << "'" << std::endl;
216 while (*p
== ',' || *p
== ' ' || *p
== ';')
222 // The defaults for CephInitParameters
223 CephInitParameters::CephInitParameters(uint32_t module_type_
)
224 : module_type(module_type_
)
226 name
.set(module_type
, "admin");
229 static void dashes_to_underscores(const char *input
, char *output
)
233 const char *i
= input
;
234 // first two characters are copied as-is
241 for (; ((c
= *i
)); ++i
) {
254 /** Once we see a standalone double dash, '--', we should remove it and stop
255 * looking for any other options and flags. */
256 bool ceph_argparse_double_dash(std::vector
<const char*> &args
,
257 std::vector
<const char*>::iterator
&i
)
259 if (strcmp(*i
, "--") == 0) {
266 bool ceph_argparse_flag(std::vector
<const char*> &args
,
267 std::vector
<const char*>::iterator
&i
, ...)
269 const char *first
= *i
;
270 char tmp
[strlen(first
)+1];
271 dashes_to_underscores(first
, tmp
);
277 const char *a
= va_arg(ap
, char*);
282 char a2
[strlen(a
)+1];
283 dashes_to_underscores(a
, a2
);
284 if (strcmp(a2
, first
) == 0) {
292 static bool va_ceph_argparse_binary_flag(std::vector
<const char*> &args
,
293 std::vector
<const char*>::iterator
&i
, int *ret
,
294 std::ostream
*oss
, va_list ap
)
296 const char *first
= *i
;
297 char tmp
[strlen(first
)+1];
298 dashes_to_underscores(first
, tmp
);
301 // does this argument match any of the possibilities?
303 const char *a
= va_arg(ap
, char*);
306 int strlen_a
= strlen(a
);
308 dashes_to_underscores(a
, a2
);
309 if (strncmp(a2
, first
, strlen(a2
)) == 0) {
310 if (first
[strlen_a
] == '=') {
312 const char *val
= first
+ strlen_a
+ 1;
313 if ((strcmp(val
, "true") == 0) || (strcmp(val
, "1") == 0)) {
317 else if ((strcmp(val
, "false") == 0) || (strcmp(val
, "0") == 0)) {
322 (*oss
) << "Parse error parsing binary flag " << a
323 << ". Expected true or false, but got '" << val
<< "'\n";
328 else if (first
[strlen_a
] == '\0') {
337 bool ceph_argparse_binary_flag(std::vector
<const char*> &args
,
338 std::vector
<const char*>::iterator
&i
, int *ret
,
339 std::ostream
*oss
, ...)
344 r
= va_ceph_argparse_binary_flag(args
, i
, ret
, oss
, ap
);
349 static int va_ceph_argparse_witharg(std::vector
<const char*> &args
,
350 std::vector
<const char*>::iterator
&i
, std::string
*ret
,
351 std::ostream
&oss
, va_list ap
)
353 const char *first
= *i
;
354 char tmp
[strlen(first
)+1];
355 dashes_to_underscores(first
, tmp
);
358 // does this argument match any of the possibilities?
360 const char *a
= va_arg(ap
, char*);
363 int strlen_a
= strlen(a
);
365 dashes_to_underscores(a
, a2
);
366 if (strncmp(a2
, first
, strlen(a2
)) == 0) {
367 if (first
[strlen_a
] == '=') {
368 *ret
= first
+ strlen_a
+ 1;
372 else if (first
[strlen_a
] == '\0') {
373 // find second part (or not)
374 if (i
+1 == args
.end()) {
375 oss
<< "Option " << *i
<< " requires an argument." << std::endl
;
389 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
390 std::vector
<const char*>::iterator
&i
, T
*ret
,
391 std::ostream
&oss
, ...)
395 bool is_option
= false;
396 bool is_numeric
= true;
399 r
= va_ceph_argparse_witharg(args
, i
, &str
, oss
, ap
);
407 ceph_arg_value_type(str
.c_str(), &is_option
, &is_numeric
);
408 if ((is_option
== true) || (is_numeric
== false)) {
410 if (is_option
== true) {
411 oss
<< "Missing option value";
413 oss
<< "The option value '" << str
<< "' is invalid";
419 T myret
= strict_str_convert(str
.c_str(), &err
);
427 template bool ceph_argparse_witharg
<int>(std::vector
<const char*> &args
,
428 std::vector
<const char*>::iterator
&i
, int *ret
,
429 std::ostream
&oss
, ...);
431 template bool ceph_argparse_witharg
<long long>(std::vector
<const char*> &args
,
432 std::vector
<const char*>::iterator
&i
, long long *ret
,
433 std::ostream
&oss
, ...);
435 template bool ceph_argparse_witharg
<float>(std::vector
<const char*> &args
,
436 std::vector
<const char*>::iterator
&i
, float *ret
,
437 std::ostream
&oss
, ...);
439 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
440 std::vector
<const char*>::iterator
&i
, std::string
*ret
,
441 std::ostream
&oss
, ...)
446 r
= va_ceph_argparse_witharg(args
, i
, ret
, oss
, ap
);
451 bool ceph_argparse_witharg(std::vector
<const char*> &args
,
452 std::vector
<const char*>::iterator
&i
, std::string
*ret
, ...)
457 r
= va_ceph_argparse_witharg(args
, i
, ret
, cerr
, ap
);
464 CephInitParameters ceph_argparse_early_args
465 (std::vector
<const char*>& args
, uint32_t module_type
,
466 std::string
*cluster
, std::string
*conf_file_list
)
468 CephInitParameters
iparams(module_type
);
471 vector
<const char *> orig_args
= args
;
473 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
474 if (strcmp(*i
, "--") == 0) {
475 /* Normally we would use ceph_argparse_double_dash. However, in this
476 * function we *don't* want to remove the double dash, because later
477 * argument parses will still need to see it. */
480 else if (ceph_argparse_flag(args
, i
, "--version", "-v", (char*)NULL
)) {
481 cout
<< pretty_version_to_str() << std::endl
;
484 else if (ceph_argparse_witharg(args
, i
, &val
, "--conf", "-c", (char*)NULL
)) {
485 *conf_file_list
= val
;
487 else if (ceph_argparse_witharg(args
, i
, &val
, "--cluster", (char*)NULL
)) {
490 else if ((module_type
!= CEPH_ENTITY_TYPE_CLIENT
) &&
491 (ceph_argparse_witharg(args
, i
, &val
, "-i", (char*)NULL
))) {
492 iparams
.name
.set_id(val
);
494 else if (ceph_argparse_witharg(args
, i
, &val
, "--id", "--user", (char*)NULL
)) {
495 iparams
.name
.set_id(val
);
497 else if (ceph_argparse_witharg(args
, i
, &val
, "--name", "-n", (char*)NULL
)) {
498 if (!iparams
.name
.from_str(val
)) {
499 cerr
<< "error parsing '" << val
<< "': expected string of the form TYPE.ID, "
500 << "valid types are: " << EntityName::get_valid_types_as_str()
505 else if (ceph_argparse_flag(args
, i
, "--show_args", (char*)NULL
)) {
507 for (std::vector
<const char *>::iterator ci
= orig_args
.begin(); ci
!= orig_args
.end(); ++ci
) {
508 if (ci
!= orig_args
.begin())
522 static void generic_usage(bool is_server
)
525 " --conf/-c FILE read configuration from the given configuration file" << std::endl
<<
527 " --id/-i ID set ID portion of my name" :
528 " --id ID set ID portion of my name") << std::endl
<<
529 " --name/-n TYPE.ID set name" << std::endl
<<
530 " --cluster NAME set cluster name (default: ceph)" << std::endl
<<
531 " --setuser USER set uid to user or uid (and gid to user's gid)" << std::endl
<<
532 " --setgroup GROUP set gid to group or gid" << std::endl
<<
533 " --version show version and quit" << std::endl
538 " -d run in foreground, log to stderr" << std::endl
<<
539 " -f run in foreground, log to usual location" << std::endl
<<
541 " --debug_ms N set message debug level (e.g. 1)" << std::endl
;
547 void generic_server_usage()
552 void generic_client_usage()
554 generic_usage(false);