From 7123f0cab155c5c25ecae670677683001c1634ad Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 14 Dec 2011 08:38:27 +0000 Subject: [PATCH] fish: Allow events to be processed in guestfish. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add 'event', 'list-events' and 'delete-event' commands so that event handlers can be registered, listed and deleted in guestfish. The event handler is a shell script snippet or host command. Cc: Pádraig Brady --- .gitignore | 1 + fish/Makefile.am | 2 + fish/events.c | 272 +++++++++++++++++++++++++++++++++++ fish/fish.c | 2 + fish/fish.h | 9 ++ fish/reopen.c | 7 + generator/.depend | 8 +- generator/generator_actions.ml | 50 +++++++ generator/generator_fish.ml | 91 ++++++++++++ generator/generator_main.ml | 1 + po/POTFILES.in | 2 + regressions/Makefile.am | 1 + regressions/test-guestfish-events.sh | 88 ++++++++++++ 13 files changed, 530 insertions(+), 4 deletions(-) create mode 100644 fish/events.c create mode 100755 regressions/test-guestfish-events.sh diff --git a/.gitignore b/.gitignore index 60ec817..aab6cd0 100644 --- a/.gitignore +++ b/.gitignore @@ -99,6 +99,7 @@ fish/cmds.c fish/cmds_gperf.c fish/cmds_gperf.gperf fish/completion.c +fish/event-names.c fish/fish-cmds.h fish/guestfish fish/guestfish.1 diff --git a/fish/Makefile.am b/fish/Makefile.am index 16a29b0..c940c2b 100644 --- a/fish/Makefile.am +++ b/fish/Makefile.am @@ -30,6 +30,7 @@ generator_built = \ cmds.c \ cmds_gperf.gperf \ completion.c \ + event-names.c \ fish-cmds.h \ guestfish-actions.pod \ guestfish-commands.pod \ @@ -81,6 +82,7 @@ guestfish_SOURCES = \ display.c \ echo.c \ edit.c \ + events.c \ fish.c \ fish.h \ glob.c \ diff --git a/fish/events.c b/fish/events.c new file mode 100644 index 0000000..1106372 --- /dev/null +++ b/fish/events.c @@ -0,0 +1,272 @@ +/* guestfish - the filesystem interactive shell + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hash.h" +#include "hash-pjw.h" + +#include "fish.h" + +/* The hash table maps names to multiple (linked list of) event handlers. */ +static Hash_table *event_handlers; + +struct entry { + struct entry *next; /* Next entry in linked list. */ + char *name; /* Event name. */ + char *command; /* Shell script / command that runs. */ + uint64_t event_bitmask; /* Events this is registered for. */ + int eh; /* Event handle (from guestfs_set_event_callback). */ +}; + +static void +entry_free (void *x) +{ + if (x) { + struct entry *p = x; + entry_free (p->next); + free (p->name); + free (p->command); + free (p); + } +} + +static size_t +entry_hash (void const *x, size_t table_size) +{ + struct entry const *p = x; + return hash_pjw (p->name, table_size); +} + +static bool +entry_compare (void const *x, void const *y) +{ + struct entry const *p = x; + struct entry const *q = y; + return STREQ (p->name, q->name); +} + +void +init_event_handlers (void) +{ + assert (event_handlers == NULL); + event_handlers = + hash_initialize (64, NULL, entry_hash, entry_compare, entry_free); +} + +void +free_event_handlers (void) +{ + assert (event_handlers != NULL); + hash_free (event_handlers); + event_handlers = NULL; +} + +static void +do_event_handler (guestfs_h *g, + void *opaque, + uint64_t event, + int event_handle, + int flags, + const char *buf, size_t buf_len, + const uint64_t *array, size_t array_len) +{ + pid_t pid; + const char *argv[8 + array_len]; + const char *shell; + struct entry *entry = opaque; + size_t i, j; + char *s; + + pid = fork (); + if (pid == -1) { + perror ("event handler: fork"); + return; + } + + if (pid == 0) { /* Child process. */ + shell = getenv ("SHELL"); + if (!shell) + shell = "/bin/sh"; + + setenv ("EVENT", event_name_of_event_bitmask (event), 1); + + /* Construct the command and arguments. */ + i = 0; + argv[i++] = shell; + argv[i++] = "-c"; + argv[i++] = entry->command; + argv[i++] = ""; /* $0 */ + + if (buf != NULL) + /* XXX: So far, buf is always ASCII NUL-terminated. There is no + * way to pass arbitrary 8 bit buffers. + */ + argv[i++] = buf; + + for (j = 0; j < array_len; ++j) { + if (asprintf (&s, "%" PRIu64, array[j]) == -1) { + perror ("event handler: asprintf"); + _exit (EXIT_FAILURE); + } + argv[i++] = s; + } + + argv[i++] = NULL; + + execvp (argv[0], (void *) argv); + perror (argv[0]); + + _exit (EXIT_FAILURE); + } + + if (waitpid (pid, NULL, 0) == -1) + perror ("event handler: waitpid"); +} + +int +run_event (const char *cmd, size_t argc, char *argv[]) +{ + int r; + struct entry *entry = NULL, *old_entry; + + if (argc != 3) { + fprintf (stderr, + _("use 'event