pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cmdline.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <glib.h>
13 
14 #include <crm/crm.h>
17 #include <crm/common/util.h>
18 
19 static gboolean
20 bump_verbosity(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
21  pcmk__common_args_t *common_args = (pcmk__common_args_t *) data;
22  common_args->verbosity++;
23  return TRUE;
24 }
25 
28 {
29  pcmk__common_args_t *args = NULL;
30 
31  args = calloc(1, sizeof(pcmk__common_args_t));
32  if (args == NULL) {
33  crm_exit(crm_errno2exit(-ENOMEM));
34  }
35 
36  args->summary = strdup(summary);
37  if (args->summary == NULL) {
38  crm_exit(crm_errno2exit(-ENOMEM));
39  }
40 
41  return args;
42 }
43 
44 static void
45 free_common_args(gpointer data) {
46  pcmk__common_args_t *common_args = (pcmk__common_args_t *) data;
47 
48  free(common_args->summary);
49  free(common_args->output_ty);
50  free(common_args->output_dest);
51 
52  if (common_args->output_as_descr != NULL) {
53  free(common_args->output_as_descr);
54  }
55 
56  free(common_args);
57 }
58 
59 GOptionContext *
60 pcmk__build_arg_context(pcmk__common_args_t *common_args, const char *fmts,
61  GOptionGroup **output_group, const char *param_string) {
62  char *desc = crm_strdup_printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
63  GOptionContext *context;
64  GOptionGroup *main_group;
65 
66  GOptionEntry main_entries[3] = {
67  { "version", '$', 0, G_OPTION_ARG_NONE, &(common_args->version),
68  "Display software version and exit",
69  NULL },
70  { "verbose", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, bump_verbosity,
71  "Increase debug output (may be specified multiple times)",
72  NULL },
73 
74  { NULL }
75  };
76 
77  main_group = g_option_group_new(NULL, "Application Options:", NULL, common_args, free_common_args);
78  g_option_group_add_entries(main_group, main_entries);
79 
80  context = g_option_context_new(param_string);
81  g_option_context_set_summary(context, common_args->summary);
82  g_option_context_set_description(context, desc);
83  g_option_context_set_main_group(context, main_group);
84 
85  if (fmts != NULL) {
86  GOptionEntry output_entries[3] = {
87  { "output-as", 0, 0, G_OPTION_ARG_STRING, &(common_args->output_ty),
88  NULL,
89  "FORMAT" },
90  { "output-to", 0, 0, G_OPTION_ARG_STRING, &(common_args->output_dest),
91  "Specify file name for output (or \"-\" for stdout)", "DEST" },
92 
93  { NULL }
94  };
95 
96  if (*output_group == NULL) {
97  *output_group = g_option_group_new("output", "Output Options:", "Show output help", NULL, NULL);
98  }
99 
100  common_args->output_as_descr = crm_strdup_printf("Specify output format as one of: %s", fmts);
101  output_entries[0].description = common_args->output_as_descr;
102  g_option_group_add_entries(*output_group, output_entries);
103  g_option_context_add_group(context, *output_group);
104  }
105 
106  free(desc);
107 
108  // main_group is now owned by context, we don't free it here
109  // cppcheck-suppress memleak
110  return context;
111 }
112 
113 void
114 pcmk__free_arg_context(GOptionContext *context) {
115  if (context == NULL) {
116  return;
117  }
118 
119  g_option_context_free(context);
120 }
121 
122 void
123 pcmk__add_main_args(GOptionContext *context, GOptionEntry entries[])
124 {
125  GOptionGroup *main_group = g_option_context_get_main_group(context);
126 
127  g_option_group_add_entries(main_group, entries);
128 }
129 
130 void
131 pcmk__add_arg_group(GOptionContext *context, const char *name,
132  const char *header, const char *desc,
133  GOptionEntry entries[])
134 {
135  GOptionGroup *group = NULL;
136 
137  group = g_option_group_new(name, header, desc, NULL, NULL);
138  g_option_group_add_entries(group, entries);
139  g_option_context_add_group(context, group);
140  // group is now owned by context, we don't free it here
141  // cppcheck-suppress memleak
142 }
143 
144 gchar **
145 pcmk__cmdline_preproc(char **argv, const char *special) {
146  GPtrArray *arr = NULL;
147  bool saw_dash_dash = false;
148 
149  if (argv == NULL) {
150  return NULL;
151  }
152 
153  if (g_get_prgname() == NULL && argv && *argv) {
154  gchar *basename = g_path_get_basename(*argv);
155 
156  g_set_prgname(basename);
157  g_free(basename);
158  }
159 
160  arr = g_ptr_array_new();
161 
162  for (int i = 0; argv[i] != NULL; i++) {
163  /* If this is the first time we saw "--" in the command line, set
164  * a flag so we know to just copy everything after it over. We also
165  * want to copy the "--" over so whatever actually parses the command
166  * line when we're done knows where arguments end.
167  */
168  if (saw_dash_dash == false && strcmp(argv[i], "--") == 0) {
169  saw_dash_dash = true;
170  }
171 
172  if (saw_dash_dash == true) {
173  g_ptr_array_add(arr, g_strdup(argv[i]));
174  continue;
175  }
176 
177  /* This is just a dash by itself. That could indicate stdin/stdout, or
178  * it could be user error. Copy it over and let glib figure it out.
179  */
180  if (pcmk__str_eq(argv[i], "-", pcmk__str_casei)) {
181  g_ptr_array_add(arr, g_strdup(argv[i]));
182  continue;
183  }
184 
185  /* This is a short argument, or perhaps several. Iterate over it
186  * and explode them out into individual arguments.
187  */
188  if (g_str_has_prefix(argv[i], "-") && !g_str_has_prefix(argv[i], "--")) {
189  /* Skip over leading dash */
190  char *ch = argv[i]+1;
191 
192  while (*ch != '\0') {
193  /* This is a special short argument that takes an option. getopt
194  * allows values to be interspersed with a list of arguments, but
195  * glib does not. Grab both the argument and its value and
196  * separate them into a new argument.
197  */
198  if (special != NULL && strchr(special, *ch) != NULL) {
199  /* The argument does not occur at the end of this string of
200  * arguments. Take everything through the end as its value.
201  */
202  if (*(ch+1) != '\0') {
203  g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
204  g_ptr_array_add(arr, g_strdup(ch+1));
205  break;
206 
207  /* The argument occurs at the end of this string. Hopefully
208  * whatever comes next in argv is its value. It may not be,
209  * but that is not for us to decide.
210  */
211  } else {
212  g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
213  ch++;
214  }
215 
216  /* This is a regular short argument. Just copy it over. */
217  } else {
218  g_ptr_array_add(arr, g_strdup_printf("-%c", *ch));
219  ch++;
220  }
221  }
222 
223  /* This is a long argument, or an option, or something else.
224  * Copy it over - everything else is copied, so this keeps it easy for
225  * the caller to know what to do with the memory when it's done.
226  */
227  } else {
228  g_ptr_array_add(arr, g_strdup(argv[i]));
229  }
230  }
231 
232  g_ptr_array_add(arr, NULL);
233 
234  return (char **) g_ptr_array_free(arr, FALSE);
235 }
236 
237 G_GNUC_PRINTF(3, 4)
238 gboolean
239 pcmk__force_args(GOptionContext *context, GError **error, const char *format, ...) {
240  int len = 0;
241  char *buf = NULL;
242  gchar **extra_args = NULL;
243  va_list ap;
244  gboolean retval = TRUE;
245 
246  va_start(ap, format);
247  len = vasprintf(&buf, format, ap);
248  CRM_ASSERT(len > 0);
249  va_end(ap);
250 
251  if (!g_shell_parse_argv(buf, NULL, &extra_args, error)) {
252  g_strfreev(extra_args);
253  free(buf);
254  return FALSE;
255  }
256 
257  retval = g_option_context_parse_strv(context, &extra_args, error);
258 
259  g_strfreev(extra_args);
260  free(buf);
261  return retval;
262 }
A dumping ground.
crm_exit_t crm_errno2exit(int rc)
Definition: results.c:577
pcmk__common_args_t * pcmk__new_common_args(const char *summary)
Definition: cmdline.c:27
gchar ** pcmk__cmdline_preproc(char **argv, const char *special)
Definition: cmdline.c:145
char data[0]
Definition: cpg.c:55
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:759
Utility functions.
gboolean summary(GList *resources)
GOptionContext * pcmk__build_arg_context(pcmk__common_args_t *common_args, const char *fmts, GOptionGroup **output_group, const char *param_string)
Definition: cmdline.c:60
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
void pcmk__free_arg_context(GOptionContext *context)
Definition: cmdline.c:114
gboolean pcmk__force_args(GOptionContext *context, GError **error, const char *format,...)
Definition: cmdline.c:239
void pcmk__add_arg_group(GOptionContext *context, const char *name, const char *header, const char *desc, GOptionEntry entries[])
Definition: cmdline.c:131
#define CRM_ASSERT(expr)
Definition: results.h:42
unsigned int verbosity
void pcmk__add_main_args(GOptionContext *context, GOptionEntry entries[])
Definition: cmdline.c:123
#define PACKAGE_BUGREPORT
Definition: config.h:484
char * name
Definition: pcmk_fence.c:31