[libvirt] [PATCH 2/8] virsh: Add vshDomainCompleter

Michal Privoznik mprivozn at redhat.com
Mon Aug 19 14:45:07 UTC 2013


On 08.08.2013 16:38, Tomas Meszaros wrote:
> Function vshDomainCompler returns domains names.
> 
> Michal Privoznik recommended to add global variable __my_conn
> so we can get the list of domains from the virConnecTListAllDomains().
> 
> vshReconnect() is called before the first command is executed
> in order to provide autocompletion for the very first command.
> ---
>  tools/virsh.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/virsh.h |  2 ++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/tools/virsh.c b/tools/virsh.c
> index f65dc79..af31b9a 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -88,6 +88,8 @@ static char *progname;
>  
>  static const vshCmdGrp cmdGroups[];
>  
> +virConnectPtr *__my_conn;
> +

Sigh. Unfortunately, we can't tunnel a pointer into readline's
callbacks. While I hate global variables, this one makes sense.

>  /* Bypass header poison */
>  #undef strdup
>  
> @@ -2502,6 +2504,51 @@ vshCloseLogFile(vshControl *ctl)
>  
>  #ifdef USE_READLINE
>  
> +/* -------------
> + * Completers
> + * -------------
> + */
> +
> +char **
> +vshDomainCompleter(unsigned int flags)
> +{
> +    virDomainPtr *domains;
> +    size_t i;
> +    char **names = NULL;
> +    int ndomains;
> +
> +    if (!*__my_conn)
> +        return NULL;
> +
> +    ndomains = virConnectListAllDomains(*__my_conn, &domains, flags);
> +
> +    if (ndomains < 0)
> +        return NULL;
> +
> +    names = vshMalloc(NULL, sizeof(char *) * (ndomains + 1));
> +
> +    if (!names)
> +        return NULL;

if vshMalloc fails, you leak domains[].

> +
> +    for (i = 0; i < ndomains; i++) {
> +        char *name = (char *)virDomainGetName(domains[i]);

what about making @name const char *?

> +        if (VIR_STRDUP(names[i], name) < 0) {
> +            virDomainFree(domains[i]);
> +            goto cleanup;
> +        }
> +        virDomainFree(domains[i]);
> +    }
> +    names[i] = NULL;
> +    VIR_FREE(domains);
> +    return names;
> +
> +cleanup:

This should be rather error: as the path is not common for success and
fail cases. The path is taken only on error.

> +    for (i = 0; names[i]; i++)
> +        VIR_FREE(names[i]);
> +    VIR_FREE(names);
> +    return NULL;
> +}
> +
>  /* -----------------
>   * Readline stuff
>   * -----------------
> @@ -3158,6 +3205,7 @@ main(int argc, char **argv)
>      ctl->debug = VSH_DEBUG_DEFAULT;
>      ctl->escapeChar = "^]";     /* Same default as telnet */
>  
> +    __my_conn = &ctl->conn;
>  
>      if (!setlocale(LC_ALL, "")) {
>          perror("setlocale");
> @@ -3219,6 +3267,11 @@ main(int argc, char **argv)
>              exit(EXIT_FAILURE);
>          }
>  
> +        /* Need to connect immediately after start in order to provide
> +         * autocompletion for the very first command.
> +         */
> +        vshReconnect(ctl);
> +
>          do {
>              const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
>              ctl->cmdstr =
> diff --git a/tools/virsh.h b/tools/virsh.h
> index e07b546..c4a9c13 100644
> --- a/tools/virsh.h
> +++ b/tools/virsh.h
> @@ -254,6 +254,8 @@ struct _vshCmdGrp {
>      const vshCmdDef *commands;
>  };
>  
> +char **vshDomainCompleter(unsigned int flags);
> +
>  void vshError(vshControl *ctl, const char *format, ...)
>      ATTRIBUTE_FMT_PRINTF(2, 3);
>  void vshOpenLogFile(vshControl *ctl);
> 

Michal




More information about the libvir-list mailing list