vsh: Remove unused infrastructure for command completion
[libvirt.git] / tools / vsh.c
blobf4c127222d2100ade5793d694761cfed92054f49
1 /*
2 * vsh.c: common data to be used by clients to exercise the libvirt API
4 * Copyright (C) 2005-2019 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include "vsh.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <signal.h>
31 #if WITH_READLINE
32 /* In order to have proper rl_message declaration with older
33 * versions of readline, we have to declare this. See 9ea3424a178
34 * for more info. */
35 # define HAVE_STDARG_H
36 # include <readline/readline.h>
37 # include <readline/history.h>
38 #endif
40 #include "internal.h"
41 #include "virbuffer.h"
42 #include "viralloc.h"
43 #include "virfile.h"
44 #include "virthread.h"
45 #include "vircommand.h"
46 #include "virstring.h"
47 #include "virutil.h"
49 #ifdef WITH_READLINE
50 /* For autocompletion */
51 vshControl *autoCompleteOpaque;
52 #endif
54 /* NOTE: It would be much nicer to have these two as part of vshControl
55 * structure, unfortunately readline doesn't support passing opaque data
56 * and only relies on static data accessible from the user-side callback
58 const vshCmdGrp *cmdGroups;
61 double
62 vshPrettyCapacity(unsigned long long val, const char **unit)
64 double limit = 1024;
66 if (val < limit) {
67 *unit = "B";
68 return val;
70 limit *= 1024;
71 if (val < limit) {
72 *unit = "KiB";
73 return val / (limit / 1024);
75 limit *= 1024;
76 if (val < limit) {
77 *unit = "MiB";
78 return val / (limit / 1024);
80 limit *= 1024;
81 if (val < limit) {
82 *unit = "GiB";
83 return val / (limit / 1024);
85 limit *= 1024;
86 if (val < limit) {
87 *unit = "TiB";
88 return val / (limit / 1024);
90 limit *= 1024;
91 if (val < limit) {
92 *unit = "PiB";
93 return val / (limit / 1024);
95 limit *= 1024;
96 *unit = "EiB";
97 return val / (limit / 1024);
102 vshNameSorter(const void *a, const void *b)
104 const char **sa = (const char**)a;
105 const char **sb = (const char**)b;
107 return vshStrcasecmp(*sa, *sb);
112 * Convert the strings separated by ',' into array. The returned
113 * array is a NULL terminated string list. The caller has to free
114 * the array using g_strfreev or a similar method.
116 * Returns the length of the filled array on success, or -1
117 * on error.
120 vshStringToArray(const char *str,
121 char ***array)
123 g_auto(GStrv) tmp = NULL;
124 GStrv n;
125 size_t ntoks = 0;
126 bool concat = false;
128 tmp = g_strsplit(str, ",", 0);
130 *array = g_new0(char *, g_strv_length(tmp) + 1);
131 (*array)[ntoks++] = g_strdup(tmp[0]);
133 /* undo splitting of comma escape (',,') by concatenating back on empty strings */
134 for (n = tmp + 1; n[0]; n++) {
135 if (concat) {
136 g_autofree char *old = (*array)[ntoks - 1];
138 (*array)[ntoks - 1] = g_strconcat(old, ",", n[0], NULL);
139 concat = false;
140 continue;
143 if (strlen(n[0]) == 0) {
144 concat = true;
145 } else {
146 (*array)[ntoks++] = g_strdup(n[0]);
150 /* corner case of ending with a single comma */
151 if (concat)
152 (*array)[ntoks++] = g_strdup("");
154 return ntoks;
157 virErrorPtr last_error;
160 * Quieten libvirt until we're done with the command.
162 void
163 vshErrorHandler(void *opaque G_GNUC_UNUSED,
164 virErrorPtr error G_GNUC_UNUSED)
166 virFreeError(last_error);
167 last_error = virSaveLastError();
170 /* Store a libvirt error that is from a helper API that doesn't raise errors
171 * so it doesn't get overwritten */
172 void
173 vshSaveLibvirtError(void)
175 virFreeError(last_error);
176 last_error = virSaveLastError();
180 /* Store libvirt error from helper API but don't overwrite existing errors */
181 void
182 vshSaveLibvirtHelperError(void)
184 if (last_error)
185 return;
187 if (virGetLastErrorCode() == VIR_ERR_OK)
188 return;
190 vshSaveLibvirtError();
195 * Reset libvirt error on graceful fallback paths
197 void
198 vshResetLibvirtError(void)
200 g_clear_pointer(&last_error, virFreeError);
201 virResetLastError();
205 * Report an error when a command finishes. This is better than before
206 * (when correct operation would report errors), but it has some
207 * problems: we lose the smarter formatting of virDefaultErrorFunc(),
208 * and it can become harder to debug problems, if errors get reported
209 * twice during one command. This case shouldn't really happen anyway,
210 * and it's IMHO a bug that libvirt does that sometimes.
212 void
213 vshReportError(vshControl *ctl)
215 if (last_error == NULL) {
216 /* Calling directly into libvirt util functions won't trigger the
217 * error callback (which sets last_error), so check it ourselves.
219 * If the returned error has CODE_OK, this most likely means that
220 * no error was ever raised, so just ignore */
221 last_error = virSaveLastError();
222 if (!last_error || last_error->code == VIR_ERR_OK)
223 goto out;
226 if (last_error->code == VIR_ERR_OK) {
227 vshError(ctl, "%s", _("unknown error"));
228 goto out;
231 vshError(ctl, "%s", last_error->message);
233 out:
234 vshResetLibvirtError();
238 * Detection of disconnections and automatic reconnection support
240 static int disconnected; /* we may have been disconnected */
242 /* Check if the internal command definitions are correct.
243 * None of the errors are to be marked as translatable. */
244 static int
245 vshCmddefCheckInternals(vshControl *ctl,
246 const vshCmdDef *cmd,
247 bool missingCompleters)
249 size_t i;
250 bool seenOptionalOption = false;
251 const char *seenOptionalPositionalOption = NULL;
252 g_auto(virBuffer) complbuf = VIR_BUFFER_INITIALIZER;
254 /* in order to perform the validation resolve the alias first */
255 if (cmd->alias) {
256 const vshCmdDef *alias;
258 if (!(alias = vshCmddefSearch(cmd->alias))) {
259 vshError(ctl, "command alias '%s' is pointing to a non-existent command '%s'",
260 cmd->name, cmd->alias);
261 return -1;
264 if (alias->alias) {
265 vshError(ctl, "command alias '%s' is pointing to another command alias '%s'",
266 cmd->name, cmd->alias);
267 return -1;
270 if (cmd->handler) {
271 vshError(ctl, "command '%s' has handler set", cmd->name);
272 return -1;
275 if (cmd->opts) {
276 vshError(ctl, "command '%s' has options set", cmd->name);
277 return -1;
280 if (cmd->info) {
281 vshError(ctl, "command '%s' has info set", cmd->name);
282 return -1;
285 if (cmd->flags != 0) {
286 vshError(ctl, "command '%s' has multiple flags set", cmd->name);
287 return -1;
290 /* we don't need to continue as the real command will be checked separately */
291 return 0;
294 /* Each command has to provide a non-empty help string. */
295 if (!cmd->info || !cmd->info->help || !*cmd->info->help) {
296 vshError(ctl, "command '%s' lacks help", cmd->name);
297 return -1;
300 if (!cmd->opts)
301 return 0;
303 for (i = 0; cmd->opts[i].name; i++) {
304 const vshCmdOptDef *opt = &cmd->opts[i];
306 if (i > 63) {
307 vshError(ctl, "command '%s' has too many options", cmd->name);
308 return -1; /* too many options */
311 if (missingCompleters && !opt->completer) {
312 switch (opt->type) {
313 case VSH_OT_STRING:
314 case VSH_OT_ARGV:
315 virBufferStrcat(&complbuf, opt->name, ", ", NULL);
316 break;
318 case VSH_OT_BOOL:
319 /* only name is completed */
320 case VSH_OT_INT:
321 /* no point in completing numbers */
322 case VSH_OT_ALIAS:
323 /* alias is handled in the referenced command */
324 case VSH_OT_NONE:
325 break;
329 /* allow at most one optional positional option */
330 if (opt->positional && !opt->required) {
331 if (seenOptionalPositionalOption) {
332 vshError(ctl, "multiple optional positional arguments (%s, %s) of command '%s' are not allowed",
333 seenOptionalPositionalOption, opt->name, cmd->name);
334 return -1;
337 seenOptionalPositionalOption = opt->name;
340 /* all optional positional arguments must be defined after the required ones */
341 if (seenOptionalPositionalOption && opt->positional && opt->required) {
342 vshError(ctl, "required positional argument '%s' declared after an optional positional argument '%s' of command '%s'",
343 opt->name, seenOptionalPositionalOption, cmd->name);
344 return -1;
347 /* Mandate no completer flags if no completer is specified */
348 if (opt->completer_flags != 0 && !opt->completer) {
349 vshError(ctl, "completer_flags of argument '%s' of command '%s' must be 0 if no completer is used",
350 opt->name, cmd->name);
351 return -1;
354 if (opt->unwanted_positional && opt->positional) {
355 vshError(ctl, "unwanted_positional flag of argument '%s' of command '%s' must not be used together with positional",
356 opt->name, cmd->name);
357 return -1;
360 switch (opt->type) {
361 case VSH_OT_NONE:
362 vshError(ctl, "invalid type 'NONE' of option '%s' of command '%s'",
363 opt->name, cmd->name);
364 return -1;
366 case VSH_OT_BOOL:
367 if (opt->completer) {
368 vshError(ctl, "bool parameter '%s' of command '%s' has completer set",
369 opt->name, cmd->name);
370 return -1;
373 if (opt->positional || opt->unwanted_positional) {
374 vshError(ctl, "boolean parameter '%s' of command '%s' must not be positional",
375 opt->name, cmd->name);
376 return -1;
379 if (opt->required) {
380 vshError(ctl, "parameter '%s' of command '%s' misused 'required' flag",
381 opt->name, cmd->name);
382 return -1; /* bool can't be mandatory */
385 break;
387 case VSH_OT_ALIAS: {
388 size_t j;
389 g_autofree char *name = NULL;
390 char *p;
392 if (opt->required ||
393 opt->positional ||
394 opt->unwanted_positional ||
395 opt->completer ||
396 !opt->help) {
397 vshError(ctl, "parameter '%s' of command '%s' has incorrect alias option",
398 opt->name, cmd->name);
399 return -1;
401 if ((p = strchr(opt->help, '=')))
402 name = g_strndup(opt->help, p - opt->help);
403 else
404 name = g_strdup(opt->help);
405 for (j = i + 1; cmd->opts[j].name; j++) {
406 if (STREQ(name, cmd->opts[j].name) &&
407 cmd->opts[j].type != VSH_OT_ALIAS)
408 break;
410 if (p) {
411 /* If alias comes with value, replacement must not be bool */
412 if (cmd->opts[j].type == VSH_OT_BOOL) {
413 vshError(ctl, "alias '%s' of command '%s' has mismatched alias type",
414 opt->name, cmd->name);
415 return -1;
418 if (!cmd->opts[j].name) {
419 vshError(ctl, "alias '%s' of command '%s' has missing alias option",
420 opt->name, cmd->name);
421 return -1;
424 break;
426 case VSH_OT_ARGV:
427 if (cmd->opts[i + 1].name) {
428 vshError(ctl, "parameter '%s' of command '%s' must be listed last",
429 opt->name, cmd->name);
430 return -1;
432 break;
434 case VSH_OT_INT:
435 case VSH_OT_STRING:
436 if (opt->positional && seenOptionalOption) {
437 vshError(ctl, "parameter '%s' of command '%s' must be listed before optional parameters",
438 opt->name, cmd->name);
439 return -1;
442 seenOptionalOption = !opt->required;
443 break;
447 virBufferTrim(&complbuf, ", ");
449 if (missingCompleters && virBufferUse(&complbuf) > 0)
450 vshPrintExtra(ctl, "%s: %s\n", cmd->name, virBufferCurrentContent(&complbuf));
452 return 0;
455 /* Parse the options associated with @cmd, i.e. test whether options are
456 * required or need an argument and fill the appropriate caller-provided bitmaps
458 static void
459 vshCmddefOptParse(const vshCmdDef *cmd,
460 uint64_t *opts_need_arg,
461 uint64_t *opts_required)
463 size_t i;
465 *opts_need_arg = 0;
466 *opts_required = 0;
468 if (!cmd->opts)
469 return;
471 for (i = 0; cmd->opts[i].name; i++) {
472 const vshCmdOptDef *opt = &cmd->opts[i];
474 if (opt->type == VSH_OT_BOOL)
475 continue;
477 if (opt->type == VSH_OT_ALIAS)
478 continue; /* skip the alias option */
480 if (opt->positional || opt->unwanted_positional)
481 *opts_need_arg |= 1ULL << i;
483 if (opt->required)
484 *opts_required |= 1ULL << i;
488 static vshCmdOptDef helpopt = {
489 .name = "help",
490 .type = VSH_OT_BOOL,
491 .help = N_("print help for this function")
494 static const vshCmdOptDef *
495 vshCmddefGetOption(vshControl *ctl,
496 const vshCmdDef *cmd,
497 const char *name,
498 uint64_t *opts_seen,
499 size_t *opt_index,
500 char **optstr,
501 bool report)
503 size_t i;
504 g_autofree char *alias = NULL;
506 if (STREQ(name, helpopt.name))
507 return &helpopt;
509 for (i = 0; cmd->opts && cmd->opts[i].name; i++) {
510 const vshCmdOptDef *opt = &cmd->opts[i];
512 if (STRNEQ(opt->name, name))
513 continue;
515 if (opt->type == VSH_OT_ALIAS) {
516 char *value;
518 /* Two types of replacements:
519 opt->help = "string": straight replacement of name
520 opt->help = "string=value": treat boolean flag as
521 alias of option and its default value */
522 alias = g_strdup(opt->help);
523 name = alias;
524 if ((value = strchr(name, '='))) {
525 *value = '\0';
526 if (*optstr) {
527 if (report)
528 vshError(ctl, _("invalid '=' after option --%1$s"),
529 opt->name);
530 return NULL;
532 *optstr = g_strdup(value + 1);
534 continue;
537 if ((*opts_seen & (1ULL << i)) && opt->type != VSH_OT_ARGV) {
538 if (report)
539 vshError(ctl, _("option --%1$s already seen"), name);
540 return NULL;
543 *opts_seen |= 1ULL << i;
544 *opt_index = i;
545 return opt;
548 /* The 'help' command ignores extra options */
549 if (STRNEQ(cmd->name, "help") && report) {
550 vshError(ctl, _("command '%1$s' doesn't support option --%2$s"),
551 cmd->name, name);
553 return NULL;
556 static const vshCmdOptDef *
557 vshCmddefGetData(const vshCmdDef *cmd, uint64_t *opts_need_arg,
558 uint64_t *opts_seen)
560 size_t i;
561 const vshCmdOptDef *opt;
563 if (!*opts_need_arg)
564 return NULL;
566 /* Grab least-significant set bit */
567 i = __builtin_ffsl(*opts_need_arg) - 1;
568 opt = &cmd->opts[i];
569 if (opt->type != VSH_OT_ARGV)
570 *opts_need_arg &= ~(1ULL << i);
571 *opts_seen |= 1ULL << i;
572 return opt;
576 * Checks for required options
578 static int
579 vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, uint64_t opts_required,
580 uint64_t opts_seen)
582 const vshCmdDef *def = cmd->def;
583 size_t i;
585 opts_required &= ~opts_seen;
586 if (!opts_required)
587 return 0;
589 for (i = 0; def->opts[i].name; i++) {
590 if (opts_required & (1ULL << i)) {
591 const vshCmdOptDef *opt = &def->opts[i];
593 vshError(ctl,
594 opt->positional ?
595 _("command '%1$s' requires <%2$s> option") :
596 _("command '%1$s' requires --%2$s option"),
597 def->name, opt->name);
600 return -1;
603 const vshCmdDef *
604 vshCmddefSearch(const char *cmdname)
606 const vshCmdGrp *g;
607 const vshCmdDef *c;
609 for (g = cmdGroups; g->name; g++) {
610 for (c = g->commands; c->name; c++) {
611 if (STREQ(c->name, cmdname))
612 return c;
616 return NULL;
619 const vshCmdGrp *
620 vshCmdGrpSearch(const char *grpname)
622 const vshCmdGrp *g;
624 for (g = cmdGroups; g->name; g++) {
625 if (STREQ(g->name, grpname) || STREQ(g->keyword, grpname))
626 return g;
629 return NULL;
632 bool
633 vshCmdGrpHelp(vshControl *ctl, const vshCmdGrp *grp)
635 const vshCmdDef *cmd = NULL;
637 vshPrint(ctl, _(" %1$s (help keyword '%2$s'):\n"), grp->name,
638 grp->keyword);
640 for (cmd = grp->commands; cmd->name; cmd++) {
641 if (cmd->alias ||
642 cmd->flags & VSH_CMD_FLAG_HIDDEN)
643 continue;
644 vshPrint(ctl, " %-30s %s\n", cmd->name, _(cmd->info->help));
647 return true;
650 static bool
651 vshCmddefHelp(const vshCmdDef *def)
653 fputs(_(" NAME\n"), stdout);
654 fprintf(stdout, " %s - %s\n", def->name, _(def->info->help));
656 fputs(_("\n SYNOPSIS\n"), stdout);
657 fprintf(stdout, " %s", def->name);
658 if (def->opts) {
659 const vshCmdOptDef *opt;
660 for (opt = def->opts; opt->name; opt++) {
662 switch (opt->type) {
663 case VSH_OT_BOOL:
664 fprintf(stdout, " [--%s]", opt->name);
665 break;
667 case VSH_OT_STRING:
668 case VSH_OT_INT:
669 if (opt->required) {
670 fprintf(stdout, " ");
671 } else {
672 fprintf(stdout, " [");
675 if (opt->positional) {
676 fprintf(stdout, "<%s>", opt->name);
677 } else {
678 if (opt->type == VSH_OT_INT) {
679 fprintf(stdout, _("--%1$s <number>"), opt->name);
680 } else {
681 fprintf(stdout, _("--%1$s <string>"), opt->name);
685 if (!opt->required)
686 fprintf(stdout, "]");
687 break;
689 case VSH_OT_ARGV:
690 if (opt->positional) {
691 if (opt->required) {
692 fprintf(stdout, " <%s>...", opt->name);
693 } else {
694 fprintf(stdout, " [<%s>]...", opt->name);
696 } else {
697 if (opt->required) {
698 fprintf(stdout, _(" --%1$s <string>..."), opt->name);
699 } else {
700 fprintf(stdout, _(" [--%1$s <string>]..."), opt->name);
703 break;
705 case VSH_OT_ALIAS:
706 case VSH_OT_NONE:
707 /* aliases are intentionally undocumented */
708 continue;
712 fputc('\n', stdout);
714 if (def->info->desc && *def->info->desc) {
715 /* Print the description only if it's not empty. */
716 fputs(_("\n DESCRIPTION\n"), stdout);
717 fprintf(stdout, " %s\n", _(def->info->desc));
720 if (def->opts && def->opts->name) {
721 const vshCmdOptDef *opt;
722 fputs(_("\n OPTIONS\n"), stdout);
723 for (opt = def->opts; opt->name; opt++) {
724 g_autofree char *optstr = NULL;
726 switch (opt->type) {
727 case VSH_OT_BOOL:
728 optstr = g_strdup_printf("--%s", opt->name);
729 break;
731 case VSH_OT_INT:
732 if (opt->positional) {
733 optstr = g_strdup_printf(_("[--%1$s] <number>"), opt->name);
734 } else {
735 optstr = g_strdup_printf(_("--%1$s <number>"), opt->name);
737 break;
739 case VSH_OT_STRING:
740 if (opt->positional) {
741 optstr = g_strdup_printf(_("[--%1$s] <string>"), opt->name);
742 } else {
743 optstr = g_strdup_printf(_("--%1$s <string>"), opt->name);
745 break;
747 case VSH_OT_ARGV:
748 if (opt->positional) {
749 optstr = g_strdup_printf(_("[--%1$s] <string>..."), opt->name);
750 } else {
751 optstr = g_strdup_printf(_("--%1$s <string>..."), opt->name);
753 break;
755 case VSH_OT_ALIAS:
756 case VSH_OT_NONE:
757 continue;
760 fprintf(stdout, " %-15s %s\n", optstr, _(opt->help));
764 return true;
767 /* ---------------
768 * Utils for work with runtime commands data
769 * ---------------
771 static void
772 vshCommandOptFree(vshCmdOpt * arg)
774 vshCmdOpt *a = arg;
776 while (a) {
777 vshCmdOpt *tmp = a;
779 a = a->next;
781 g_free(tmp->data);
782 /* 'argv' doesn't own the strings themselves */
783 g_free(tmp->argv);
784 g_free(tmp->argvstr);
785 g_free(tmp);
789 static void
790 vshCommandFree(vshCmd *cmd)
792 vshCmd *c = cmd;
794 while (c) {
795 vshCmd *tmp = c;
797 c = c->next;
799 vshCommandOptFree(tmp->opts);
800 g_free(tmp);
804 G_DEFINE_AUTOPTR_CLEANUP_FUNC(vshCmd, vshCommandFree);
807 * vshCommandOpt:
808 * @cmd: parsed command line to search
809 * @name: option name to search for
810 * @opt: result of the search
811 * @needData: true if option must be non-boolean
813 * Look up an option passed to CMD by NAME. Returns 1 with *OPT set
814 * to the option if found, 0 with *OPT set to NULL if the name is
815 * valid and the option is not required, -1 with *OPT set to NULL if
816 * the option is required but not present, and assert if NAME is not
817 * valid (which indicates a programming error) unless cmd->skipChecks
818 * is set. No error messages are issued if a value is returned.
820 static int
821 vshCommandOpt(const vshCmd *cmd, const char *name, vshCmdOpt **opt,
822 bool needData)
824 vshCmdOpt *candidate = cmd->opts;
825 const vshCmdOptDef *valid = cmd->def->opts;
826 int ret = 0;
828 /* See if option is valid and/or required. */
829 *opt = NULL;
831 while (valid && valid->name) {
832 if (STREQ(name, valid->name))
833 break;
834 valid++;
837 if (!cmd->skipChecks)
838 assert(valid && (!needData || valid->type != VSH_OT_BOOL));
840 if (valid && valid->required)
841 ret = -1;
843 /* See if option is present on command line. */
844 while (candidate) {
845 if (STREQ(candidate->def->name, name)) {
846 *opt = candidate;
847 ret = 1;
848 break;
850 candidate = candidate->next;
852 return ret;
856 * vshCommandOptInt:
857 * @ctl virtshell control structure
858 * @cmd command reference
859 * @name option name
860 * @value result
862 * Convert option to int.
863 * On error, a message is displayed.
865 * Return value:
866 * >0 if option found and valid (@value updated)
867 * 0 if option not found and not required (@value untouched)
868 * <0 in all other cases (@value untouched)
871 vshCommandOptInt(vshControl *ctl, const vshCmd *cmd,
872 const char *name, int *value)
874 vshCmdOpt *arg;
875 int ret;
877 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
878 return ret;
880 if ((ret = virStrToLong_i(arg->data, NULL, 10, value)) < 0)
881 vshError(ctl,
882 _("Numeric value '%1$s' for <%2$s> option is malformed or out of range"),
883 arg->data, name);
884 else
885 ret = 1;
887 return ret;
890 static int
891 vshCommandOptUIntInternal(vshControl *ctl,
892 const vshCmd *cmd,
893 const char *name,
894 unsigned int *value,
895 bool wrap)
897 vshCmdOpt *arg;
898 int ret;
900 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
901 return ret;
903 if (wrap)
904 ret = virStrToLong_ui(arg->data, NULL, 10, value);
905 else
906 ret = virStrToLong_uip(arg->data, NULL, 10, value);
907 if (ret < 0)
908 vshError(ctl,
909 _("Numeric value '%1$s' for <%2$s> option is malformed or out of range"),
910 arg->data, name);
911 else
912 ret = 1;
914 return ret;
918 * vshCommandOptUInt:
919 * @ctl virtshell control structure
920 * @cmd command reference
921 * @name option name
922 * @value result
924 * Convert option to unsigned int, reject negative numbers
925 * See vshCommandOptInt()
928 vshCommandOptUInt(vshControl *ctl, const vshCmd *cmd,
929 const char *name, unsigned int *value)
931 return vshCommandOptUIntInternal(ctl, cmd, name, value, false);
935 * vshCommandOptUIntWrap:
936 * @ctl virtshell control structure
937 * @cmd command reference
938 * @name option name
939 * @value result
941 * Convert option to unsigned int, wraps negative numbers to positive
942 * See vshCommandOptInt()
945 vshCommandOptUIntWrap(vshControl *ctl, const vshCmd *cmd,
946 const char *name, unsigned int *value)
948 return vshCommandOptUIntInternal(ctl, cmd, name, value, true);
951 static int
952 vshCommandOptULInternal(vshControl *ctl,
953 const vshCmd *cmd,
954 const char *name,
955 unsigned long *value,
956 bool wrap)
958 vshCmdOpt *arg;
959 int ret;
961 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
962 return ret;
964 if (wrap)
965 ret = virStrToLong_ul(arg->data, NULL, 10, value);
966 else
967 ret = virStrToLong_ulp(arg->data, NULL, 10, value);
968 if (ret < 0)
969 vshError(ctl,
970 _("Numeric value '%1$s' for <%2$s> option is malformed or out of range"),
971 arg->data, name);
972 else
973 ret = 1;
975 return ret;
979 * vshCommandOptUL:
980 * @ctl virtshell control structure
981 * @cmd command reference
982 * @name option name
983 * @value result
985 * Convert option to unsigned long
986 * See vshCommandOptInt()
989 vshCommandOptUL(vshControl *ctl, const vshCmd *cmd,
990 const char *name, unsigned long *value)
992 return vshCommandOptULInternal(ctl, cmd, name, value, false);
996 * vshCommandOptULWrap:
997 * @ctl virtshell control structure
998 * @cmd command reference
999 * @name option name
1000 * @value result
1002 * Convert option to unsigned long, wraps negative numbers to positive
1003 * See vshCommandOptInt()
1006 vshCommandOptULWrap(vshControl *ctl, const vshCmd *cmd,
1007 const char *name, unsigned long *value)
1009 return vshCommandOptULInternal(ctl, cmd, name, value, true);
1013 * vshCommandOptStringQuiet:
1014 * @ctl virtshell control structure
1015 * @cmd command reference
1016 * @name option name
1017 * @value result
1019 * Returns option as STRING. On error -1 is returned but no error is set.
1020 * Return value:
1021 * >0 if option found and valid (@value updated)
1022 * 0 if option not found and not required (@value untouched)
1023 * <0 in all other cases (@value untouched)
1026 vshCommandOptStringQuiet(vshControl *ctl G_GNUC_UNUSED, const vshCmd *cmd,
1027 const char *name, const char **value)
1029 vshCmdOpt *arg;
1030 int ret;
1032 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
1033 return ret;
1035 if (!arg->def->allowEmpty && *arg->data == '\0')
1036 return -1;
1037 *value = arg->data;
1038 return 1;
1042 * vshCommandOptString:
1043 * @ctl virtshell control structure
1044 * @cmd command structure
1045 * @name option name
1046 * @value result (updated to NULL or the option argument)
1048 * Gets a option argument as string.
1050 * Returns 0 on success or when the option is not present and not
1051 * required, *value is set to the option argument. On error -1 is
1052 * returned and error message printed.
1055 vshCommandOptString(vshControl *ctl,
1056 const vshCmd *cmd,
1057 const char *name,
1058 const char **value)
1060 vshCmdOpt *arg;
1061 int ret;
1062 const char *error = NULL;
1064 /* clear out the value */
1065 *value = NULL;
1067 ret = vshCommandOpt(cmd, name, &arg, true);
1068 /* option is not required and not present */
1069 if (ret == 0)
1070 return 0;
1071 /* this should not be propagated here, just to be sure */
1072 if (ret == -1)
1073 error = N_("Mandatory option not present");
1074 else if (arg && *arg->data == '\0' && !arg->def->allowEmpty)
1075 error = N_("Option argument is empty");
1077 if (error) {
1078 if (!cmd->skipChecks)
1079 vshError(ctl, _("Failed to get option '%1$s': %2$s"), name, _(error));
1080 return -1;
1083 *value = arg->data;
1084 return 0;
1088 * vshCommandOptLongLong:
1089 * @ctl virtshell control structure
1090 * @cmd command reference
1091 * @name option name
1092 * @value result
1094 * Returns option as long long
1095 * See vshCommandOptInt()
1098 vshCommandOptLongLong(vshControl *ctl, const vshCmd *cmd,
1099 const char *name, long long *value)
1101 vshCmdOpt *arg;
1102 int ret;
1104 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
1105 return ret;
1107 if ((ret = virStrToLong_ll(arg->data, NULL, 10, value)) < 0)
1108 vshError(ctl,
1109 _("Numeric value '%1$s' for <%2$s> option is malformed or out of range"),
1110 arg->data, name);
1111 else
1112 ret = 1;
1114 return ret;
1117 static int
1118 vshCommandOptULongLongInternal(vshControl *ctl,
1119 const vshCmd *cmd,
1120 const char *name,
1121 unsigned long long *value,
1122 bool wrap)
1124 vshCmdOpt *arg;
1125 int ret;
1127 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
1128 return ret;
1130 if (wrap)
1131 ret = virStrToLong_ull(arg->data, NULL, 10, value);
1132 else
1133 ret = virStrToLong_ullp(arg->data, NULL, 10, value);
1134 if (ret < 0)
1135 vshError(ctl,
1136 _("Numeric value '%1$s' for <%2$s> option is malformed or out of range"),
1137 arg->data, name);
1138 else
1139 ret = 1;
1141 return ret;
1145 * vshCommandOptULongLong:
1146 * @ctl virtshell control structure
1147 * @cmd command reference
1148 * @name option name
1149 * @value result
1151 * Returns option as long long, rejects negative numbers
1152 * See vshCommandOptInt()
1155 vshCommandOptULongLong(vshControl *ctl, const vshCmd *cmd,
1156 const char *name, unsigned long long *value)
1158 return vshCommandOptULongLongInternal(ctl, cmd, name, value, false);
1162 * vshCommandOptULongLongWrap:
1163 * @ctl virtshell control structure
1164 * @cmd command reference
1165 * @name option name
1166 * @value result
1168 * Returns option as long long, wraps negative numbers to positive
1169 * See vshCommandOptInt()
1172 vshCommandOptULongLongWrap(vshControl *ctl, const vshCmd *cmd,
1173 const char *name, unsigned long long *value)
1175 return vshCommandOptULongLongInternal(ctl, cmd, name, value, true);
1179 * vshCommandOptScaledInt:
1180 * @ctl virtshell control structure
1181 * @cmd command reference
1182 * @name option name
1183 * @value result
1184 * @scale default of 1 or 1024, if no suffix is present
1185 * @max maximum value permitted
1187 * Returns option as long long, scaled according to suffix
1188 * See vshCommandOptInt()
1191 vshCommandOptScaledInt(vshControl *ctl, const vshCmd *cmd,
1192 const char *name, unsigned long long *value,
1193 int scale, unsigned long long max)
1195 vshCmdOpt *arg;
1196 char *end;
1197 int ret;
1199 if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
1200 return ret;
1202 if (virStrToLong_ullp(arg->data, &end, 10, value) < 0 ||
1203 virScaleInteger(value, end, scale, max) < 0) {
1204 vshError(ctl,
1205 _("Scaled numeric value '%1$s' for <%2$s> option is malformed or out of range"),
1206 arg->data, name);
1207 return -1;
1210 return 1;
1215 * vshCommandOptBool:
1216 * @cmd command reference
1217 * @name option name
1219 * Returns true/false if the option exists. Note that this does NOT
1220 * validate whether the option is actually boolean, or even whether
1221 * name is legal; so that this can be used to probe whether a data
1222 * option is present without actually using that data.
1224 bool
1225 vshCommandOptBool(const vshCmd *cmd, const char *name)
1227 vshCmdOpt *dummy;
1229 return vshCommandOpt(cmd, name, &dummy, false) == 1;
1233 static vshCmdOpt *
1234 vshCommandOptArgvInternal(const vshCmd *cmd,
1235 const char *name)
1237 vshCmdOpt *first = NULL;
1238 vshCmdOpt *opt;
1239 size_t nargv = 0;
1240 size_t nargv_alloc = 0;
1242 for (opt = cmd->opts; opt; opt = opt->next) {
1243 if (STRNEQ(opt->def->name, name))
1244 continue;
1246 if (!first) {
1247 /* Return existing data if we'we already processed it */
1248 if (opt->argv)
1249 return opt;
1251 first = opt;
1254 /* extra NULL terminator */
1255 VIR_RESIZE_N(first->argv, nargv_alloc, nargv, 2);
1256 first->argv[nargv++] = opt->data;
1259 if (first)
1260 first->argvstr = g_strjoinv(" ", (GStrv) first->argv);
1262 return first;
1267 * vshCommandOptArgv:
1268 * @cmd: command reference
1269 * @name: name of argument
1271 * Returns a NULL terminated list of strings of values passed as argument of
1272 * ARGV argument named @name. The returned string list is owned by @cmd and
1273 * caller must not free or modify it.
1275 const char **
1276 vshCommandOptArgv(const vshCmd *cmd,
1277 const char *name)
1279 vshCmdOpt *opt = vshCommandOptArgvInternal(cmd, name);
1281 if (!opt)
1282 return NULL;
1284 return opt->argv;
1289 * vshCommandOptArgvString:
1290 * @cmd: command reference
1291 * @name: name of argument
1293 * Returns a string containing all values passed as ARGV argument @name
1294 * delimited/concatenated by adding spaces.
1296 const char *
1297 vshCommandOptArgvString(const vshCmd *cmd,
1298 const char *name)
1300 vshCmdOpt *opt = vshCommandOptArgvInternal(cmd, name);
1302 if (!opt)
1303 return NULL;
1305 return opt->argvstr;
1310 * vshBlockJobOptionBandwidth:
1311 * @ctl: virsh control data
1312 * @cmd: virsh command description
1313 * @bytes: return bandwidth in bytes/s instead of MiB/s
1314 * @bandwidth: return value
1316 * Extracts the value of --bandwidth either as a wrap-able number without scale
1317 * or as a scaled integer. The returned value is checked to fit into a unsigned
1318 * long data type. This is a legacy compatibility function and it should not
1319 * be used for things other the block job APIs.
1321 * Returns 0 on success, -1 on error.
1324 vshBlockJobOptionBandwidth(vshControl *ctl,
1325 const vshCmd *cmd,
1326 bool bytes,
1327 unsigned long *bandwidth)
1329 vshCmdOpt *arg;
1330 char *end;
1331 unsigned long long bw;
1332 int ret;
1334 if ((ret = vshCommandOpt(cmd, "bandwidth", &arg, true)) <= 0)
1335 return ret;
1337 /* due to historical reasons we declare to parse negative numbers and wrap
1338 * them to the unsigned data type. */
1339 if (virStrToLong_ul(arg->data, NULL, 10, bandwidth) < 0) {
1340 /* try to parse the number as scaled size in this case we don't accept
1341 * wrapping since it would be ridiculous. In case of a 32 bit host,
1342 * limit the value to ULONG_MAX */
1343 if (virStrToLong_ullp(arg->data, &end, 10, &bw) < 0 ||
1344 virScaleInteger(&bw, end, 1, ULONG_MAX) < 0) {
1345 vshError(ctl,
1346 _("Scaled numeric value '%1$s' for <--bandwidth> option is malformed or out of range"),
1347 arg->data);
1348 return -1;
1351 if (!bytes)
1352 bw >>= 20;
1354 *bandwidth = bw;
1357 return 0;
1362 * Executes command(s) and returns return code from last command
1364 bool
1365 vshCommandRun(vshControl *ctl, const vshCmd *cmd)
1367 const vshClientHooks *hooks = ctl->hooks;
1368 bool ret = true;
1370 while (cmd) {
1371 gint64 before, after;
1372 bool enable_timing = ctl->timing;
1374 before = g_get_real_time();
1376 if ((cmd->def->flags & VSH_CMD_FLAG_NOCONNECT) ||
1377 (hooks && hooks->connHandler && hooks->connHandler(ctl))) {
1378 ret = cmd->def->handler(ctl, cmd);
1379 } else {
1380 /* connection is not usable, return error */
1381 ret = false;
1384 after = g_get_real_time();
1386 /* try to automatically catch disconnections */
1387 if (!ret &&
1388 ((last_error != NULL) &&
1389 (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
1390 (last_error->domain == VIR_FROM_REMOTE)) ||
1391 (last_error->code == VIR_ERR_RPC) ||
1392 (last_error->code == VIR_ERR_NO_CONNECT) ||
1393 (last_error->code == VIR_ERR_INVALID_CONN))))
1394 disconnected++;
1396 if (!ret)
1397 vshReportError(ctl);
1399 if (STREQ(cmd->def->name, "quit") ||
1400 STREQ(cmd->def->name, "exit")) /* hack ... */
1401 return ret;
1403 if (enable_timing) {
1404 double diff_ms = (after - before) / 1000.0;
1406 vshPrint(ctl, _("\n(Time: %1$.3f ms)\n\n"), diff_ms);
1407 } else {
1408 vshPrintExtra(ctl, "\n");
1410 cmd = cmd->next;
1412 return ret;
1415 /* ---------------
1416 * Command parsing
1417 * ---------------
1420 typedef enum {
1421 VSH_TK_ERROR, /* Failed to parse a token */
1422 VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
1423 VSH_TK_SUBCMD_END, /* Separation between commands */
1424 VSH_TK_END /* No more commands */
1425 } vshCommandToken;
1427 typedef struct _vshCommandParser vshCommandParser;
1428 struct _vshCommandParser {
1429 vshCommandToken(*getNextArg)(vshControl *, vshCommandParser *,
1430 char **, bool);
1431 /* vshCommandStringGetArg() */
1432 char *pos;
1433 size_t point;
1434 /* vshCommandArgvGetArg() */
1435 char **arg_pos;
1436 char **arg_end;
1439 static bool
1440 vshCommandParse(vshControl *ctl, vshCommandParser *parser, vshCmd **partial)
1442 char *tkdata = NULL;
1443 vshCmd *clast = NULL;
1444 vshCmdOpt *first = NULL;
1445 vshCmdOpt *last = NULL;
1446 const vshCmdDef *cmd = NULL;
1448 if (!partial) {
1449 g_clear_pointer(&ctl->cmd, vshCommandFree);
1452 while (1) {
1453 vshCommandToken tk;
1454 bool data_only = false;
1455 uint64_t opts_need_arg = 0;
1456 uint64_t opts_required = 0;
1457 uint64_t opts_seen = 0;
1459 cmd = NULL;
1460 first = NULL;
1461 last = NULL;
1463 if (partial) {
1464 g_clear_pointer(partial, vshCommandFree);
1467 while (1) {
1468 const vshCmdOptDef *opt = NULL;
1470 tkdata = NULL;
1471 tk = parser->getNextArg(ctl, parser, &tkdata, true);
1473 if (tk == VSH_TK_ERROR)
1474 goto syntaxError;
1475 if (tk != VSH_TK_ARG) {
1476 VIR_FREE(tkdata);
1477 break;
1480 if (cmd == NULL) {
1481 /* first token must be command name or comment */
1482 if (*tkdata == '#') {
1483 do {
1484 VIR_FREE(tkdata);
1485 tk = parser->getNextArg(ctl, parser, &tkdata, false);
1486 } while (tk == VSH_TK_ARG);
1487 VIR_FREE(tkdata);
1488 break;
1489 } else if (!(cmd = vshCmddefSearch(tkdata))) {
1490 if (!partial)
1491 vshError(ctl, _("unknown command: '%1$s'"), tkdata);
1492 goto syntaxError; /* ... or ignore this command only? */
1495 /* aliases need to be resolved to the actual commands */
1496 if (cmd->alias) {
1497 VIR_FREE(tkdata);
1498 tkdata = g_strdup(cmd->alias);
1499 if (!(cmd = vshCmddefSearch(tkdata))) {
1500 /* self-test ensures that the alias exists */
1501 vshError(ctl, _("unknown command: '%1$s'"), tkdata);
1502 goto syntaxError;
1506 vshCmddefOptParse(cmd, &opts_need_arg, &opts_required);
1507 VIR_FREE(tkdata);
1508 } else if (data_only) {
1509 goto get_data;
1510 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
1511 g_ascii_isalnum(tkdata[2])) {
1512 char *optstr = strchr(tkdata + 2, '=');
1513 size_t opt_index = 0;
1515 if (optstr) {
1516 *optstr = '\0'; /* convert the '=' to '\0' */
1517 optstr = g_strdup(optstr + 1);
1519 /* Special case 'help' to ignore all spurious options */
1520 if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
1521 &opts_seen, &opt_index,
1522 &optstr, partial == NULL))) {
1523 VIR_FREE(optstr);
1524 if (STREQ(cmd->name, "help"))
1525 continue;
1526 goto syntaxError;
1528 VIR_FREE(tkdata);
1530 if (opt->type != VSH_OT_BOOL) {
1531 /* option data */
1532 if (optstr)
1533 tkdata = optstr;
1534 else
1535 tk = parser->getNextArg(ctl, parser, &tkdata, partial == NULL);
1536 if (tk == VSH_TK_ERROR)
1537 goto syntaxError;
1538 if (tk != VSH_TK_ARG) {
1539 if (partial) {
1540 vshCmdOpt *arg = g_new0(vshCmdOpt, 1);
1541 arg->def = opt;
1542 arg->data = g_steal_pointer(&tkdata);
1543 arg->next = NULL;
1545 if (!first)
1546 first = arg;
1547 if (last)
1548 last->next = arg;
1549 last = arg;
1550 } else {
1551 vshError(ctl,
1552 _("expected syntax: --%1$s <%2$s>"),
1553 opt->name,
1554 opt->type ==
1555 VSH_OT_INT ? _("number") : _("string"));
1557 goto syntaxError;
1559 if (opt->type != VSH_OT_ARGV)
1560 opts_need_arg &= ~(1ULL << opt_index);
1561 } else {
1562 tkdata = NULL;
1563 if (optstr) {
1564 if (!partial)
1565 vshError(ctl, _("invalid '=' after option --%1$s"),
1566 opt->name);
1567 VIR_FREE(optstr);
1568 goto syntaxError;
1571 } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
1572 tkdata[2] == '\0') {
1573 VIR_FREE(tkdata);
1574 data_only = true;
1575 continue;
1576 } else {
1577 get_data:
1578 /* Special case 'help' to ignore spurious data */
1579 if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
1580 &opts_seen)) &&
1581 STRNEQ(cmd->name, "help")) {
1582 if (!partial)
1583 vshError(ctl, _("unexpected data '%1$s'"), tkdata);
1584 goto syntaxError;
1587 if (opt) {
1588 /* save option */
1589 vshCmdOpt *arg = g_new0(vshCmdOpt, 1);
1591 arg->def = opt;
1592 arg->data = g_steal_pointer(&tkdata);
1593 arg->next = NULL;
1595 if (!first)
1596 first = arg;
1597 if (last)
1598 last->next = arg;
1599 last = arg;
1601 if (!partial)
1602 vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
1603 cmd->name,
1604 opt->name,
1605 opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
1606 opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
1610 /* command parsed -- allocate new struct for the command */
1611 if (cmd) {
1612 vshCmd *c = g_new0(vshCmd, 1);
1613 vshCmdOpt *tmpopt = first;
1615 /* if we encountered --help, replace parsed command with
1616 * 'help <cmdname>' */
1617 for (tmpopt = first; tmpopt; tmpopt = tmpopt->next) {
1618 const vshCmdDef *help;
1619 if (STRNEQ(tmpopt->def->name, "help"))
1620 continue;
1622 /* the self-test code ensures that help exists */
1623 if (!(help = vshCmddefSearch("help")))
1624 break;
1626 vshCommandOptFree(first);
1627 first = g_new0(vshCmdOpt, 1);
1628 first->def = help->opts;
1629 first->data = g_strdup(cmd->name);
1630 first->next = NULL;
1632 cmd = help;
1633 opts_required = 0;
1634 opts_seen = 0;
1635 break;
1638 c->opts = g_steal_pointer(&first);
1639 c->lastopt = last;
1640 c->def = cmd;
1641 c->next = NULL;
1643 if (!partial &&
1644 vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
1645 vshCommandFree(c);
1646 goto syntaxError;
1649 if (partial) {
1650 vshCommandFree(*partial);
1651 *partial = c;
1652 } else {
1653 if (!ctl->cmd)
1654 ctl->cmd = c;
1655 if (clast)
1656 clast->next = c;
1657 clast = c;
1661 if (tk == VSH_TK_END)
1662 break;
1665 return true;
1667 syntaxError:
1668 if (partial) {
1669 vshCmd *tmp;
1671 tmp = g_new0(vshCmd, 1);
1672 tmp->opts = first;
1673 tmp->lastopt = last;
1674 tmp->def = cmd;
1676 *partial = tmp;
1677 } else {
1678 g_clear_pointer(&ctl->cmd, vshCommandFree);
1679 vshCommandOptFree(first);
1681 VIR_FREE(tkdata);
1682 return false;
1685 /* --------------------
1686 * Command argv parsing
1687 * --------------------
1690 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
1691 vshCommandArgvGetArg(vshControl *ctl G_GNUC_UNUSED,
1692 vshCommandParser *parser,
1693 char **res,
1694 bool report G_GNUC_UNUSED)
1696 if (parser->arg_pos == parser->arg_end) {
1697 *res = NULL;
1698 return VSH_TK_END;
1701 *res = g_strdup(*parser->arg_pos);
1702 parser->arg_pos++;
1703 return VSH_TK_ARG;
1706 bool
1707 vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
1709 vshCommandParser parser = { 0 };
1711 if (nargs <= 0)
1712 return false;
1714 parser.arg_pos = argv;
1715 parser.arg_end = argv + nargs;
1716 parser.getNextArg = vshCommandArgvGetArg;
1717 return vshCommandParse(ctl, &parser, NULL);
1720 /* ----------------------
1721 * Command string parsing
1722 * ----------------------
1725 static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
1726 vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
1727 bool report)
1729 bool single_quote = false;
1730 bool double_quote = false;
1731 char *p = parser->pos;
1732 char *q = g_strdup(p);
1734 *res = q;
1736 while (*p == ' ' || *p == '\t' || (*p == '\\' && p[1] == '\n'))
1737 p += 1 + (*p == '\\');
1739 if (*p == '\0')
1740 return VSH_TK_END;
1741 if (*p == ';' || *p == '\n') {
1742 parser->pos = ++p; /* = \0 or begin of next command */
1743 return VSH_TK_SUBCMD_END;
1745 if (*p == '#') { /* Argument starting with # is comment to end of line */
1746 while (*p && *p != '\n')
1747 p++;
1748 parser->pos = p + !!*p;
1749 return VSH_TK_SUBCMD_END;
1752 while (*p) {
1753 /* end of token is blank space or ';' */
1754 if (!double_quote && !single_quote &&
1755 (*p == ' ' || *p == '\t' || *p == ';' || *p == '\n'))
1756 break;
1758 if (!double_quote && *p == '\'') { /* single quote */
1759 single_quote = !single_quote;
1760 p++;
1761 continue;
1762 } else if (!single_quote && *p == '\\') { /* escape */
1764 * The same as in shell, a \ in "" is an escaper,
1765 * but a \ in '' is not an escaper.
1767 p++;
1768 if (*p == '\0') {
1769 if (report)
1770 vshError(ctl, "%s", _("dangling \\"));
1771 return VSH_TK_ERROR;
1772 } else if (*p == '\n') {
1773 /* Elide backslash-newline entirely */
1774 p++;
1775 continue;
1777 } else if (!single_quote && *p == '"') { /* double quote */
1778 double_quote = !double_quote;
1779 p++;
1780 continue;
1783 *q++ = *p++;
1786 if (double_quote) {
1787 /* We have seen a double quote, but not it's companion
1788 * ending. It's valid though, in case when we're called
1789 * from completer (report = false), but it's not valid
1790 * when parsing real command (report= true). */
1791 if (report) {
1792 vshError(ctl, "%s", _("missing \""));
1793 return VSH_TK_ERROR;
1797 *q = '\0';
1798 parser->pos = p;
1799 return VSH_TK_ARG;
1804 * vshCommandStringParse:
1805 * @ctl virsh control structure
1806 * @cmdstr: string to parse
1807 * @partial: store partially parsed command here
1809 * Parse given string @cmdstr as a command and store it under
1810 * @ctl->cmd. For readline completion, if @partial is not NULL on
1811 * the input then errors in parsing are ignored (because user is
1812 * still in progress of writing the command string) and partially
1813 * parsed command is stored at *@partial (caller has to free it
1814 * afterwards).
1816 bool
1817 vshCommandStringParse(vshControl *ctl,
1818 char *cmdstr,
1819 vshCmd **partial)
1821 vshCommandParser parser = { 0 };
1823 if (cmdstr == NULL || *cmdstr == '\0')
1824 return false;
1826 parser.pos = cmdstr;
1827 parser.getNextArg = vshCommandStringGetArg;
1828 return vshCommandParse(ctl, &parser, partial);
1832 * virshCommandOptTimeoutToMs:
1833 * @ctl virsh control structure
1834 * @cmd command reference
1835 * @timeout result
1837 * Parse an optional --timeout parameter in seconds, but store the
1838 * value of the timeout in milliseconds.
1839 * See vshCommandOptInt()
1842 vshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout)
1844 int ret;
1845 unsigned int utimeout;
1847 if ((ret = vshCommandOptUInt(ctl, cmd, "timeout", &utimeout)) <= 0)
1848 return ret;
1850 /* Ensure that the timeout is not zero and that we can convert
1851 * it from seconds to milliseconds without overflowing. */
1852 if (utimeout == 0 || utimeout > INT_MAX / 1000) {
1853 vshError(ctl,
1854 _("Numeric value '%1$u' for <%2$s> option is malformed or out of range"),
1855 utimeout,
1856 "timeout");
1857 ret = -1;
1858 } else {
1859 *timeout = ((int) utimeout) * 1000;
1862 return ret;
1866 /* ---------------
1867 * Misc utils
1868 * ---------------
1871 /* Return a non-NULL string representation of a typed parameter; exit on
1872 * unknown type. */
1873 char *
1874 vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
1876 switch (item->type) {
1877 case VIR_TYPED_PARAM_INT:
1878 return g_strdup_printf("%d", item->value.i);
1879 break;
1881 case VIR_TYPED_PARAM_UINT:
1882 return g_strdup_printf("%u", item->value.ui);
1883 break;
1885 case VIR_TYPED_PARAM_LLONG:
1886 return g_strdup_printf("%lld", item->value.l);
1887 break;
1889 case VIR_TYPED_PARAM_ULLONG:
1890 return g_strdup_printf("%llu", item->value.ul);
1891 break;
1893 case VIR_TYPED_PARAM_DOUBLE:
1894 return g_strdup_printf("%f", item->value.d);
1895 break;
1897 case VIR_TYPED_PARAM_BOOLEAN:
1898 return g_strdup(item->value.b ? _("yes") : _("no"));
1899 break;
1901 case VIR_TYPED_PARAM_STRING:
1902 return g_strdup(item->value.s);
1903 break;
1905 default:
1906 vshError(ctl, _("unimplemented parameter type %1$d"), item->type);
1907 exit(EXIT_FAILURE);
1911 void
1912 vshDebug(vshControl *ctl, int level, const char *format, ...)
1914 va_list ap;
1915 g_autofree char *str = NULL;
1917 /* Aligning log levels to that of libvirt.
1918 * Traces with levels >= user-specified-level
1919 * gets logged into file
1921 if (level < ctl->debug)
1922 return;
1924 va_start(ap, format);
1925 vshOutputLogFile(ctl, level, format, ap);
1926 va_end(ap);
1928 va_start(ap, format);
1929 str = g_strdup_vprintf(format, ap);
1930 va_end(ap);
1931 fputs(str, stdout);
1932 fflush(stdout);
1936 void
1937 vshPrintVa(vshControl *ctl G_GNUC_UNUSED,
1938 const char *format,
1939 va_list ap)
1941 g_autofree char *str = NULL;
1943 str = g_strdup_vprintf(format, ap);
1944 fputs(str, stdout);
1945 fflush(stdout);
1949 void
1950 vshPrintExtra(vshControl *ctl,
1951 const char *format,
1952 ...)
1954 va_list ap;
1956 if (ctl && ctl->quiet)
1957 return;
1959 va_start(ap, format);
1960 vshPrintVa(ctl, format, ap);
1961 va_end(ap);
1965 void
1966 vshPrint(vshControl *ctl,
1967 const char *format,
1968 ...)
1970 va_list ap;
1972 va_start(ap, format);
1973 vshPrintVa(ctl, format, ap);
1974 va_end(ap);
1978 bool
1979 vshTTYIsInterruptCharacter(vshControl *ctl G_GNUC_UNUSED,
1980 const char chr G_GNUC_UNUSED)
1982 #ifndef WIN32
1983 if (ctl->istty &&
1984 ctl->termattr.c_cc[VINTR] == chr)
1985 return true;
1986 #endif
1988 return false;
1992 bool
1993 vshTTYAvailable(vshControl *ctl)
1995 return ctl->istty;
2000 vshTTYDisableInterrupt(vshControl *ctl G_GNUC_UNUSED)
2002 #ifndef WIN32
2003 struct termios termset = ctl->termattr;
2005 if (!ctl->istty)
2006 return -1;
2008 /* check if we need to set the terminal */
2009 if (termset.c_cc[VINTR] == _POSIX_VDISABLE)
2010 return 0;
2012 termset.c_cc[VINTR] = _POSIX_VDISABLE;
2013 termset.c_lflag &= ~ICANON;
2015 if (tcsetattr(STDIN_FILENO, TCSANOW, &termset) < 0)
2016 return -1;
2017 #endif
2019 return 0;
2024 vshTTYRestore(vshControl *ctl G_GNUC_UNUSED)
2026 #ifndef WIN32
2027 if (!ctl->istty)
2028 return 0;
2030 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ctl->termattr) < 0)
2031 return -1;
2032 #endif
2034 return 0;
2039 vshTTYMakeRaw(vshControl *ctl G_GNUC_UNUSED,
2040 bool report_errors G_GNUC_UNUSED)
2042 #ifndef WIN32
2043 struct termios rawattr = ctl->termattr;
2046 if (!ctl->istty) {
2047 if (report_errors) {
2048 vshError(ctl, "%s",
2049 _("unable to make terminal raw: console isn't a tty"));
2052 return -1;
2055 cfmakeraw(&rawattr);
2057 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) {
2058 if (report_errors)
2059 vshError(ctl, _("unable to set tty attributes: %1$s"),
2060 g_strerror(errno));
2061 return -1;
2063 #endif
2065 return 0;
2069 void
2070 vshError(vshControl *ctl, const char *format, ...)
2072 va_list ap;
2073 g_autofree char *str = NULL;
2075 if (ctl != NULL) {
2076 va_start(ap, format);
2077 vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
2078 va_end(ap);
2081 /* Most output is to stdout, but if someone ran virsh 2>&1, then
2082 * printing to stderr will not interleave correctly with stdout
2083 * unless we flush between every transition between streams. */
2084 fflush(stdout);
2085 fputs(_("error: "), stderr);
2087 va_start(ap, format);
2088 str = g_strdup_vprintf(format, ap);
2089 va_end(ap);
2091 fprintf(stderr, "%s\n", NULLSTR(str));
2092 fflush(stderr);
2096 void
2097 vshEventLoop(void *opaque)
2099 vshControl *ctl = opaque;
2101 while (1) {
2102 bool quit = false;
2103 VIR_WITH_MUTEX_LOCK_GUARD(&ctl->lock) {
2104 quit = ctl->quit;
2107 if (quit)
2108 break;
2110 if (virEventRunDefaultImpl() < 0)
2111 vshReportError(ctl);
2117 * Helpers for waiting for a libvirt event.
2120 /* We want to use SIGINT to cancel a wait; but as signal handlers
2121 * don't have an opaque argument, we have to use static storage. */
2122 #ifndef WIN32
2123 static int vshEventFd = -1;
2124 static struct sigaction vshEventOldAction;
2127 /* Signal handler installed in vshEventStart, removed in vshEventCleanup. */
2128 static void
2129 vshEventInt(int sig G_GNUC_UNUSED,
2130 siginfo_t *siginfo G_GNUC_UNUSED,
2131 void *context G_GNUC_UNUSED)
2133 char reason = VSH_EVENT_INTERRUPT;
2134 if (vshEventFd >= 0)
2135 ignore_value(safewrite(vshEventFd, &reason, 1));
2137 #endif /* !WIN32 */
2140 /* Event loop handler used to limit length of waiting for any other event. */
2141 void
2142 vshEventTimeout(int timer G_GNUC_UNUSED,
2143 void *opaque)
2145 vshControl *ctl = opaque;
2146 char reason = VSH_EVENT_TIMEOUT;
2148 if (ctl->eventPipe[1] >= 0)
2149 ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
2154 * vshEventStart:
2155 * @ctl vsh command struct
2156 * @timeout_ms max wait time in milliseconds, or 0 for indefinite
2158 * Set up a wait for a libvirt event. The wait can be canceled by
2159 * SIGINT or by calling vshEventDone() in your event handler. If
2160 * @timeout_ms is positive, the wait will also end if the timeout
2161 * expires. Call vshEventWait() to block the main thread (the event
2162 * handler runs in the event loop thread). When done (including if
2163 * there was an error registering for an event), use vshEventCleanup()
2164 * to quit waiting. Returns 0 on success, -1 on failure. */
2166 vshEventStart(vshControl *ctl, int timeout_ms)
2168 #ifndef WIN32
2169 struct sigaction action;
2170 assert(vshEventFd == -1);
2171 #endif /* !WIN32 */
2173 assert(ctl->eventPipe[0] == -1 && ctl->eventPipe[1] == -1 &&
2174 ctl->eventTimerId >= 0);
2175 if (virPipe(ctl->eventPipe) < 0) {
2176 vshSaveLibvirtError();
2177 vshReportError(ctl);
2178 return -1;
2181 #ifndef WIN32
2182 vshEventFd = ctl->eventPipe[1];
2184 action.sa_sigaction = vshEventInt;
2185 action.sa_flags = SA_SIGINFO;
2186 sigemptyset(&action.sa_mask);
2187 sigaction(SIGINT, &action, &vshEventOldAction);
2188 #endif /* !WIN32 */
2190 if (timeout_ms)
2191 virEventUpdateTimeout(ctl->eventTimerId, timeout_ms);
2193 return 0;
2198 * vshEventDone:
2199 * @ctl vsh command struct
2201 * Call this from an event callback to let the main thread quit
2202 * blocking on further events.
2204 void
2205 vshEventDone(vshControl *ctl)
2207 char reason = VSH_EVENT_DONE;
2209 if (ctl->eventPipe[1] >= 0)
2210 ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
2215 * vshEventWait:
2216 * @ctl vsh command struct
2218 * Call this in the main thread after calling vshEventStart() then
2219 * registering for one or more events. This call will block until
2220 * SIGINT, the timeout registered at the start, or until one of your
2221 * event handlers calls vshEventDone(). Returns an enum VSH_EVENT_*
2222 * stating how the wait concluded, or -1 on error.
2225 vshEventWait(vshControl *ctl)
2227 char buf;
2228 int rv;
2230 assert(ctl->eventPipe[0] >= 0);
2231 while ((rv = read(ctl->eventPipe[0], &buf, 1)) < 0 && errno == EINTR);
2232 if (rv != 1) {
2233 if (!rv)
2234 errno = EPIPE;
2235 vshError(ctl, _("failed to determine loop exit status: %1$s"),
2236 g_strerror(errno));
2237 return -1;
2239 return buf;
2244 * vshEventCleanup:
2245 * @ctl vsh control struct
2247 * Call at the end of any function that has used vshEventStart(), to
2248 * tear down any remaining SIGINT or timeout handlers.
2250 void
2251 vshEventCleanup(vshControl *ctl)
2253 #ifndef WIN32
2254 if (vshEventFd >= 0) {
2255 sigaction(SIGINT, &vshEventOldAction, NULL);
2256 vshEventFd = -1;
2258 #endif /* !WIN32 */
2259 VIR_FORCE_CLOSE(ctl->eventPipe[0]);
2260 VIR_FORCE_CLOSE(ctl->eventPipe[1]);
2261 virEventUpdateTimeout(ctl->eventTimerId, -1);
2264 #ifdef O_SYNC
2265 # define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)
2266 #else
2267 # define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT)
2268 #endif
2271 * vshOpenLogFile:
2273 * Open log file.
2275 void
2276 vshOpenLogFile(vshControl *ctl)
2278 if (ctl->logfile == NULL)
2279 return;
2281 if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
2282 vshError(ctl, "%s",
2283 _("failed to open the log file. check the log file path"));
2284 exit(EXIT_FAILURE);
2289 * vshOutputLogFile:
2291 * Outputting an error to log file.
2293 void
2294 vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format,
2295 va_list ap)
2297 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
2298 g_autofree char *str = NULL;
2299 size_t len;
2300 const char *lvl = "";
2301 g_autoptr(GDateTime) now = g_date_time_new_now_local();
2302 g_autofree gchar *nowstr = NULL;
2304 if (ctl->log_fd == -1)
2305 return;
2308 * create log format
2310 * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
2312 nowstr = g_date_time_format(now, "%Y.%m.%d %H:%M:%S");
2313 virBufferAsprintf(&buf, "[%s %s %d] ",
2314 nowstr,
2315 ctl->progname,
2316 (int) getpid());
2317 switch (log_level) {
2318 case VSH_ERR_DEBUG:
2319 lvl = LVL_DEBUG;
2320 break;
2321 case VSH_ERR_INFO:
2322 lvl = LVL_INFO;
2323 break;
2324 case VSH_ERR_NOTICE:
2325 lvl = LVL_INFO;
2326 break;
2327 case VSH_ERR_WARNING:
2328 lvl = LVL_WARNING;
2329 break;
2330 case VSH_ERR_ERROR:
2331 lvl = LVL_ERROR;
2332 break;
2333 default:
2334 lvl = LVL_DEBUG;
2335 break;
2337 virBufferAsprintf(&buf, "%s ", lvl);
2338 virBufferVasprintf(&buf, msg_format, ap);
2339 virBufferTrim(&buf, "\n");
2340 virBufferAddChar(&buf, '\n');
2342 str = virBufferContentAndReset(&buf);
2343 len = strlen(str);
2345 /* write log */
2346 if (safewrite(ctl->log_fd, str, len) < 0)
2347 goto error;
2349 return;
2351 error:
2352 vshCloseLogFile(ctl);
2353 vshError(ctl, "%s", _("failed to write the log file"));
2357 * vshCloseLogFile:
2359 * Close log file.
2361 void
2362 vshCloseLogFile(vshControl *ctl)
2364 /* log file close */
2365 if (VIR_CLOSE(ctl->log_fd) < 0) {
2366 vshError(ctl, _("%1$s: failed to write log file: %2$s"),
2367 ctl->logfile ? ctl->logfile : "?",
2368 g_strerror(errno));
2371 g_clear_pointer(&ctl->logfile, g_free);
2374 #ifndef WIN32
2375 static void
2376 vshPrintRaw(vshControl *ctl, ...)
2378 va_list ap;
2379 char *key;
2381 va_start(ap, ctl);
2382 while ((key = va_arg(ap, char *)) != NULL)
2383 vshPrint(ctl, "%s\r\n", key);
2384 va_end(ap);
2388 * vshAskReedit:
2389 * @msg: Question to ask user
2391 * Ask user if he wants to return to previously
2392 * edited file.
2394 * Returns 'y' if he wants to
2395 * 'n' if he doesn't want to
2396 * 'i' if he wants to try defining it again while ignoring validation
2397 * 'f' if he forcibly wants to
2398 * -1 on error
2399 * 0 otherwise
2402 vshAskReedit(vshControl *ctl, const char *msg, bool relax_avail)
2404 int c = -1;
2406 if (!isatty(STDIN_FILENO))
2407 return -1;
2409 vshReportError(ctl);
2411 if (vshTTYMakeRaw(ctl, false) < 0)
2412 return -1;
2414 while (true) {
2415 vshPrint(ctl, "\r%s %s %s: ", msg, _("Try again?"),
2416 relax_avail ? "[y,n,i,f,?]" : "[y,n,f,?]");
2417 c = g_ascii_tolower(getchar());
2419 if (c == '?') {
2420 vshPrintRaw(ctl,
2422 _("y - yes, start editor again"),
2423 _("n - no, throw away my changes"),
2424 NULL);
2426 if (relax_avail) {
2427 vshPrintRaw(ctl,
2428 _("i - turn off validation and try to redefine again"),
2429 NULL);
2432 vshPrintRaw(ctl,
2433 _("f - force, try to redefine again"),
2434 _("? - print this help"),
2435 NULL);
2436 continue;
2437 } else if (c == 'y' || c == 'n' || c == 'f' ||
2438 (relax_avail && c == 'i')) {
2439 break;
2443 vshTTYRestore(ctl);
2445 vshPrint(ctl, "\r\n");
2446 return c;
2448 #else /* WIN32 */
2450 vshAskReedit(vshControl *ctl,
2451 const char *msg G_GNUC_UNUSED,
2452 bool relax_avail G_GNUC_UNUSED)
2454 vshDebug(ctl, VSH_ERR_WARNING, "%s", _("This function is not supported on WIN32 platform"));
2455 return 0;
2457 #endif /* WIN32 */
2460 void
2461 vshEditUnlinkTempfile(char *file)
2463 if (!file)
2464 return;
2466 ignore_value(unlink(file));
2467 g_free(file);
2471 /* Common code for the edit / net-edit / pool-edit functions which follow. */
2472 char *
2473 vshEditWriteToTempFile(vshControl *ctl, const char *doc)
2475 g_autofree char *filename = NULL;
2476 g_autoptr(vshTempFile) ret = NULL;
2477 const char *tmpdir;
2478 VIR_AUTOCLOSE fd = -1;
2480 tmpdir = getenv("TMPDIR");
2481 if (!tmpdir)
2482 tmpdir = "/tmp";
2483 filename = g_strdup_printf("%s/virshXXXXXX.xml", tmpdir);
2484 fd = g_mkstemp_full(filename, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR);
2485 if (fd == -1) {
2486 vshError(ctl, _("g_mkstemp_full: failed to create temporary file: %1$s"),
2487 g_strerror(errno));
2488 return NULL;
2491 ret = g_steal_pointer(&filename);
2493 if (safewrite(fd, doc, strlen(doc)) == -1) {
2494 vshError(ctl, _("write: %1$s: failed to write to temporary file: %2$s"),
2495 ret, g_strerror(errno));
2496 return NULL;
2498 if (VIR_CLOSE(fd) < 0) {
2499 vshError(ctl, _("close: %1$s: failed to write or close temporary file: %2$s"),
2500 ret, g_strerror(errno));
2501 return NULL;
2504 /* Temporary filename: caller frees. */
2505 return g_steal_pointer(&ret);
2508 /* Characters permitted in $EDITOR environment variable and temp filename. */
2509 #define ACCEPTED_CHARS \
2510 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/_.:@"
2512 /* Hard-code default editor used as a fallback if not configured by
2513 * VISUAL or EDITOR environment variables. */
2514 #define DEFAULT_EDITOR "vi"
2517 vshEditFile(vshControl *ctl, const char *filename)
2519 const char *editor;
2520 g_autoptr(virCommand) cmd = NULL;
2521 int outfd = STDOUT_FILENO;
2522 int errfd = STDERR_FILENO;
2524 editor = getenv("VISUAL");
2525 if (!editor)
2526 editor = getenv("EDITOR");
2527 if (!editor)
2528 editor = DEFAULT_EDITOR;
2530 /* Check that filename doesn't contain shell meta-characters, and
2531 * if it does, refuse to run. Follow the Unix conventions for
2532 * EDITOR: the user can intentionally specify command options, so
2533 * we don't protect any shell metacharacters there. Lots more
2534 * than virsh will misbehave if EDITOR has bogus contents (which
2535 * is why sudo scrubs it by default). Conversely, if the editor
2536 * is safe, we can run it directly rather than wasting a shell.
2538 if (strspn(editor, ACCEPTED_CHARS) != strlen(editor)) {
2539 if (strspn(filename, ACCEPTED_CHARS) != strlen(filename)) {
2540 vshError(ctl,
2541 _("%1$s: temporary filename contains shell meta or other unacceptable characters (is $TMPDIR wrong?)"),
2542 filename);
2543 return -1;
2545 cmd = virCommandNewArgList("sh", "-c", NULL);
2546 virCommandAddArgFormat(cmd, "%s %s", editor, filename);
2547 } else {
2548 cmd = virCommandNewArgList(editor, filename, NULL);
2551 virCommandSetInputFD(cmd, STDIN_FILENO);
2552 virCommandSetOutputFD(cmd, &outfd);
2553 virCommandSetErrorFD(cmd, &errfd);
2554 if (virCommandRunAsync(cmd, NULL) < 0 ||
2555 virCommandWait(cmd, NULL) < 0) {
2556 vshReportError(ctl);
2557 return -1;
2559 return 0;
2562 char *
2563 vshEditReadBackFile(vshControl *ctl, const char *filename)
2565 char *ret;
2567 if (virFileReadAll(filename, VSH_MAX_XML_FILE, &ret) == -1) {
2568 vshError(ctl,
2569 _("%1$s: failed to read temporary file: %2$s"),
2570 filename, g_strerror(errno));
2571 return NULL;
2573 return ret;
2577 vshEditString(vshControl *ctl,
2578 char **output,
2579 const char *string)
2581 g_autoptr(vshTempFile) tmp = NULL;
2582 char *tmpstr;
2584 /* Create and open the temporary file. */
2585 if (!(tmp = vshEditWriteToTempFile(ctl, string)))
2586 return -1;
2588 /* Start the editor. */
2589 if (vshEditFile(ctl, tmp) == -1)
2590 return -1;
2592 /* Read back the edited file. */
2593 if (!(*output = vshEditReadBackFile(ctl, tmp)))
2594 return -1;
2596 /* strip a possible newline at the end of file; some
2597 * editors enforce a newline, this makes editing
2598 * more convenient */
2599 if ((tmpstr = strrchr(*output, '\n')) &&
2600 *(tmpstr+1) == '\0')
2601 *tmpstr = '\0';
2603 return 0;
2606 /* Tree listing helpers. */
2608 static int
2609 vshTreePrintInternal(vshControl *ctl,
2610 vshTreeLookup lookup,
2611 void *opaque,
2612 int num_devices,
2613 int devid,
2614 int lastdev,
2615 bool root,
2616 virBuffer *indent)
2618 size_t i;
2619 int nextlastdev = -1;
2620 const char *dev = (lookup)(devid, false, opaque);
2622 /* Print this device, with indent if not at root */
2623 vshPrint(ctl, "%s%s%s\n", virBufferCurrentContent(indent),
2624 root ? "" : "+- ", dev);
2626 /* Update indent to show '|' or ' ' for child devices */
2627 if (!root) {
2628 virBufferAddChar(indent, devid == lastdev ? ' ' : '|');
2629 virBufferAddChar(indent, ' ');
2632 /* Determine the index of the last child device */
2633 for (i = 0; i < num_devices; i++) {
2634 const char *parent = (lookup)(i, true, opaque);
2636 if (parent && STREQ(parent, dev))
2637 nextlastdev = i;
2640 /* If there is a child device, then print another blank line */
2641 if (nextlastdev != -1)
2642 vshPrint(ctl, "%s |\n", virBufferCurrentContent(indent));
2644 /* Finally print all children */
2645 virBufferAddLit(indent, " ");
2646 for (i = 0; i < num_devices; i++) {
2647 const char *parent = (lookup)(i, true, opaque);
2649 if (parent && STREQ(parent, dev) &&
2650 vshTreePrintInternal(ctl, lookup, opaque,
2651 num_devices, i, nextlastdev,
2652 false, indent) < 0)
2653 return -1;
2655 virBufferTrim(indent, " ");
2657 /* If there was no child device, and we're the last in
2658 * a list of devices, then print another blank line */
2659 if (nextlastdev == -1 && devid == lastdev)
2660 vshPrint(ctl, "%s\n", virBufferCurrentContent(indent));
2662 if (!root)
2663 virBufferTrimLen(indent, 2);
2665 return 0;
2669 vshTreePrint(vshControl *ctl, vshTreeLookup lookup, void *opaque,
2670 int num_devices, int devid)
2672 int ret;
2673 g_auto(virBuffer) indent = VIR_BUFFER_INITIALIZER;
2675 ret = vshTreePrintInternal(ctl, lookup, opaque, num_devices,
2676 devid, devid, true, &indent);
2677 if (ret < 0)
2678 vshError(ctl, "%s", _("Failed to complete tree listing"));
2679 return ret;
2684 * vshReadlineCommandGenerator:
2686 * Generator function for command completion. Used also for completing the
2687 * '--command' option of the 'help' command.
2689 * Returns a string list of all commands, or NULL on failure.
2691 static char **
2692 vshReadlineCommandGenerator(void)
2694 size_t grp_list_index = 0;
2695 const vshCmdGrp *grp;
2696 size_t ret_size = 0;
2697 g_auto(GStrv) ret = NULL;
2699 grp = cmdGroups;
2701 for (grp_list_index = 0; grp[grp_list_index].name; grp_list_index++) {
2702 const vshCmdDef *cmds = grp[grp_list_index].commands;
2703 size_t cmd_list_index;
2705 for (cmd_list_index = 0; cmds[cmd_list_index].name; cmd_list_index++) {
2706 const char *name = cmds[cmd_list_index].name;
2708 if (cmds[cmd_list_index].alias ||
2709 cmds[cmd_list_index].flags & VSH_CMD_FLAG_HIDDEN)
2710 continue;
2712 VIR_REALLOC_N(ret, ret_size + 2);
2714 ret[ret_size] = g_strdup(name);
2715 ret_size++;
2716 /* Terminate the string list properly. */
2717 ret[ret_size] = NULL;
2721 return g_steal_pointer(&ret);
2725 #if WITH_READLINE
2727 /* -----------------
2728 * Readline stuff
2729 * -----------------
2733 static char **
2734 vshReadlineOptionsGenerator(const vshCmdDef *cmd,
2735 vshCmd *last)
2737 size_t list_index = 0;
2738 size_t ret_size = 0;
2739 g_auto(GStrv) ret = NULL;
2741 if (!cmd)
2742 return NULL;
2744 if (!cmd->opts)
2745 return NULL;
2747 for (list_index = 0; cmd->opts[list_index].name; list_index++) {
2748 const char *name = cmd->opts[list_index].name;
2749 bool exists = false;
2750 vshCmdOpt *opt = last->opts;
2752 /* Skip aliases, we do not report them in help output either. */
2753 if (cmd->opts[list_index].type == VSH_OT_ALIAS)
2754 continue;
2756 while (opt) {
2757 if (STREQ(opt->def->name, name) && opt->def->type != VSH_OT_ARGV) {
2758 exists = true;
2759 break;
2762 opt = opt->next;
2765 if (exists)
2766 continue;
2768 VIR_REALLOC_N(ret, ret_size + 2);
2770 ret[ret_size] = g_strdup_printf("--%s", name);
2771 ret_size++;
2772 /* Terminate the string list properly. */
2773 ret[ret_size] = NULL;
2776 return g_steal_pointer(&ret);
2780 static int
2781 vshCompleterFilter(char ***list,
2782 const char *text)
2784 char **newList = NULL;
2785 size_t newList_len = 0;
2786 size_t list_len;
2787 size_t i;
2789 if (!list || !*list)
2790 return 0;
2792 list_len = g_strv_length(*list);
2793 newList = g_new0(char *, list_len + 1);
2795 for (i = 0; i < list_len; i++) {
2796 if (!STRPREFIX((*list)[i], text)) {
2797 g_clear_pointer(&(*list)[i], g_free);
2798 continue;
2801 newList[newList_len] = g_steal_pointer(&(*list)[i]);
2802 newList_len++;
2805 newList = g_renew(char *, newList, newList_len + 1);
2806 g_free(*list);
2807 *list = newList;
2808 return 0;
2812 static char *
2813 vshReadlineParse(const char *text, int state)
2815 static char **list;
2816 static size_t list_index;
2817 char *ret = NULL;
2819 /* Readline calls this function until NULL is returned. On
2820 * the very first call @state is zero which means we should
2821 * initialize those static variables above. On subsequent
2822 * calls @state is non zero. */
2823 if (!state) {
2824 g_autoptr(vshCmd) partial = NULL;
2825 const vshCmdDef *cmd = NULL;
2826 g_autofree char *line = g_strdup(rl_line_buffer);
2828 g_clear_pointer(&list, g_strfreev);
2829 list_index = 0;
2831 *(line + rl_point) = '\0';
2833 vshCommandStringParse(NULL, line, &partial);
2835 if (partial) {
2836 cmd = partial->def;
2837 partial->skipChecks = true;
2840 if (cmd && STREQ(cmd->name, text)) {
2841 /* Corner case - some commands share prefix (e.g.
2842 * dump and dumpxml). If user typed 'dump<TAB><TAB>',
2843 * then @text = "dump" and we want to offer command
2844 * completion. If they typed 'dump <TAB><TAB>' then
2845 * @text = "" (the space after the command) and we
2846 * want to offer options completion for dump command.
2848 cmd = NULL;
2851 if (!cmd) {
2852 list = vshReadlineCommandGenerator();
2853 } else {
2854 bool complete_argument = false;
2856 /* attempt completion only when:
2857 - there is an argument
2858 - it has the 'data' field filled
2859 - it has a completer (rules out booleans)
2861 if (partial->lastopt && partial->lastopt->data && partial->lastopt->def->completer) {
2862 /* Furthermore we want to do the completion only at the point of
2863 * user's cursor. This is the case if:
2864 * - value in 'data' is equal to 'text' (last component of the completed command)
2865 * - value in 'data' is a space when 'text' is empty (quirk)
2867 if (STREQ_NULLABLE(partial->lastopt->data, text))
2868 complete_argument = true;
2870 if (STREQ_NULLABLE(partial->lastopt->data, " ") && *text == '\0')
2871 complete_argument = true;
2874 if (complete_argument) {
2875 list = partial->lastopt->def->completer(autoCompleteOpaque,
2876 partial,
2877 partial->lastopt->def->completer_flags);
2878 } else {
2879 list = vshReadlineOptionsGenerator(cmd, partial);
2883 /* Escape completions, if needed (i.e. argument
2884 * we are completing wasn't started with a quote
2885 * character). This also enables filtering done
2886 * below to work properly. */
2887 if (list &&
2888 !rl_completion_quote_character) {
2889 size_t i;
2891 for (i = 0; list[i]; i++) {
2892 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
2894 virBufferEscape(&buf, '\\', " ", "%s", list[i]);
2895 VIR_FREE(list[i]);
2896 list[i] = virBufferContentAndReset(&buf);
2900 /* For string list returned by completers we have to do
2901 * filtering based on @text because completers returns all
2902 * possible strings. */
2903 if (vshCompleterFilter(&list, text) < 0)
2904 goto cleanup;
2907 if (list) {
2908 ret = g_strdup(list[list_index]);
2909 list_index++;
2912 cleanup:
2913 if (!ret) {
2914 g_clear_pointer(&list, g_strfreev);
2915 list_index = 0;
2918 return ret;
2921 static char **
2922 vshReadlineCompletion(const char *text,
2923 int start G_GNUC_UNUSED,
2924 int end G_GNUC_UNUSED)
2926 return rl_completion_matches(text, vshReadlineParse);
2930 static int
2931 vshReadlineCharIsQuoted(char *line, int idx)
2933 return idx > 0 &&
2934 line[idx - 1] == '\\' &&
2935 !vshReadlineCharIsQuoted(line, idx - 1);
2939 # define HISTSIZE_MAX 500000
2941 static int
2942 vshReadlineInit(vshControl *ctl)
2944 g_autofree char *userdir = NULL;
2945 int max_history = 500;
2946 g_autofree char *histsize_env = NULL;
2947 const char *histsize_str = NULL;
2948 const char *break_characters = " \t\n`@$><=;|&{(";
2949 const char *quote_characters = "\"'";
2951 /* initialize readline stuff only once */
2952 if (ctl->historydir)
2953 return 0;
2955 /* Opaque data for autocomplete callbacks. */
2956 autoCompleteOpaque = ctl;
2958 rl_readline_name = ctl->name;
2960 /* Tell the completer that we want a crack first. */
2961 rl_attempted_completion_function = vshReadlineCompletion;
2963 rl_basic_word_break_characters = break_characters;
2965 rl_completer_quote_characters = quote_characters;
2966 rl_char_is_quoted_p = vshReadlineCharIsQuoted;
2968 histsize_env = g_strdup_printf("%s_HISTSIZE", ctl->env_prefix);
2970 /* Limit the total size of the history buffer */
2971 if ((histsize_str = getenv(histsize_env))) {
2972 if (virStrToLong_i(histsize_str, NULL, 10, &max_history) < 0) {
2973 vshError(ctl, _("Bad $%1$s value."), histsize_env);
2974 return -1;
2975 } else if (max_history > HISTSIZE_MAX || max_history < 0) {
2976 vshError(ctl, _("$%1$s value should be between 0 and %2$d"),
2977 histsize_env, HISTSIZE_MAX);
2978 return -1;
2981 stifle_history(max_history);
2983 /* Prepare to read/write history from/to the
2984 * $XDG_CACHE_HOME/virtshell/history file
2986 userdir = virGetUserCacheDirectory();
2988 ctl->historydir = g_strdup_printf("%s/%s", userdir, ctl->name);
2990 ctl->historyfile = g_strdup_printf("%s/history", ctl->historydir);
2992 read_history(ctl->historyfile);
2993 return 0;
2996 static void
2997 vshReadlineDeinit(vshControl *ctl)
2999 if (ctl->historyfile != NULL) {
3000 if (g_mkdir_with_parents(ctl->historydir, 0755) < 0 &&
3001 errno != EEXIST) {
3002 vshError(ctl, _("Failed to create '%1$s': %2$s"),
3003 ctl->historydir, g_strerror(errno));
3004 } else {
3005 write_history(ctl->historyfile);
3009 g_clear_pointer(&ctl->historydir, g_free);
3010 g_clear_pointer(&ctl->historyfile, g_free);
3013 char *
3014 vshReadline(vshControl *ctl G_GNUC_UNUSED, const char *prompt)
3016 return readline(prompt);
3019 void
3020 vshReadlineHistoryAdd(const char *cmd)
3022 return add_history(cmd);
3025 #else /* !WITH_READLINE */
3027 static int
3028 vshReadlineInit(vshControl *ctl G_GNUC_UNUSED)
3030 /* empty */
3031 return 0;
3034 static void
3035 vshReadlineDeinit(vshControl *ctl G_GNUC_UNUSED)
3037 /* empty */
3040 char *
3041 vshReadline(vshControl *ctl G_GNUC_UNUSED,
3042 const char *prompt)
3044 char line[1024];
3045 char *r;
3046 int len;
3048 fputs(prompt, stdout);
3049 fflush(stdout);
3050 r = fgets(line, sizeof(line), stdin);
3051 if (r == NULL) return NULL; /* EOF */
3053 /* Chomp trailing \n */
3054 len = strlen(r);
3055 if (len > 0 && r[len-1] == '\n')
3056 r[len-1] = '\0';
3058 return g_strdup(r);
3061 void
3062 vshReadlineHistoryAdd(const char *cmd G_GNUC_UNUSED)
3064 /* empty */
3067 #endif /* !WITH_READLINE */
3070 * Initialize debug settings.
3072 static int
3073 vshInitDebug(vshControl *ctl)
3075 const char *debugEnv;
3077 if (ctl->debug == VSH_DEBUG_DEFAULT) {
3078 g_autofree char *env = g_strdup_printf("%s_DEBUG", ctl->env_prefix);
3080 /* log level not set from commandline, check env variable */
3081 debugEnv = getenv(env);
3082 if (debugEnv) {
3083 int debug;
3084 if (virStrToLong_i(debugEnv, NULL, 10, &debug) < 0 ||
3085 debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR) {
3086 vshError(ctl, _("%1$s_DEBUG not set with a valid numeric value"),
3087 ctl->env_prefix);
3088 } else {
3089 ctl->debug = debug;
3094 if (ctl->logfile == NULL) {
3095 g_autofree char *env = g_strdup_printf("%s_LOG_FILE", ctl->env_prefix);
3097 /* log file not set from cmdline */
3098 debugEnv = getenv(env);
3099 if (debugEnv && *debugEnv) {
3100 ctl->logfile = g_strdup(debugEnv);
3101 vshOpenLogFile(ctl);
3105 return 0;
3110 * Initialize global data
3112 bool
3113 vshInit(vshControl *ctl, const vshCmdGrp *groups)
3115 if (!ctl->hooks) {
3116 vshError(ctl, "%s", _("client hooks cannot be NULL"));
3117 return false;
3120 if (!groups) {
3121 vshError(ctl, "%s", _("command groups must be non-NULL"));
3122 return false;
3125 cmdGroups = groups;
3127 if (vshInitDebug(ctl) < 0 ||
3128 (ctl->imode && vshReadlineInit(ctl) < 0))
3129 return false;
3131 return true;
3134 bool
3135 vshInitReload(vshControl *ctl)
3137 if (!cmdGroups) {
3138 vshError(ctl, "%s", _("command groups is NULL run vshInit before reloading"));
3139 return false;
3142 if (vshInitDebug(ctl) < 0)
3143 return false;
3145 if (ctl->imode)
3146 vshReadlineDeinit(ctl);
3147 if (ctl->imode && vshReadlineInit(ctl) < 0)
3148 return false;
3150 return true;
3153 void
3154 vshDeinit(vshControl *ctl)
3156 /* NB: Don't make calling of vshReadlineDeinit conditional on active
3157 * interactive mode. */
3158 vshReadlineDeinit(ctl);
3159 vshCloseLogFile(ctl);
3162 /* -----------------------------------------------
3163 * Generic commands available to use by any client
3164 * -----------------------------------------------
3167 static char **
3168 vshCompleteHelpCommand(vshControl *ctl G_GNUC_UNUSED,
3169 const vshCmd *cmd G_GNUC_UNUSED,
3170 unsigned int completerflags G_GNUC_UNUSED)
3172 return vshReadlineCommandGenerator();
3176 const vshCmdOptDef opts_help[] = {
3177 {.name = "command",
3178 .type = VSH_OT_STRING,
3179 .positional = true,
3180 .completer = vshCompleteHelpCommand,
3181 .help = N_("Prints global help, command specific help, or help for a group of related commands")
3183 {.name = NULL}
3186 const vshCmdInfo info_help = {
3187 .help = N_("print help"),
3188 .desc = N_("Prints global help, command specific help, or help for a\n"
3189 " group of related commands"),
3192 bool
3193 cmdHelp(vshControl *ctl, const vshCmd *cmd)
3195 const vshCmdDef *def = NULL;
3196 const vshCmdGrp *grp = NULL;
3197 const char *name = NULL;
3199 if (vshCommandOptStringQuiet(ctl, cmd, "command", &name) <= 0) {
3200 vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
3202 for (grp = cmdGroups; grp->name; grp++) {
3203 vshPrint(ctl, _(" %1$s (help keyword '%2$s'):\n"), grp->name,
3204 grp->keyword);
3206 for (def = grp->commands; def->name; def++) {
3207 if (def->alias ||
3208 def->flags & VSH_CMD_FLAG_HIDDEN)
3209 continue;
3210 vshPrint(ctl, " %-30s %s\n", def->name, _(def->info->help));
3213 vshPrint(ctl, "\n");
3216 return true;
3219 if ((def = vshCmddefSearch(name))) {
3220 if (def->alias)
3221 def = vshCmddefSearch(def->alias);
3224 if (def) {
3225 return vshCmddefHelp(def);
3226 } else if ((grp = vshCmdGrpSearch(name))) {
3227 return vshCmdGrpHelp(ctl, grp);
3228 } else {
3229 vshError(ctl, _("command or command group '%1$s' doesn't exist"), name);
3230 return false;
3234 const vshCmdOptDef opts_cd[] = {
3235 {.name = "dir",
3236 .type = VSH_OT_STRING,
3237 .positional = true,
3238 .help = N_("directory to switch to (default: home or else root)")
3240 {.name = NULL}
3243 const vshCmdInfo info_cd = {
3244 .help = N_("change the current directory"),
3245 .desc = N_("Change the current directory."),
3248 bool
3249 cmdCd(vshControl *ctl, const vshCmd *cmd)
3251 const char *dir = NULL;
3252 g_autofree char *dir_malloced = NULL;
3254 if (vshCommandOptStringQuiet(ctl, cmd, "dir", &dir) <= 0)
3255 dir = dir_malloced = virGetUserDirectory();
3256 if (!dir)
3257 dir = "/";
3259 if (chdir(dir) == -1) {
3260 vshError(ctl, _("cd: %1$s: %2$s"),
3261 g_strerror(errno), dir);
3262 return false;
3265 return true;
3268 const vshCmdOptDef opts_echo[] = {
3269 {.name = "shell",
3270 .type = VSH_OT_BOOL,
3271 .help = N_("escape for shell use")
3273 {.name = "xml",
3274 .type = VSH_OT_BOOL,
3275 .help = N_("escape for XML use")
3277 {.name = "split",
3278 .type = VSH_OT_BOOL,
3279 .help = N_("split each argument on ','; ',,' is an escape sequence")
3281 {.name = "err",
3282 .type = VSH_OT_BOOL,
3283 .help = N_("output to stderr"),
3285 {.name = "str",
3286 .type = VSH_OT_ALIAS,
3287 .help = "string"
3289 {.name = "hi",
3290 .type = VSH_OT_ALIAS,
3291 .help = "string=hello"
3293 {.name = "prefix",
3294 .type = VSH_OT_STRING,
3295 .help = N_("prefix the message")
3297 {.name = "string",
3298 .type = VSH_OT_ARGV,
3299 .positional = true,
3300 .help = N_("arguments to echo")
3302 {.name = NULL}
3305 const vshCmdInfo info_echo = {
3306 .help = N_("echo arguments. Used for internal testing."),
3307 .desc = N_("Echo back arguments, possibly with quoting. Used for internal testing."),
3310 /* Exists mainly for debugging virsh, but also handy for adding back
3311 * quotes for later evaluation.
3313 bool
3314 cmdEcho(vshControl *ctl, const vshCmd *cmd)
3316 bool shell = vshCommandOptBool(cmd, "shell");
3317 bool xml = vshCommandOptBool(cmd, "xml");
3318 bool err = vshCommandOptBool(cmd, "err");
3319 bool split = vshCommandOptBool(cmd, "split");
3320 const char *prefix;
3321 g_autofree char *arg = NULL;
3322 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
3323 const char **o;
3325 VSH_EXCLUSIVE_OPTIONS_VAR(shell, xml);
3326 VSH_EXCLUSIVE_OPTIONS_VAR(shell, split);
3327 VSH_EXCLUSIVE_OPTIONS_VAR(xml, split);
3329 ignore_value(vshCommandOptString(ctl, cmd, "prefix", &prefix));
3331 if (prefix)
3332 virBufferAsprintf(&buf, "%s ", prefix);
3334 for (o = vshCommandOptArgv(cmd, "string"); o && *o; o++) {
3335 const char *curr = *o;
3337 if (xml) {
3338 virBufferEscapeString(&buf, "%s", curr);
3339 } else if (shell) {
3340 virBufferEscapeShell(&buf, curr);
3341 } else if (split) {
3342 g_auto(GStrv) spl = NULL;
3343 GStrv n;
3345 vshStringToArray(curr, &spl);
3347 for (n = spl; *n; n++)
3348 virBufferAsprintf(&buf, "%s\n", *n);
3349 } else {
3350 virBufferAdd(&buf, curr, -1);
3353 virBufferAddChar(&buf, ' ');
3356 virBufferTrim(&buf, " ");
3358 arg = virBufferContentAndReset(&buf);
3359 if (arg) {
3360 if (err)
3361 vshError(ctl, "%s", arg);
3362 else
3363 vshPrint(ctl, "%s", arg);
3365 return true;
3368 const vshCmdInfo info_pwd = {
3369 .help = N_("print the current directory"),
3370 .desc = N_("Print the current directory."),
3373 bool
3374 cmdPwd(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
3376 g_autofree char *cwd = g_get_current_dir();
3378 vshPrint(ctl, _("%1$s\n"), cwd);
3380 return true;
3383 const vshCmdInfo info_quit = {
3384 .help = N_("quit this interactive terminal"),
3385 .desc = "",
3388 bool
3389 cmdQuit(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
3391 ctl->imode = false;
3392 return true;
3395 /* -----------------
3396 * Command self-test
3397 * ----------------- */
3399 const vshCmdOptDef opts_selftest[] = {
3400 {.name = "completers-missing",
3401 .type = VSH_OT_BOOL,
3402 .help = N_("output the list of options which are missing completers")
3404 {.name = "dump-help",
3405 .type = VSH_OT_BOOL,
3406 .help = N_("output help for each command")
3408 {.name = NULL}
3410 const vshCmdInfo info_selftest = {
3411 .help = N_("internal command for testing virt shells"),
3412 .desc = N_("internal use only"),
3415 bool
3416 cmdSelfTest(vshControl *ctl, const vshCmd *cmd)
3418 const vshCmdGrp *grp;
3419 const vshCmdDef *def;
3420 bool completers = vshCommandOptBool(cmd, "completers-missing");
3421 bool dumphelp = vshCommandOptBool(cmd, "dump-help");
3423 for (grp = cmdGroups; grp->name; grp++) {
3424 for (def = grp->commands; def->name; def++) {
3426 if (dumphelp && !def->alias)
3427 vshCmddefHelp(def);
3429 if (vshCmddefCheckInternals(ctl, def, completers) < 0)
3430 return false;
3434 return true;
3437 /* ----------------------
3438 * Autocompletion command
3439 * ---------------------- */
3441 const vshCmdOptDef opts_complete[] = {
3442 {.name = "string",
3443 .type = VSH_OT_ARGV,
3444 .positional = true,
3445 .allowEmpty = true,
3446 .help = N_("partial string to autocomplete")
3448 {.name = NULL}
3451 const vshCmdInfo info_complete = {
3452 .help = N_("internal command for autocompletion"),
3453 .desc = N_("internal use only"),
3457 #ifdef WITH_READLINE
3459 static virOnceControl vshCmdCompleteCloseStdinOnce = VIR_ONCE_CONTROL_INITIALIZER;
3461 static void
3462 vshCmdCompleteCloseStdin(void)
3464 /* In non-interactive mode which is how the 'complete' command is intended
3465 * to be used we need to ensure that any authentication callback will not
3466 * attempt to read any input which would break the completion */
3467 int stdin_fileno = STDIN_FILENO;
3469 VIR_FORCE_CLOSE(stdin_fileno);
3473 bool
3474 cmdComplete(vshControl *ctl, const vshCmd *cmd)
3476 const vshClientHooks *hooks = ctl->hooks;
3477 const char *lastArg = NULL;
3478 const char **args = NULL;
3479 g_auto(GStrv) matches = NULL;
3480 char **iter;
3482 /* The completer needs also the last component */
3483 for (args = vshCommandOptArgv(cmd, "string"); args && *args; args++)
3484 lastArg = *args;
3486 /* This command is flagged VSH_CMD_FLAG_NOCONNECT because we
3487 * need to prevent auth hooks reading any input. Therefore, we
3488 * have to close stdin and then connect ourselves. */
3489 if (!ctl->imode) {
3490 if (virOnce(&vshCmdCompleteCloseStdinOnce, vshCmdCompleteCloseStdin) < 0)
3491 return false;
3494 if (!(hooks && hooks->connHandler && hooks->connHandler(ctl)))
3495 return false;
3497 vshReadlineInit(ctl);
3499 if (!(rl_line_buffer = g_strdup(vshCommandOptArgvString(cmd, "string"))))
3500 rl_line_buffer = g_strdup("");
3502 /* rl_point is current cursor position in rl_line_buffer.
3503 * In our case it's at the end of the whole line. */
3504 rl_point = strlen(rl_line_buffer);
3506 matches = vshReadlineCompletion(lastArg, 0, 0);
3507 g_clear_pointer(&rl_line_buffer, g_free);
3509 if (!matches)
3510 return false;
3512 for (iter = matches; *iter; iter++) {
3513 if (iter == matches && matches[1])
3514 continue;
3515 printf("%s\n", *iter);
3518 return true;
3522 #else /* !WITH_READLINE */
3525 bool
3526 cmdComplete(vshControl *ctl G_GNUC_UNUSED,
3527 const vshCmd *cmd G_GNUC_UNUSED)
3529 return false;
3531 #endif /* !WITH_READLINE */