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 */
32 #include "ignore-value.h"
35 #include "guestfs-internal.h"
38 guestfs_set_event_callback (guestfs_h *g,
39 guestfs_event_callback cb,
40 uint64_t event_bitmask,
45 error (g, "flags parameter should be passed as 0 to this function");
49 /* We cast size_t to int which is not always safe for large numbers,
50 * and in any case if a program is registering a huge number of
51 * callbacks then we'd want to look at using an alternate data
52 * structure in place of a linear list.
54 if (g->nr_events >= 1000) {
55 error (g, "too many event callbacks registered");
59 int event_handle = (int) g->nr_events;
61 guestfs_safe_realloc (g, g->events,
62 (g->nr_events+1) * sizeof (struct event));
65 g->events[event_handle].event_bitmask = event_bitmask;
66 g->events[event_handle].cb = cb;
67 g->events[event_handle].opaque = opaque;
68 g->events[event_handle].opaque2 = NULL;
74 guestfs_delete_event_callback (guestfs_h *g, int event_handle)
76 if (event_handle < 0 || event_handle >= (int) g->nr_events)
79 /* Set the event_bitmask to 0, which will ensure that this callback
80 * cannot match any event and therefore cannot be called.
82 g->events[event_handle].event_bitmask = 0;
85 /* Functions to generate an event with various payloads. */
88 guestfs___call_callbacks_void (guestfs_h *g, uint64_t event)
92 for (i = 0; i < g->nr_events; ++i)
93 if ((g->events[i].event_bitmask & event) != 0)
94 g->events[i].cb (g, g->events[i].opaque, event, i, 0, NULL, 0, NULL, 0);
96 /* All events with payload type void are discarded if no callback
102 guestfs___call_callbacks_message (guestfs_h *g, uint64_t event,
103 const char *buf, size_t buf_len)
107 for (i = 0; i < g->nr_events; ++i)
108 if ((g->events[i].event_bitmask & event) != 0) {
109 g->events[i].cb (g, g->events[i].opaque, event, i, 0,
110 buf, buf_len, NULL, 0);
114 /* Emulate the old-style handlers. Callers can override
115 * print-on-stderr simply by registering a callback.
118 (event == GUESTFS_EVENT_APPLIANCE ||
119 event == GUESTFS_EVENT_LIBRARY ||
120 event == GUESTFS_EVENT_TRACE) &&
121 (g->verbose || event == GUESTFS_EVENT_TRACE)) {
122 int from_appliance = event == GUESTFS_EVENT_APPLIANCE;
126 /* APPLIANCE => <buf>
127 * LIBRARY => libguestfs: <buf>\n
128 * TRACE => libguestfs: trace: <buf>\n (RHBZ#673479)
131 if (event != GUESTFS_EVENT_APPLIANCE)
132 fputs ("libguestfs: ", stderr);
134 if (event == GUESTFS_EVENT_TRACE)
135 fputs ("trace: ", stderr);
137 /* Special or non-printing characters in the buffer must be
138 * escaped (RHBZ#731744). The buffer can contain any 8 bit
139 * character, even \0.
141 * Handling of \n and \r characters is complex:
143 * Case 1: Messages from the appliance: These messages already
144 * contain \n and \r characters at logical positions, so we just
145 * echo those out directly.
147 * Case 2: Messages from other sources: These messages should NOT
148 * contain \n or \r. If they do, it is escaped. However we also
149 * need to print a real end of line after these messages.
151 for (i = 0; i < buf_len; ++i) {
153 if (c_isprint (c) || (from_appliance && (c == '\n' || c == '\r')))
157 case '\0': fputs ("\\0", stderr); break;
158 case '\a': fputs ("\\a", stderr); break;
159 case '\b': fputs ("\\b", stderr); break;
160 case '\f': fputs ("\\f", stderr); break;
161 case '\n': fputs ("\\n", stderr); break;
162 case '\r': fputs ("\\r", stderr); break;
163 case '\t': fputs ("\\t", stderr); break;
164 case '\v': fputs ("\\v", stderr); break;
166 fprintf (stderr, "\\x%x", (unsigned) c);
177 guestfs___call_callbacks_array (guestfs_h *g, uint64_t event,
178 const uint64_t *array, size_t array_len)
182 for (i = 0; i < g->nr_events; ++i)
183 if ((g->events[i].event_bitmask & event) != 0)
184 g->events[i].cb (g, g->events[i].opaque, event, i, 0,
185 NULL, 0, array, array_len);
187 /* All events with payload type array are discarded if no callback
192 /* Emulate old-style callback API.
194 * There were no event handles, so multiple callbacks per event were
195 * not supported. Calling the same 'guestfs_set_*_callback' function
196 * would replace the existing event. Calling it with cb == NULL meant
197 * that the caller wanted to remove the callback.
201 replace_old_style_event_callback (guestfs_h *g,
202 guestfs_event_callback cb,
203 uint64_t event_bitmask,
209 /* Use 'cb' pointer as a sentinel to replace the existing callback
210 * for this event if one was registered previously. Else append a
214 for (i = 0; i < g->nr_events; ++i)
215 if (g->events[i].cb == cb) {
216 if (opaque2 == NULL) {
217 /* opaque2 (the original callback) is NULL, which in the
218 * old-style API meant remove the callback.
220 guestfs_delete_event_callback (g, i);
228 return; /* see above */
230 /* i == g->nr_events */
232 guestfs_safe_realloc (g, g->events,
233 (g->nr_events+1) * sizeof (struct event));
237 g->events[i].event_bitmask = event_bitmask;
238 g->events[i].cb = cb;
239 g->events[i].opaque = opaque;
240 g->events[i].opaque2 = opaque2;
244 log_message_callback_wrapper (guestfs_h *g,
249 const char *buf, size_t buf_len,
250 const uint64_t *array, size_t array_len)
252 guestfs_log_message_cb cb = g->events[event_handle].opaque2;
253 /* Note that the old callback declared the message buffer as
254 * (char *, int). I sure hope message buffers aren't too large
255 * and that callers aren't writing to them. XXX
257 cb (g, opaque, (char *) buf, (int) buf_len);
261 guestfs_set_log_message_callback (guestfs_h *g,
262 guestfs_log_message_cb cb, void *opaque)
264 replace_old_style_event_callback (g, log_message_callback_wrapper,
265 GUESTFS_EVENT_APPLIANCE,
270 subprocess_quit_callback_wrapper (guestfs_h *g,
275 const char *buf, size_t buf_len,
276 const uint64_t *array, size_t array_len)
278 guestfs_subprocess_quit_cb cb = g->events[event_handle].opaque2;
283 guestfs_set_subprocess_quit_callback (guestfs_h *g,
284 guestfs_subprocess_quit_cb cb, void *opaque)
286 replace_old_style_event_callback (g, subprocess_quit_callback_wrapper,
287 GUESTFS_EVENT_SUBPROCESS_QUIT,
292 launch_done_callback_wrapper (guestfs_h *g,
297 const char *buf, size_t buf_len,
298 const uint64_t *array, size_t array_len)
300 guestfs_launch_done_cb cb = g->events[event_handle].opaque2;
305 guestfs_set_launch_done_callback (guestfs_h *g,
306 guestfs_launch_done_cb cb, void *opaque)
308 replace_old_style_event_callback (g, launch_done_callback_wrapper,
309 GUESTFS_EVENT_LAUNCH_DONE,
314 close_callback_wrapper (guestfs_h *g,
319 const char *buf, size_t buf_len,
320 const uint64_t *array, size_t array_len)
322 guestfs_close_cb cb = g->events[event_handle].opaque2;
327 guestfs_set_close_callback (guestfs_h *g,
328 guestfs_close_cb cb, void *opaque)
330 replace_old_style_event_callback (g, close_callback_wrapper,
336 progress_callback_wrapper (guestfs_h *g,
341 const char *buf, size_t buf_len,
342 const uint64_t *array, size_t array_len)
344 guestfs_progress_cb cb = g->events[event_handle].opaque2;
345 assert (array_len >= 4);
346 cb (g, opaque, (int) array[0], (int) array[1], array[2], array[3]);
350 guestfs_set_progress_callback (guestfs_h *g,
351 guestfs_progress_cb cb, void *opaque)
353 replace_old_style_event_callback (g, progress_callback_wrapper,
354 GUESTFS_EVENT_PROGRESS,