2 * Copyright (C) 2011 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #define _BSD_SOURCE /* for mkdtemp, usleep */
31 #include "ignore-value.h"
34 #include "guestfs-internal.h"
37 guestfs_set_event_callback (guestfs_h *g,
38 guestfs_event_callback cb,
39 uint64_t event_bitmask,
44 error (g, "flags parameter should be passed as 0 to this function");
48 /* We cast size_t to int which is not always safe for large numbers,
49 * and in any case if a program is registering a huge number of
50 * callbacks then we'd want to look at using an alternate data
51 * structure in place of a linear list.
53 if (g->nr_events >= 1000) {
54 error (g, "too many event callbacks registered");
58 int event_handle = (int) g->nr_events;
60 guestfs_safe_realloc (g, g->events,
61 (g->nr_events+1) * sizeof (struct event));
64 g->events[event_handle].event_bitmask = event_bitmask;
65 g->events[event_handle].cb = cb;
66 g->events[event_handle].opaque = opaque;
67 g->events[event_handle].opaque2 = NULL;
73 guestfs_delete_event_callback (guestfs_h *g, int event_handle)
75 if (event_handle < 0 || event_handle >= (int) g->nr_events)
78 /* Set the event_bitmask to 0, which will ensure that this callback
79 * cannot match any event and therefore cannot be called.
81 g->events[event_handle].event_bitmask = 0;
84 /* Functions to generate an event with various payloads. */
87 guestfs___call_callbacks_void (guestfs_h *g, uint64_t event)
91 for (i = 0; i < g->nr_events; ++i)
92 if ((g->events[i].event_bitmask & event) != 0)
93 g->events[i].cb (g, g->events[i].opaque, event, i, 0, NULL, 0, NULL, 0);
95 /* All events with payload type void are discarded if no callback
101 guestfs___call_callbacks_message (guestfs_h *g, uint64_t event,
102 const char *buf, size_t buf_len)
106 for (i = 0; i < g->nr_events; ++i)
107 if ((g->events[i].event_bitmask & event) != 0) {
108 g->events[i].cb (g, g->events[i].opaque, event, i, 0,
109 buf, buf_len, NULL, 0);
113 /* If nothing was registered and we're verbose or tracing, then we
114 * print the message on stderr. This essentially emulates the
115 * behaviour of the old-style handlers, while allowing callers to
116 * override print-on-stderr simply by registering a callback.
118 if (count == 0 && (g->verbose || event == GUESTFS_EVENT_TRACE)) {
119 const char *prefix = "libguestfs: ";
120 const char *trace = "trace: ";
121 const char *nl = "\n";
123 /* APPLIANCE => <buf>
124 * LIBRARY => libguestfs: <buf>\n
125 * TRACE => libguestfs: trace: <buf>\n (RHBZ#673479)
128 if (event != GUESTFS_EVENT_APPLIANCE)
129 ignore_value (write (STDERR_FILENO, prefix, strlen (prefix)));
131 if (event == GUESTFS_EVENT_TRACE)
132 ignore_value (write (STDERR_FILENO, trace, strlen (trace)));
134 ignore_value (write (STDERR_FILENO, buf, buf_len));
136 /* Messages from the appliance already contain \n characters, others
137 * need this to be appended.
139 if (event != GUESTFS_EVENT_APPLIANCE)
140 ignore_value (write (STDERR_FILENO, nl, strlen (nl)));
145 guestfs___call_callbacks_array (guestfs_h *g, uint64_t event,
146 const uint64_t *array, size_t array_len)
150 for (i = 0; i < g->nr_events; ++i)
151 if ((g->events[i].event_bitmask & event) != 0)
152 g->events[i].cb (g, g->events[i].opaque, event, i, 0,
153 NULL, 0, array, array_len);
155 /* All events with payload type array are discarded if no callback
160 /* Emulate old-style callback API.
162 * There were no event handles, so multiple callbacks per event were
163 * not supported. Calling the same 'guestfs_set_*_callback' function
164 * would replace the existing event. Calling it with cb == NULL meant
165 * that the caller wanted to remove the callback.
169 replace_old_style_event_callback (guestfs_h *g,
170 guestfs_event_callback cb,
171 uint64_t event_bitmask,
177 /* Use 'cb' pointer as a sentinel to replace the existing callback
178 * for this event if one was registered previously. Else append a
182 for (i = 0; i < g->nr_events; ++i)
183 if (g->events[i].cb == cb) {
184 if (opaque2 == NULL) {
185 /* opaque2 (the original callback) is NULL, which in the
186 * old-style API meant remove the callback.
188 guestfs_delete_event_callback (g, i);
196 return; /* see above */
198 /* i == g->nr_events */
200 guestfs_safe_realloc (g, g->events,
201 (g->nr_events+1) * sizeof (struct event));
205 g->events[i].event_bitmask = event_bitmask;
206 g->events[i].cb = cb;
207 g->events[i].opaque = opaque;
208 g->events[i].opaque2 = opaque2;
212 log_message_callback_wrapper (guestfs_h *g,
217 const char *buf, size_t buf_len,
218 const uint64_t *array, size_t array_len)
220 guestfs_log_message_cb cb = g->events[event_handle].opaque2;
221 /* Note that the old callback declared the message buffer as
222 * (char *, int). I sure hope message buffers aren't too large
223 * and that callers aren't writing to them. XXX
225 cb (g, opaque, (char *) buf, (int) buf_len);
229 guestfs_set_log_message_callback (guestfs_h *g,
230 guestfs_log_message_cb cb, void *opaque)
232 replace_old_style_event_callback (g, log_message_callback_wrapper,
233 GUESTFS_EVENT_APPLIANCE,
238 subprocess_quit_callback_wrapper (guestfs_h *g,
243 const char *buf, size_t buf_len,
244 const uint64_t *array, size_t array_len)
246 guestfs_subprocess_quit_cb cb = g->events[event_handle].opaque2;
251 guestfs_set_subprocess_quit_callback (guestfs_h *g,
252 guestfs_subprocess_quit_cb cb, void *opaque)
254 replace_old_style_event_callback (g, subprocess_quit_callback_wrapper,
255 GUESTFS_EVENT_SUBPROCESS_QUIT,
260 launch_done_callback_wrapper (guestfs_h *g,
265 const char *buf, size_t buf_len,
266 const uint64_t *array, size_t array_len)
268 guestfs_launch_done_cb cb = g->events[event_handle].opaque2;
273 guestfs_set_launch_done_callback (guestfs_h *g,
274 guestfs_launch_done_cb cb, void *opaque)
276 replace_old_style_event_callback (g, launch_done_callback_wrapper,
277 GUESTFS_EVENT_LAUNCH_DONE,
282 close_callback_wrapper (guestfs_h *g,
287 const char *buf, size_t buf_len,
288 const uint64_t *array, size_t array_len)
290 guestfs_close_cb cb = g->events[event_handle].opaque2;
295 guestfs_set_close_callback (guestfs_h *g,
296 guestfs_close_cb cb, void *opaque)
298 replace_old_style_event_callback (g, close_callback_wrapper,
304 progress_callback_wrapper (guestfs_h *g,
309 const char *buf, size_t buf_len,
310 const uint64_t *array, size_t array_len)
312 guestfs_progress_cb cb = g->events[event_handle].opaque2;
313 assert (array_len >= 4);
314 cb (g, opaque, (int) array[0], (int) array[1], array[2], array[3]);
318 guestfs_set_progress_callback (guestfs_h *g,
319 guestfs_progress_cb cb, void *opaque)
321 replace_old_style_event_callback (g, progress_callback_wrapper,
322 GUESTFS_EVENT_PROGRESS,