[PATCH v2 2/3] virhook: support hooks placed in several files

Michal Privoznik mprivozn at redhat.com
Tue Jun 23 16:38:41 UTC 2020


On 6/23/20 4:45 PM, Dmitry Nesterenko wrote:
> Signed-off-by: Dmitry Nesterenko <dmitry.nesterenko at virtuozzo.com>
> ---
>   src/util/virhook.c | 106 +++++++++++++++++++++++++++++++++++++++++----
>   1 file changed, 97 insertions(+), 9 deletions(-)
> 
> diff --git a/src/util/virhook.c b/src/util/virhook.c
> index 64ee9a2307..cd26c8c9bd 100644
> --- a/src/util/virhook.c
> +++ b/src/util/virhook.c
> @@ -33,6 +33,7 @@
>   #include "virfile.h"
>   #include "configmake.h"
>   #include "vircommand.h"
> +#include "virstring.h"
>   
>   #define VIR_FROM_THIS VIR_FROM_HOOK
>   
> @@ -141,7 +142,11 @@ static int virHooksFound = -1;
>   static int
>   virHookCheck(int no, const char *driver)
>   {
> +    int ret;
> +    DIR *dir;
> +    struct dirent *entry;
>       g_autofree char *path = NULL;
> +    g_autofree char *dir_path = NULL;
>   
>       if (driver == NULL) {
>           virReportError(VIR_ERR_INTERNAL_ERROR,
> @@ -158,16 +163,39 @@ virHookCheck(int no, const char *driver)
>   
>       if (!virFileExists(path)) {
>           VIR_DEBUG("No hook script %s", path);
> -        return 0;
> +    } else if (!virFileIsExecutable(path)) {
> +        VIR_WARN("Non-executable hook script %s", path);
> +    } else {
> +        VIR_DEBUG("Found hook script %s", path);
> +        return 1;
>       }
>   
> -    if (!virFileIsExecutable(path)) {
> -        VIR_WARN("Non-executable hook script %s", path);
> +    dir_path = g_strdup_printf("%s.d", path);
> +    if ((ret = virDirOpenIfExists(&dir, dir_path)) < 0)
> +        return -1;
> +
> +    if (!ret) {
> +        VIR_DEBUG("No hook script dir %s", dir_path);
>           return 0;
>       }
>   
> -    VIR_DEBUG("Found hook script %s", path);
> -    return 1;
> +    while ((ret = virDirRead(dir, &entry, dir_path)) > 0) {
> +        g_autofree char *entry_path = g_build_filename(dir_path,
> +                                                       entry->d_name,
> +                                                       NULL);
> +        if (!virFileIsExecutable(entry_path)) {
> +            VIR_WARN("Non-executable hook script %s", entry_path);
> +            continue;
> +        }
> +
> +        VIR_DEBUG("Found hook script %s", entry_path);
> +        ret = 1;
> +        break;
> +    }
> +
> +    VIR_DIR_CLOSE(dir);
> +
> +    return ret;
>   }
>   
>   /*
> @@ -282,7 +310,7 @@ virRunScript(const char *path,
>    * @input: extra input given to the script on stdin
>    * @output: optional address of variable to store malloced result buffer
>    *
> - * Implement a hook call, where the external script for the driver is
> + * Implement a hook call, where the external scripts for the driver is

s/is/are/

>    * called with the given information. This is a synchronous call, we wait for
>    * execution completion. If @output is non-NULL, *output is guaranteed to be
>    * allocated after successful virHookCall, and is best-effort allocated after

I'm documenting the $driver.d/ directory and the output chaining.

> @@ -300,11 +328,16 @@ virHookCall(int driver,
>               const char *input,
>               char **output)
>   {
> +    int ret, script_ret;
> +    DIR *dir;
> +    struct dirent *entry;
>       g_autofree char *path = NULL;
> -    g_autoptr(virCommand) cmd = NULL;
> +    g_autofree char *dir_path = NULL;
> +    VIR_AUTOSTRINGLIST entries = NULL;
>       const char *drvstr;
>       const char *opstr;
>       const char *subopstr;
> +    size_t i, nentries;
>   
>       if (output)
>           *output = NULL;
> @@ -368,6 +401,61 @@ virHookCall(int driver,
>           return -1;
>       }
>   
> -    return virRunScript(path, id, opstr, subopstr, extra,
> -                        input, output);
> +    script_ret = 1;
> +
> +    if (virFileIsExecutable(path)) {
> +        script_ret = virRunScript(path, id, opstr, subopstr, extra,
> +                                  input, output);
> +    }
> +
> +    dir_path = g_strdup_printf("%s.d", path);
> +    if ((ret = virDirOpenIfExists(&dir, dir_path)) < 0)
> +        return -1;
> +
> +    if (!ret)
> +        return script_ret;
> +
> +    while ((ret = virDirRead(dir, &entry, dir_path)) > 0) {
> +        g_autofree char *entry_path = g_build_filename(dir_path,
> +                                                       entry->d_name,
> +                                                       NULL);
> +        if (!virFileIsExecutable(entry_path))
> +            continue;
> +
> +        virStringListAdd(&entries, entry_path);
> +    }
> +
> +    VIR_DIR_CLOSE(dir);
> +
> +    if (ret < 0)
> +        return -1;
> +
> +    if (!entries)
> +        return script_ret;
> +
> +    nentries = virStringListLength((const char **)entries);
> +    qsort(entries, nentries, sizeof(*entries), virStringSortCompare);
> +
> +    for (i = 0; i < nentries; i++) {
> +        int entry_ret;
> +        char *entry_input;
> +        g_autofree char *entry_output = NULL;
> +
> +        /* Get input from previous output */
> +        entry_input = (!script_ret && output &&
> +                       !virStringIsEmpty(*output)) ? *output : (char *)input;

How about making entry_input const char* instead of typecast?

> +        entry_ret = virRunScript(entries[i], id, opstr,
> +                                 subopstr, extra, entry_input,
> +                                 (output) ? &entry_output : NULL);
> +        if (entry_ret < script_ret)
> +            script_ret = entry_ret;
> +
> +        /* Replace output to new output from item */
> +        if (!entry_ret && output && !virStringIsEmpty(entry_output)) {
> +            g_free(*output);
> +            *output = g_steal_pointer(&entry_output);
> +        }
> +    }
> +
> +    return script_ret;
>   }
> 

Michal




More information about the libvir-list mailing list