1 /* guestfish - the filesystem interactive shell
2 * Copyright (C) 2011 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <sys/types.h>
37 /* The hash table maps names to multiple (linked list of) event handlers. */
38 static Hash_table *event_handlers;
41 struct entry *next; /* Next entry in linked list. */
42 char *name; /* Event name. */
43 char *command; /* Shell script / command that runs. */
44 uint64_t event_bitmask; /* Events this is registered for. */
45 int eh; /* Event handle (from guestfs_set_event_callback). */
61 entry_hash (void const *x, size_t table_size)
63 struct entry const *p = x;
64 return hash_pjw (p->name, table_size);
68 entry_compare (void const *x, void const *y)
70 struct entry const *p = x;
71 struct entry const *q = y;
72 return STREQ (p->name, q->name);
76 init_event_handlers (void)
78 assert (event_handlers == NULL);
80 hash_initialize (64, NULL, entry_hash, entry_compare, entry_free);
84 free_event_handlers (void)
86 assert (event_handlers != NULL);
87 hash_free (event_handlers);
88 event_handlers = NULL;
92 do_event_handler (guestfs_h *g,
97 const char *buf, size_t buf_len,
98 const uint64_t *array, size_t array_len)
101 const char *argv[8 + array_len];
103 struct entry *entry = opaque;
109 perror ("event handler: fork");
113 if (pid == 0) { /* Child process. */
114 shell = getenv ("SHELL");
118 setenv ("EVENT", event_name_of_event_bitmask (event), 1);
120 /* Construct the command and arguments. */
124 argv[i++] = entry->command;
125 argv[i++] = ""; /* $0 */
128 /* XXX: So far, buf is always ASCII NUL-terminated. There is no
129 * way to pass arbitrary 8 bit buffers.
133 for (j = 0; j < array_len; ++j) {
134 if (asprintf (&s, "%" PRIu64, array[j]) == -1) {
135 perror ("event handler: asprintf");
136 _exit (EXIT_FAILURE);
143 execvp (argv[0], (void *) argv);
146 _exit (EXIT_FAILURE);
149 if (waitpid (pid, NULL, 0) == -1)
150 perror ("event handler: waitpid");
154 run_event (const char *cmd, size_t argc, char *argv[])
157 struct entry *entry = NULL, *old_entry;
161 _("use 'event <name> <eventset> <script>' to register an event handler\n"));
165 entry = calloc (1, sizeof *entry);
172 r = event_bitmask_of_event_set (argv[1], &entry->event_bitmask);
176 entry->name = strdup (argv[0]);
177 if (entry->name == NULL) {
181 entry->command = strdup (argv[2]);
182 if (entry->command == NULL) {
188 guestfs_set_event_callback (g, do_event_handler,
189 entry->event_bitmask, 0, entry);
193 r = hash_insert_if_absent (event_handlers, entry, (const void **) &old_entry);
196 if (r == 0) { /* old_entry set to existing entry */
197 entry->next = old_entry->next;
198 /* XXX are we allowed to update the old entry? */
199 old_entry->next = entry;
207 guestfs_delete_event_callback (g, entry->eh);
209 free (entry->command);
216 run_delete_event (const char *cmd, size_t argc, char *argv[])
220 _("use 'delete-event <name>' to delete an event handler\n"));
224 const struct entry key = { .name = bad_cast (argv[0]) };
225 struct entry *entry, *p;
227 entry = hash_delete (event_handlers, &key);
229 fprintf (stderr, _("delete-event: %s: no such event handler\n"), argv[0]);
233 /* Delete them from the handle. */
236 guestfs_delete_event_callback (g, p->eh);
240 /* Free the structures. */
247 list_event (void *x, void *data)
249 struct entry *entry = x;
252 printf ("\"%s\" (%d): ", entry->name, entry->eh);
253 print_event_set (entry->event_bitmask, stdout);
254 printf (": %s\n", entry->command);
262 run_list_events (const char *cmd, size_t argc, char *argv[])
266 _("use 'list-events' to list event handlers\n"));
270 hash_do_for_each (event_handlers, list_event, NULL);