/* * vsh.h: common data to be used by clients to exercise the libvirt API * * Copyright (C) 2005, 2007-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * <http://www.gnu.org/licenses/>. */ #pragma once #include <stdarg.h> #ifndef WIN32 # include <termios.h> #endif #include "internal.h" #include "virthread.h" #define VIR_FROM_THIS VIR_FROM_NONE #define VSH_MAX_XML_FILE (10*1024*1024) #define VSH_MATCH(FLAG) (flags & (FLAG)) /** * The log configuration */ #define MSG_BUFFER 4096 #define DIR_MODE (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) /* 0755 */ #define FILE_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) /* 0644 */ #define LOCK_MODE (S_IWUSR | S_IRUSR) /* 0600 */ #define LVL_DEBUG "DEBUG" #define LVL_INFO "INFO" #define LVL_NOTICE "NOTICE" #define LVL_WARNING "WARNING" #define LVL_ERROR "ERROR" /** * vshErrorLevel: * * Indicates the level of a log message */ typedef enum { VSH_ERR_DEBUG = 0, VSH_ERR_INFO, VSH_ERR_NOTICE, VSH_ERR_WARNING, VSH_ERR_ERROR } vshErrorLevel; #define VSH_DEBUG_DEFAULT VSH_ERR_ERROR /* * virsh command line grammar: * * command_line = <command>\n | <command>; <command>; ... * * command = <keyword> <option> [--] <data> * * option = <bool_option> | <int_option> | <string_option> * data = <string> * * bool_option = --optionname * int_option = --optionname <number> | --optionname=<number> * string_option = --optionname <string> | --optionname=<string> * * keyword = [a-zA-Z][a-zA-Z-]* * number = [0-9]+ * string = ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+ * */ /* * vshCmdOptType - command option type */ typedef enum { VSH_OT_NONE = 0, /* cannary to catch programming errors */ VSH_OT_BOOL, /* optional boolean option */ VSH_OT_STRING, /* optional string option */ VSH_OT_INT, /* optional or mandatory int option */ VSH_OT_ARGV, /* remaining arguments */ VSH_OT_ALIAS, /* alternate spelling for a later argument */ } vshCmdOptType; /* forward declarations */ typedef struct _vshClientHooks vshClientHooks; typedef struct _vshCmd vshCmd; typedef struct _vshCmdDef vshCmdDef; typedef struct _vshCmdGrp vshCmdGrp; typedef struct _vshCmdInfo vshCmdInfo; typedef struct _vshCmdOpt vshCmdOpt; typedef struct _vshCmdOptDef vshCmdOptDef; typedef struct _vshControl vshControl; typedef char **(*vshCompleter)(vshControl *ctl, const vshCmd *cmd, unsigned int flags); /* * "help" - short description of command * "desc" - description of command, or empty string */ struct _vshCmdInfo { const char *help; /* short description of command */ const char *desc; /* description of command */ }; /* * vshCmdOptDef - command option definition */ struct _vshCmdOptDef { const char *name; /* the name of option, or NULL for list end */ vshCmdOptType type; /* option type */ bool required; /* option is required */ bool positional; /* option is a positional option (not requiring '--optionname') */ /* Historically the command parser in virsh allowed many optional arguments * which were documented as non-positional to be filled positionally. To * preserve this functionality those need to be annotated with the * 'unwanted_positional' flag. New options must not use this flag */ bool unwanted_positional; bool allowEmpty; /* allow empty string */ const char *help; /* non-NULL help string; or for VSH_OT_ALIAS * the name of a later public option */ vshCompleter completer; /* option completer */ unsigned int completer_flags; /* option completer flags */ }; /* * vshCmdOpt - command options * * After parsing a command, all arguments to the command have been * collected into a list of these objects. */ struct _vshCmdOpt { const vshCmdOptDef *def; /* non-NULL pointer to option definition */ bool present; /* true if option was present on command line */ char *data; /* allocated data, or NULL for bool option */ char **argv; /* for VSH_OT_ARGV, the list of options */ size_t nargv; char *argvstr; /* space-joined @argv */ }; /* * Command Usage Flags */ enum { VSH_CMD_FLAG_NOCONNECT = (1 << 0), /* no prior connection needed */ VSH_CMD_FLAG_HIDDEN = (1 << 1), /* command is hidden/internal */ }; /* * vshCmdDef - command definition */ struct _vshCmdDef { const char *name; /* name of command, or NULL for list end */ bool (*handler) (vshControl *, const vshCmd *); /* command handler */ const vshCmdOptDef *opts; /* definition of command options */ const vshCmdInfo *info; /* details about command */ unsigned int flags; /* bitwise OR of VSH_CMD_FLAG */ const char *alias; /* name of the aliased command */ }; /* * vshCmd - parsed command */ struct _vshCmd { const vshCmdDef *def; /* command definition */ vshCmdOpt *opts; /* list of command arguments */ vshCmdOpt *lastopt; /* last option of the commandline */ vshCmd *next; /* next command */ bool skipChecks; /* skip validity checks when retrieving opts */ bool helpOptionSeen; /* The '--help' option was seen when persing the command */ }; /* * vshControl */ struct _vshControl { const char *name; /* hardcoded name of the binary that cannot * be changed without recompilation compared * to program name */ const char *env_prefix; /* hardcoded environment variable prefix */ char *connname; /* connection name */ char *progname; /* program name */ vshCmd *cmd; /* the current command */ char *cmdstr; /* string with command */ bool imode; /* interactive mode? */ bool quiet; /* quiet mode */ bool timing; /* print timing info? */ int debug; /* print debug messages? */ char *logfile; /* log file name */ int log_fd; /* log file descriptor */ char *historydir; /* readline history directory name */ char *historyfile; /* readline history file name */ virThread eventLoop; virMutex lock; bool eventLoopStarted; bool quit; int eventPipe[2]; /* Write-to-self pipe to end waiting for an * event to occur */ int eventTimerId; /* id of event loop timeout registration */ int keepalive_interval; /* Client keepalive interval */ int keepalive_count; /* Client keepalive count */ #ifndef WIN32 struct termios termattr; /* settings of the tty terminal */ #endif bool istty; /* is the terminal a tty */ const vshClientHooks *hooks;/* mandatory client specific hooks */ void *privData; /* client specific data */ }; typedef void * (*vshConnectionHook)(vshControl *ctl); struct _vshClientHooks { vshConnectionHook connHandler; }; struct _vshCmdGrp { const char *name; /* name of group, or NULL for list end */ const char *keyword; /* help keyword */ const vshCmdDef *commands; }; void vshError(vshControl *ctl, const char *format, ...) G_GNUC_PRINTF(2, 3); void vshOpenLogFile(vshControl *ctl); void vshOutputLogFile(vshControl *ctl, int log_level, const char *format, va_list ap) G_GNUC_PRINTF(3, 0); void vshCloseLogFile(vshControl *ctl); int vshCommandOptInt(vshControl *ctl, const vshCmd *cmd, const char *name, int *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptUInt(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned int *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptUIntWrap(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned int *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptUL(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptULWrap(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptStringQuiet(vshControl *ctl, const vshCmd *cmd, const char *name, const char **value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptString(vshControl *ctl, const vshCmd *cmd, const char *name, const char **value) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptLongLong(vshControl *ctl, const vshCmd *cmd, const char *name, long long *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptULongLong(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long long *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptULongLongWrap(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long long *value) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshCommandOptScaledInt(vshControl *ctl, const vshCmd *cmd, const char *name, unsigned long long *value, int scale, unsigned long long max) ATTRIBUTE_NONNULL(4) G_GNUC_WARN_UNUSED_RESULT; int vshBlockJobOptionBandwidth(vshControl *ctl, const vshCmd *cmd, bool bytes, unsigned long *bandwidth); bool vshCommandOptBool(const vshCmd *cmd, const char *name); bool vshCommandRun(vshControl *ctl, const vshCmd *cmd); bool vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial); const char ** vshCommandOptArgv(const vshCmd *cmd, const char *name); const char * vshCommandOptArgvString(const vshCmd *cmd, const char *name); bool vshCommandArgvParse(vshControl *ctl, int nargs, char **argv); int vshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout); void vshPrintVa(vshControl *ctl, const char *format, va_list ap) G_GNUC_PRINTF(2, 0); void vshPrint(vshControl *ctl, const char *format, ...) G_GNUC_PRINTF(2, 3); void vshPrintExtra(vshControl *ctl, const char *format, ...) G_GNUC_PRINTF(2, 3); bool vshInit(vshControl *ctl, const vshCmdGrp *groups); bool vshInitReload(vshControl *ctl); void vshDeinit(vshControl *ctl); void vshDebug(vshControl *ctl, int level, const char *format, ...) G_GNUC_PRINTF(3, 4); /* User visible sort, so we want locale-specific case comparison. */ #define vshStrcasecmp(S1, S2) strcasecmp(S1, S2) int vshNameSorter(const void *a, const void *b); char *vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); double vshPrettyCapacity(unsigned long long val, const char **unit); int vshStringToArray(const char *str, char ***array); /* Given an index, return either the name of that device (non-NULL) or * of its parent (NULL if a root). */ typedef const char * (*vshTreeLookup)(int devid, bool parent, void *opaque); int vshTreePrint(vshControl *ctl, vshTreeLookup lookup, void *opaque, int num_devices, int devid); /* error handling */ extern virErrorPtr last_error; void vshErrorHandler(void *opaque, virErrorPtr error); void vshReportError(vshControl *ctl); void vshResetLibvirtError(void); void vshSaveLibvirtError(void); void vshSaveLibvirtHelperError(void); /* file handling */ void vshEditUnlinkTempfile(char *file); typedef char vshTempFile; G_DEFINE_AUTOPTR_CLEANUP_FUNC(vshTempFile, vshEditUnlinkTempfile); char *vshEditWriteToTempFile(vshControl *ctl, const char *doc); int vshEditFile(vshControl *ctl, const char *filename); char *vshEditReadBackFile(vshControl *ctl, const char *filename); int vshEditString(vshControl *ctl, char **output, const char *string); int vshAskReedit(vshControl *ctl, const char *msg, bool relax_avail); /* terminal modifications */ bool vshTTYIsInterruptCharacter(vshControl *ctl, const char chr); int vshTTYDisableInterrupt(vshControl *ctl); int vshTTYRestore(vshControl *ctl); int vshTTYMakeRaw(vshControl *ctl, bool report_errors); bool vshTTYAvailable(vshControl *ctl); /* waiting for events */ enum { VSH_EVENT_INTERRUPT, VSH_EVENT_TIMEOUT, VSH_EVENT_DONE, }; void vshEventCleanup(vshControl *ctl); void vshEventDone(vshControl *ctl); void vshEventLoop(void *opaque); int vshEventStart(vshControl *ctl, int timeout_ms); void vshEventTimeout(int timer, void *opaque); int vshEventWait(vshControl *ctl); /* generic commands */ extern const vshCmdOptDef opts_help[]; extern const vshCmdInfo info_help; extern const vshCmdOptDef opts_cd[]; extern const vshCmdInfo info_cd; extern const vshCmdOptDef opts_echo[]; extern const vshCmdInfo info_echo; extern const vshCmdInfo info_pwd; extern const vshCmdInfo info_quit; extern const vshCmdOptDef opts_selftest[]; extern const vshCmdInfo info_selftest; extern const vshCmdOptDef opts_complete[]; extern const vshCmdInfo info_complete; bool cmdHelp(vshControl *ctl, const vshCmd *cmd); bool cmdCd(vshControl *ctl, const vshCmd *cmd); bool cmdEcho(vshControl *ctl, const vshCmd *cmd); bool cmdPwd(vshControl *ctl, const vshCmd *cmd); bool cmdQuit(vshControl *ctl, const vshCmd *cmd); bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd); bool cmdComplete(vshControl *ctl, const vshCmd *cmd); #define VSH_CMD_CD \ { \ .name = "cd", \ .handler = cmdCd, \ .opts = opts_cd, \ .info = &info_cd, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_ECHO \ { \ .name = "echo", \ .handler = cmdEcho, \ .opts = opts_echo, \ .info = &info_echo, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_EXIT \ { \ .name = "exit", \ .handler = cmdQuit, \ .opts = NULL, \ .info = &info_quit, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_HELP \ { \ .name = "help", \ .handler = cmdHelp, \ .opts = opts_help, \ .info = &info_help, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_PWD \ { \ .name = "pwd", \ .handler = cmdPwd, \ .opts = NULL, \ .info = &info_pwd, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_QUIT \ { \ .name = "quit", \ .handler = cmdQuit, \ .opts = NULL, \ .info = &info_quit, \ .flags = VSH_CMD_FLAG_NOCONNECT \ } #define VSH_CMD_SELF_TEST \ { \ .name = "self-test", \ .handler = cmdSelfTest, \ .opts = opts_selftest, \ .info = &info_selftest, \ .flags = VSH_CMD_FLAG_NOCONNECT | VSH_CMD_FLAG_HIDDEN, \ } #define VSH_CMD_COMPLETE \ { \ .name = "complete", \ .handler = cmdComplete, \ .opts = opts_complete, \ .info = &info_complete, \ .flags = VSH_CMD_FLAG_NOCONNECT | VSH_CMD_FLAG_HIDDEN, \ } /* readline */ char * vshReadline(vshControl *ctl, const char *prompt); void vshReadlineHistoryAdd(const char *cmd); /* Macros to help dealing with mutually exclusive options. */ /* VSH_EXCLUSIVE_OPTIONS_EXPR: * * @NAME1: String containing the name of the option. * @EXPR1: Expression to validate the variable (boolean variable) * @NAME2: String containing the name of the option. * @EXPR2: Expression to validate the variable (boolean variable) * * Reject mutually exclusive command options in virsh. Use the * provided expression to check the variables. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, EXPR1, NAME2, EXPR2) \ if ((EXPR1) && (EXPR2)) { \ vshError(ctl, _("Options --%1$s and --%2$s are mutually exclusive"), \ NAME1, NAME2); \ return false; \ } /* VSH_EXCLUSIVE_OPTIONS: * * @NAME1: String containing the name of the option. * @NAME2: String containing the name of the option. * * Reject mutually exclusive command options in virsh. Use the * vshCommandOptBool call to request them. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_EXCLUSIVE_OPTIONS(NAME1, NAME2) \ VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, vshCommandOptBool(cmd, NAME1), \ NAME2, vshCommandOptBool(cmd, NAME2)) /* VSH_EXCLUSIVE_OPTIONS_VAR: * * @VARNAME1: Boolean variable containing the value of the option of same name * @VARNAME2: Boolean variable containing the value of the option of same name * * Reject mutually exclusive command options in virsh. Check in variables that * contain the value and have same name as the option. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_EXCLUSIVE_OPTIONS_VAR(VARNAME1, VARNAME2) \ VSH_EXCLUSIVE_OPTIONS_EXPR(#VARNAME1, VARNAME1, #VARNAME2, VARNAME2) /* Macros to help dealing with alternative mutually exclusive options. */ /* VSH_ALTERNATIVE_OPTIONS_EXPR: * * @NAME1: String containing the name of the option. * @EXPR1: Expression to validate the variable (must evaluate to bool). * @NAME2: String containing the name of the option. * @EXPR2: Expression to validate the variable (must evaluate to bool). * * Require exactly one of the command options in virsh. Use the provided * expression to check the variables. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_ALTERNATIVE_OPTIONS_EXPR(NAME1, EXPR1, NAME2, EXPR2) \ do { \ bool _expr1 = EXPR1; \ bool _expr2 = EXPR2; \ VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, _expr1, NAME2, _expr2); \ if (!_expr1 && !_expr2) { \ vshError(ctl, _("Either --%1$s or --%2$s must be provided"), \ NAME1, NAME2); \ return false; \ } \ } while (0) #define VSH_ALTERNATIVE_OPTIONS(NAME1, NAME2) \ VSH_ALTERNATIVE_OPTIONS_EXPR(NAME1, vshCommandOptBool(cmd, NAME1), \ NAME2, vshCommandOptBool(cmd, NAME2)) /* Macros to help dealing with required options. */ /* VSH_REQUIRE_OPTION_EXPR: * * @NAME1: String containing the name of the option. * @EXPR1: Expression to validate the variable (boolean variable). * @NAME2: String containing the name of required option. * @EXPR2: Expression to validate the variable (boolean variable). * * Check if required command options in virsh was set. Use the * provided expression to check the variables. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_REQUIRE_OPTION_EXPR(NAME1, EXPR1, NAME2, EXPR2) \ do { \ if ((EXPR1) && !(EXPR2)) { \ vshError(ctl, _("Option --%1$s is required by option --%2$s"), \ NAME2, NAME1); \ return false; \ } \ } while (0) /* VSH_REQUIRE_OPTION: * * @NAME1: String containing the name of the option. * @NAME2: String containing the name of required option. * * Check if required command options in virsh was set. Use the * vshCommandOptBool call to request them. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_REQUIRE_OPTION(NAME1, NAME2) \ VSH_REQUIRE_OPTION_EXPR(NAME1, vshCommandOptBool(cmd, NAME1), \ NAME2, vshCommandOptBool(cmd, NAME2)) /* VSH_REQUIRE_OPTION_VAR: * * @VARNAME1: Boolean variable containing the value of the option of same name. * @VARNAME2: Boolean variable containing the value of required option of * same name. * * Check if required command options in virsh was set. Check in variables * that contain the value and have same name as the option. * * This helper does an early return and therefore it has to be called * before anything that would require cleanup. */ #define VSH_REQUIRE_OPTION_VAR(VARNAME1, VARNAME2) \ VSH_REQUIRE_OPTION_EXPR(#VARNAME1, VARNAME1, #VARNAME2, VARNAME2)