diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-11-12 12:56:39 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-11-12 13:40:25 +0000 |
commit | 02ecd048d3caf7804361bb0f5dca071f97aefaa1 (patch) | |
tree | 2b17e6b2037297bc1bc93b4371be15a3b9d3aef6 | |
parent | f9ab256f0e4c1197b505b0249e66e7614644bd0b (diff) | |
download | libguestfs-02ecd048d3caf7804361bb0f5dca071f97aefaa1.tar.gz libguestfs-02ecd048d3caf7804361bb0f5dca071f97aefaa1.tar.xz libguestfs-02ecd048d3caf7804361bb0f5dca071f97aefaa1.zip |
lib: Split up huge src/guestfs.c into logical compilation units.
This file had grown by accretion to include:
- code related to handles (now in src/handle.c)
- safe allocation (src/alloc.c)
- debug, errors, warnings (src/errors.c)
- private data (src/private-data.c)
- miscellaneous functions (src/canonical-name.c, src/utils.c)
This commit also removes about a dozen #include files which were
probably not really used.
This is just code motion.
-rw-r--r-- | po/POTFILES | 7 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/alloc.c | 124 | ||||
-rw-r--r-- | src/canonical-name.c | 50 | ||||
-rw-r--r-- | src/errors.c | 282 | ||||
-rw-r--r-- | src/guestfs-internal.h | 39 | ||||
-rw-r--r-- | src/handle.c (renamed from src/guestfs.c) | 523 | ||||
-rw-r--r-- | src/private-data.c | 148 | ||||
-rw-r--r-- | src/utils.c | 36 |
9 files changed, 675 insertions, 541 deletions
diff --git a/po/POTFILES b/po/POTFILES index fcaa77ce..622c0158 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -225,18 +225,21 @@ src/actions-5.c src/actions-6.c src/actions-support.c src/actions-variants.c +src/alloc.c src/appliance.c src/bindtests.c +src/canonical-name.c src/command.c src/dbdump.c src/errnostring-gperf.c src/errnostring.c +src/errors.c src/events.c src/file.c src/filearch.c src/free-structs.c src/fuse.c -src/guestfs.c +src/handle.c src/info.c src/inspect-apps.c src/inspect-fs-cd.c @@ -253,8 +256,10 @@ src/libvirt-auth.c src/libvirt-domain.c src/listfs.c src/match.c +src/private-data.c src/proto.c src/tmpdirs.c +src/utils.c test-tool/test-tool.c tools/virt-list-filesystems.pl tools/virt-list-partitions.pl diff --git a/src/Makefile.am b/src/Makefile.am index 7b7f6065..d979e251 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,7 +126,6 @@ libguestfs_la_LDFLAGS = -version-info $(MAX_PROC_NR):0:$(MAX_PROC_NR) libguestfs_la_LDFLAGS += $(VERSION_SCRIPT_FLAGS)$(srcdir)/libguestfs.syms libguestfs_la_SOURCES = \ - guestfs.c \ guestfs.h \ guestfs-internal.h \ guestfs_protocol.h \ @@ -139,15 +138,19 @@ libguestfs_la_SOURCES = \ actions-6.c \ actions-support.c \ actions-variants.c \ + alloc.c \ appliance.c \ bindtests.c \ command.c \ + canonical-name.c \ dbdump.c \ + errors.c \ events.c \ file.c \ filearch.c \ free-structs.c \ fuse.c \ + handle.c \ info.c \ inspect.c \ inspect-apps.c \ @@ -164,8 +167,10 @@ libguestfs_la_SOURCES = \ libvirt-domain.c \ listfs.c \ match.c \ + private-data.c \ proto.c \ tmpdirs.c \ + utils.c \ libguestfs.syms libguestfs_la_LIBADD = \ diff --git a/src/alloc.c b/src/alloc.c new file mode 100644 index 00000000..dc64bbd8 --- /dev/null +++ b/src/alloc.c @@ -0,0 +1,124 @@ +/* libguestfs + * Copyright (C) 2009-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "guestfs.h" +#include "guestfs-internal.h" + +void * +guestfs_safe_malloc (guestfs_h *g, size_t nbytes) +{ + void *ptr = malloc (nbytes); + if (nbytes > 0 && !ptr) g->abort_cb (); + return ptr; +} + +/* Return 1 if an array of N objects, each of size S, cannot exist due + to size arithmetic overflow. S must be positive and N must be + nonnegative. This is a macro, not an inline function, so that it + works correctly even when SIZE_MAX < N. + + By gnulib convention, SIZE_MAX represents overflow in size + calculations, so the conservative dividend to use here is + SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. + However, malloc (SIZE_MAX) fails on all known hosts where + sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for + exactly-SIZE_MAX allocations on such hosts; this avoids a test and + branch when S is known to be 1. */ +# define xalloc_oversized(n, s) \ + ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) + +/* Technically we should add an autoconf test for this, testing for the desired + functionality, like what's done in gnulib, but for now, this is fine. */ +#if defined(__GLIBC__) +#define HAVE_GNU_CALLOC (__GLIBC__ >= 2) +#else +#define HAVE_GNU_CALLOC 0 +#endif + +/* Allocate zeroed memory for N elements of S bytes, with error + checking. S must be nonzero. */ +void * +guestfs_safe_calloc (guestfs_h *g, size_t n, size_t s) +{ + /* From gnulib's calloc function in xmalloc.c. */ + void *p; + /* Test for overflow, since some calloc implementations don't have + proper overflow checks. But omit overflow and size-zero tests if + HAVE_GNU_CALLOC, since GNU calloc catches overflow and never + returns NULL if successful. */ + if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) + || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) + g->abort_cb (); + return p; +} + +void * +guestfs_safe_realloc (guestfs_h *g, void *ptr, size_t nbytes) +{ + void *p = realloc (ptr, nbytes); + if (nbytes > 0 && !p) g->abort_cb (); + return p; +} + +char * +guestfs_safe_strdup (guestfs_h *g, const char *str) +{ + char *s = strdup (str); + if (!s) g->abort_cb (); + return s; +} + +char * +guestfs_safe_strndup (guestfs_h *g, const char *str, size_t n) +{ + char *s = strndup (str, n); + if (!s) g->abort_cb (); + return s; +} + +void * +guestfs_safe_memdup (guestfs_h *g, const void *ptr, size_t size) +{ + void *p = malloc (size); + if (!p) g->abort_cb (); + memcpy (p, ptr, size); + return p; +} + +char * +guestfs_safe_asprintf (guestfs_h *g, const char *fs, ...) +{ + va_list args; + char *msg; + + va_start (args, fs); + int err = vasprintf (&msg, fs, args); + va_end (args); + + if (err == -1) + g->abort_cb (); + + return msg; +} diff --git a/src/canonical-name.c b/src/canonical-name.c new file mode 100644 index 00000000..b7176072 --- /dev/null +++ b/src/canonical-name.c @@ -0,0 +1,50 @@ +/* libguestfs + * Copyright (C) 2009-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "guestfs.h" +#include "guestfs-internal.h" +#include "guestfs-internal-actions.h" + +char * +guestfs__canonical_device_name (guestfs_h *g, const char *device) +{ + char *ret; + + if (STRPREFIX (device, "/dev/hd") || + STRPREFIX (device, "/dev/vd")) { + ret = safe_strdup (g, device); + ret[5] = 's'; + } + else if (STRPREFIX (device, "/dev/mapper/") || + STRPREFIX (device, "/dev/dm-")) { + /* XXX hide errors */ + ret = guestfs_lvm_canonical_lv_name (g, device); + if (ret == NULL) + ret = safe_strdup (g, device); + } + else + ret = safe_strdup (g, device); + + return ret; /* caller frees */ +} diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 00000000..d12a4a3a --- /dev/null +++ b/src/errors.c @@ -0,0 +1,282 @@ +/* libguestfs + * Copyright (C) 2009-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +#include "c-ctype.h" + +#include "guestfs.h" +#include "guestfs-internal.h" + +const char * +guestfs_last_error (guestfs_h *g) +{ + return g->last_error; +} + +int +guestfs_last_errno (guestfs_h *g) +{ + return g->last_errnum; +} + +static void +set_last_error (guestfs_h *g, int errnum, const char *msg) +{ + free (g->last_error); + g->last_error = strdup (msg); + g->last_errnum = errnum; +} + +/* Warning are printed unconditionally. We try to make these rare. + * Generally speaking, a warning should either be an error, or if it's + * not important for end users then it should be a debug message. + */ +void +guestfs___warning (guestfs_h *g, const char *fs, ...) +{ + va_list args; + char *msg, *msg2; + int len; + + va_start (args, fs); + len = vasprintf (&msg, fs, args); + va_end (args); + + if (len < 0) return; + + len = asprintf (&msg2, _("warning: %s"), msg); + free (msg); + + if (len < 0) return; + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_LIBRARY, msg2, len); + + free (msg2); +} + +/* Debug messages. */ +void +guestfs___debug (guestfs_h *g, const char *fs, ...) +{ + va_list args; + char *msg; + int len; + + /* The cpp macro "debug" has already checked that g->verbose is true + * before calling this function, but we check it again just in case + * anyone calls this function directly. + */ + if (!g->verbose) + return; + + va_start (args, fs); + len = vasprintf (&msg, fs, args); + va_end (args); + + if (len < 0) return; + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_LIBRARY, msg, len); + + free (msg); +} + +/* Call trace messages. These are enabled by setting g->trace, and + * calls to this function should only happen from the generated code + * in src/actions.c + */ +void +guestfs___trace (guestfs_h *g, const char *fs, ...) +{ + va_list args; + char *msg; + int len; + + va_start (args, fs); + len = vasprintf (&msg, fs, args); + va_end (args); + + if (len < 0) return; + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_TRACE, msg, len); + + free (msg); +} + +void +guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...) +{ + va_list args; + char *msg; + + va_start (args, fs); + int err = vasprintf (&msg, fs, args); + va_end (args); + + if (err < 0) return; + + /* set_last_error first so that the callback can access the error + * message and errno through the handle if it wishes. + */ + set_last_error (g, errnum, msg); + if (g->error_cb) g->error_cb (g, g->error_cb_data, msg); + + free (msg); +} + +void +guestfs_perrorf (guestfs_h *g, const char *fs, ...) +{ + va_list args; + char *msg; + int errnum = errno; + + va_start (args, fs); + int err = vasprintf (&msg, fs, args); + va_end (args); + + if (err < 0) return; + + char buf[256]; + strerror_r (errnum, buf, sizeof buf); + + msg = safe_realloc (g, msg, strlen (msg) + 2 + strlen (buf) + 1); + strcat (msg, ": "); + strcat (msg, buf); + + /* set_last_error first so that the callback can access the error + * message and errno through the handle if it wishes. + */ + set_last_error (g, errnum, msg); + if (g->error_cb) g->error_cb (g, g->error_cb_data, msg); + + free (msg); +} + +void +guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb cb) +{ + g->abort_cb = cb; +} + +guestfs_abort_cb +guestfs_get_out_of_memory_handler (guestfs_h *g) +{ + return g->abort_cb; +} + +void +guestfs_set_error_handler (guestfs_h *g, + guestfs_error_handler_cb cb, void *data) +{ + g->error_cb = cb; + g->error_cb_data = data; +} + +guestfs_error_handler_cb +guestfs_get_error_handler (guestfs_h *g, void **data_rtn) +{ + if (data_rtn) *data_rtn = g->error_cb_data; + return g->error_cb; +} + +void +guestfs_push_error_handler (guestfs_h *g, + guestfs_error_handler_cb cb, void *data) +{ + struct error_cb_stack *old_stack; + + old_stack = g->error_cb_stack; + g->error_cb_stack = safe_malloc (g, sizeof (struct error_cb_stack)); + g->error_cb_stack->next = old_stack; + g->error_cb_stack->error_cb = g->error_cb; + g->error_cb_stack->error_cb_data = g->error_cb_data; + + guestfs_set_error_handler (g, cb, data); +} + +void +guestfs_pop_error_handler (guestfs_h *g) +{ + struct error_cb_stack *next_stack; + + if (g->error_cb_stack) { + next_stack = g->error_cb_stack->next; + guestfs_set_error_handler (g, g->error_cb_stack->error_cb, + g->error_cb_stack->error_cb_data); + free (g->error_cb_stack); + g->error_cb_stack = next_stack; + } + else + guestfs___init_error_handler (g); +} + +static void default_error_cb (guestfs_h *g, void *data, const char *msg); + +void +guestfs___init_error_handler (guestfs_h *g) +{ + g->error_cb = default_error_cb; + g->error_cb_data = NULL; +} + +static void +default_error_cb (guestfs_h *g, void *data, const char *msg) +{ + fprintf (stderr, _("libguestfs: error: %s\n"), msg); +} + +/* When tracing, be careful how we print BufferIn parameters which + * usually contain large amounts of binary data (RHBZ#646822). + */ +void +guestfs___print_BufferIn (FILE *out, const char *buf, size_t buf_size) +{ + size_t i; + size_t orig_size = buf_size; + + if (buf_size > 256) + buf_size = 256; + + fputc ('"', out); + + for (i = 0; i < buf_size; ++i) { + if (c_isprint (buf[i])) + fputc (buf[i], out); + else + fprintf (out, "\\x%02x", (unsigned char) buf[i]); + } + + fputc ('"', out); + + if (orig_size > buf_size) + fprintf (out, + _("<truncated, original size %zu bytes>"), orig_size); +} + +void +guestfs___print_BufferOut (FILE *out, const char *buf, size_t buf_size) +{ + guestfs___print_BufferIn (out, buf, buf_size); +} diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 4a12de76..6e0b3685 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -472,14 +472,7 @@ struct guestfs_message_header; struct guestfs_message_error; struct guestfs_progress; -/* guestfs.c */ -extern void guestfs_error (guestfs_h *g, const char *fs, ...) - __attribute__((format (printf,2,3))); -extern void guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...) - __attribute__((format (printf,3,4))); -extern void guestfs_perrorf (guestfs_h *g, const char *fs, ...) - __attribute__((format (printf,2,3))); - +/* alloc.c */ extern void *guestfs_safe_realloc (guestfs_h *g, void *ptr, size_t nbytes); extern char *guestfs_safe_strdup (guestfs_h *g, const char *str); extern char *guestfs_safe_strndup (guestfs_h *g, const char *str, size_t n); @@ -487,6 +480,24 @@ extern void *guestfs_safe_memdup (guestfs_h *g, const void *ptr, size_t size); extern char *guestfs_safe_asprintf (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3))); +#define safe_calloc guestfs_safe_calloc +#define safe_malloc guestfs_safe_malloc +#define safe_realloc guestfs_safe_realloc +#define safe_strdup guestfs_safe_strdup +#define safe_strndup guestfs_safe_strndup +#define safe_memdup guestfs_safe_memdup +#define safe_asprintf guestfs_safe_asprintf + +/* errors.c */ +extern void guestfs___init_error_handler (guestfs_h *g); + +extern void guestfs_error (guestfs_h *g, const char *fs, ...) + __attribute__((format (printf,2,3))); +extern void guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...) + __attribute__((format (printf,3,4))); +extern void guestfs_perrorf (guestfs_h *g, const char *fs, ...) + __attribute__((format (printf,2,3))); + extern void guestfs___warning (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3))); extern void guestfs___debug (guestfs_h *g, const char *fs, ...) @@ -494,8 +505,6 @@ extern void guestfs___debug (guestfs_h *g, const char *fs, ...) extern void guestfs___trace (guestfs_h *g, const char *fs, ...) __attribute__((format (printf,2,3))); -extern void guestfs___free_string_list (char **); - extern void guestfs___print_BufferIn (FILE *out, const char *buf, size_t buf_size); extern void guestfs___print_BufferOut (FILE *out, const char *buf, size_t buf_size); @@ -504,13 +513,9 @@ extern void guestfs___print_BufferOut (FILE *out, const char *buf, size_t buf_si #define warning(g,...) guestfs___warning((g),__VA_ARGS__) #define debug(g,...) \ do { if ((g)->verbose) guestfs___debug ((g),__VA_ARGS__); } while (0) -#define safe_calloc guestfs_safe_calloc -#define safe_malloc guestfs_safe_malloc -#define safe_realloc guestfs_safe_realloc -#define safe_strdup guestfs_safe_strdup -#define safe_strndup guestfs_safe_strndup -#define safe_memdup guestfs_safe_memdup -#define safe_asprintf guestfs_safe_asprintf + +/* utils.c */ +extern void guestfs___free_string_list (char **); /* actions-support.c */ extern int guestfs___check_reply_header (guestfs_h *g, const struct guestfs_message_header *hdr, unsigned int proc_nr, unsigned int serial); diff --git a/src/guestfs.c b/src/handle.c index f8eb76c7..fd7db698 100644 --- a/src/guestfs.c +++ b/src/handle.c @@ -18,29 +18,10 @@ #include <config.h> -#define _BSD_SOURCE /* for mkdtemp, usleep */ - #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> -#include <inttypes.h> #include <unistd.h> #include <string.h> -#include <fcntl.h> -#include <time.h> -#include <assert.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/un.h> -#include <sys/wait.h> - -#include <rpc/types.h> -#include <rpc/xdr.h> #ifdef HAVE_LIBVIRT #include <libvirt/libvirt.h> @@ -51,10 +32,7 @@ #include <libxml/xmlversion.h> #endif -#include "c-ctype.h" #include "glthread/lock.h" -#include "hash.h" -#include "hash-pjw.h" #include "guestfs.h" #include "guestfs-internal.h" @@ -62,7 +40,6 @@ #include "guestfs_protocol.h" static int parse_attach_method (guestfs_h *g, const char *method); -static void init_error_handler (guestfs_h *g); static int shutdown_backend (guestfs_h *g, int check_for_errors); static void close_handles (void); @@ -117,7 +94,7 @@ guestfs_create_flags (unsigned flags, ...) g->fd[1] = -1; g->sock = -1; - init_error_handler (g); + guestfs___init_error_handler (g); g->abort_cb = abort; g->recovery_proc = 1; @@ -410,321 +387,6 @@ close_handles (void) while (handles) guestfs_close (handles); } -const char * -guestfs_last_error (guestfs_h *g) -{ - return g->last_error; -} - -int -guestfs_last_errno (guestfs_h *g) -{ - return g->last_errnum; -} - -static void -set_last_error (guestfs_h *g, int errnum, const char *msg) -{ - free (g->last_error); - g->last_error = strdup (msg); - g->last_errnum = errnum; -} - -/* Warning are printed unconditionally. We try to make these rare. - * Generally speaking, a warning should either be an error, or if it's - * not important for end users then it should be a debug message. - */ -void -guestfs___warning (guestfs_h *g, const char *fs, ...) -{ - va_list args; - char *msg, *msg2; - int len; - - va_start (args, fs); - len = vasprintf (&msg, fs, args); - va_end (args); - - if (len < 0) return; - - len = asprintf (&msg2, _("warning: %s"), msg); - free (msg); - - if (len < 0) return; - - guestfs___call_callbacks_message (g, GUESTFS_EVENT_LIBRARY, msg2, len); - - free (msg2); -} - -/* Debug messages. */ -void -guestfs___debug (guestfs_h *g, const char *fs, ...) -{ - va_list args; - char *msg; - int len; - - /* The cpp macro "debug" has already checked that g->verbose is true - * before calling this function, but we check it again just in case - * anyone calls this function directly. - */ - if (!g->verbose) - return; - - va_start (args, fs); - len = vasprintf (&msg, fs, args); - va_end (args); - - if (len < 0) return; - - guestfs___call_callbacks_message (g, GUESTFS_EVENT_LIBRARY, msg, len); - - free (msg); -} - -/* Call trace messages. These are enabled by setting g->trace, and - * calls to this function should only happen from the generated code - * in src/actions.c - */ -void -guestfs___trace (guestfs_h *g, const char *fs, ...) -{ - va_list args; - char *msg; - int len; - - va_start (args, fs); - len = vasprintf (&msg, fs, args); - va_end (args); - - if (len < 0) return; - - guestfs___call_callbacks_message (g, GUESTFS_EVENT_TRACE, msg, len); - - free (msg); -} - -void -guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...) -{ - va_list args; - char *msg; - - va_start (args, fs); - int err = vasprintf (&msg, fs, args); - va_end (args); - - if (err < 0) return; - - /* set_last_error first so that the callback can access the error - * message and errno through the handle if it wishes. - */ - set_last_error (g, errnum, msg); - if (g->error_cb) g->error_cb (g, g->error_cb_data, msg); - - free (msg); -} - -void -guestfs_perrorf (guestfs_h *g, const char *fs, ...) -{ - va_list args; - char *msg; - int errnum = errno; - - va_start (args, fs); - int err = vasprintf (&msg, fs, args); - va_end (args); - - if (err < 0) return; - - char buf[256]; - strerror_r (errnum, buf, sizeof buf); - - msg = safe_realloc (g, msg, strlen (msg) + 2 + strlen (buf) + 1); - strcat (msg, ": "); - strcat (msg, buf); - - /* set_last_error first so that the callback can access the error - * message and errno through the handle if it wishes. - */ - set_last_error (g, errnum, msg); - if (g->error_cb) g->error_cb (g, g->error_cb_data, msg); - - free (msg); -} - -void * -guestfs_safe_malloc (guestfs_h *g, size_t nbytes) -{ - void *ptr = malloc (nbytes); - if (nbytes > 0 && !ptr) g->abort_cb (); - return ptr; -} - -/* Return 1 if an array of N objects, each of size S, cannot exist due - to size arithmetic overflow. S must be positive and N must be - nonnegative. This is a macro, not an inline function, so that it - works correctly even when SIZE_MAX < N. - - By gnulib convention, SIZE_MAX represents overflow in size - calculations, so the conservative dividend to use here is - SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. - However, malloc (SIZE_MAX) fails on all known hosts where - sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for - exactly-SIZE_MAX allocations on such hosts; this avoids a test and - branch when S is known to be 1. */ -# define xalloc_oversized(n, s) \ - ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) - -/* Technically we should add an autoconf test for this, testing for the desired - functionality, like what's done in gnulib, but for now, this is fine. */ -#if defined(__GLIBC__) -#define HAVE_GNU_CALLOC (__GLIBC__ >= 2) -#else -#define HAVE_GNU_CALLOC 0 -#endif - -/* Allocate zeroed memory for N elements of S bytes, with error - checking. S must be nonzero. */ -void * -guestfs_safe_calloc (guestfs_h *g, size_t n, size_t s) -{ - /* From gnulib's calloc function in xmalloc.c. */ - void *p; - /* Test for overflow, since some calloc implementations don't have - proper overflow checks. But omit overflow and size-zero tests if - HAVE_GNU_CALLOC, since GNU calloc catches overflow and never - returns NULL if successful. */ - if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) - || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) - g->abort_cb (); - return p; -} - -void * -guestfs_safe_realloc (guestfs_h *g, void *ptr, size_t nbytes) -{ - void *p = realloc (ptr, nbytes); - if (nbytes > 0 && !p) g->abort_cb (); - return p; -} - -char * -guestfs_safe_strdup (guestfs_h *g, const char *str) -{ - char *s = strdup (str); - if (!s) g->abort_cb (); - return s; -} - -char * -guestfs_safe_strndup (guestfs_h *g, const char *str, size_t n) -{ - char *s = strndup (str, n); - if (!s) g->abort_cb (); - return s; -} - -void * -guestfs_safe_memdup (guestfs_h *g, const void *ptr, size_t size) -{ - void *p = malloc (size); - if (!p) g->abort_cb (); - memcpy (p, ptr, size); - return p; -} - -char * -guestfs_safe_asprintf (guestfs_h *g, const char *fs, ...) -{ - va_list args; - char *msg; - - va_start (args, fs); - int err = vasprintf (&msg, fs, args); - va_end (args); - - if (err == -1) - g->abort_cb (); - - return msg; -} - -void -guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb cb) -{ - g->abort_cb = cb; -} - -guestfs_abort_cb -guestfs_get_out_of_memory_handler (guestfs_h *g) -{ - return g->abort_cb; -} - -void -guestfs_set_error_handler (guestfs_h *g, - guestfs_error_handler_cb cb, void *data) -{ - g->error_cb = cb; - g->error_cb_data = data; -} - -guestfs_error_handler_cb -guestfs_get_error_handler (guestfs_h *g, void **data_rtn) -{ - if (data_rtn) *data_rtn = g->error_cb_data; - return g->error_cb; -} - -void -guestfs_push_error_handler (guestfs_h *g, - guestfs_error_handler_cb cb, void *data) -{ - struct error_cb_stack *old_stack; - - old_stack = g->error_cb_stack; - g->error_cb_stack = safe_malloc (g, sizeof (struct error_cb_stack)); - g->error_cb_stack->next = old_stack; - g->error_cb_stack->error_cb = g->error_cb; - g->error_cb_stack->error_cb_data = g->error_cb_data; - - guestfs_set_error_handler (g, cb, data); -} - -void -guestfs_pop_error_handler (guestfs_h *g) -{ - struct error_cb_stack *next_stack; - - if (g->error_cb_stack) { - next_stack = g->error_cb_stack->next; - guestfs_set_error_handler (g, g->error_cb_stack->error_cb, - g->error_cb_stack->error_cb_data); - free (g->error_cb_stack); - g->error_cb_stack = next_stack; - } - else - init_error_handler (g); -} - -static void default_error_cb (guestfs_h *g, void *data, const char *msg); - -static void -init_error_handler (guestfs_h *g) -{ - g->error_cb = default_error_cb; - g->error_cb_data = NULL; -} - -static void -default_error_cb (guestfs_h *g, void *data, const char *msg) -{ - fprintf (stderr, _("libguestfs: error: %s\n"), msg); -} - void guestfs_user_cancel (guestfs_h *g) { @@ -1005,186 +667,3 @@ guestfs__get_smp (guestfs_h *g) { return g->smp; } - -/* Note the private data area is allocated lazily, since the vast - * majority of callers will never use it. This means g->pda is - * likely to be NULL. - */ -struct pda_entry { - char *key; /* key */ - void *data; /* opaque user data pointer */ -}; - -static size_t -hasher (void const *x, size_t table_size) -{ - struct pda_entry const *p = x; - return hash_pjw (p->key, table_size); -} - -static bool -comparator (void const *x, void const *y) -{ - struct pda_entry const *a = x; - struct pda_entry const *b = y; - return STREQ (a->key, b->key); -} - -static void -freer (void *x) -{ - if (x) { - struct pda_entry *p = x; - free (p->key); - free (p); - } -} - -void -guestfs_set_private (guestfs_h *g, const char *key, void *data) -{ - if (g->pda == NULL) { - g->pda = hash_initialize (16, NULL, hasher, comparator, freer); - if (g->pda == NULL) - g->abort_cb (); - } - - struct pda_entry *new_entry = safe_malloc (g, sizeof *new_entry); - new_entry->key = safe_strdup (g, key); - new_entry->data = data; - - struct pda_entry *old_entry = hash_delete (g->pda, new_entry); - freer (old_entry); - - struct pda_entry *entry = hash_insert (g->pda, new_entry); - if (entry == NULL) - g->abort_cb (); - assert (entry == new_entry); -} - -static inline char * -bad_cast (char const *s) -{ - return (char *) s; -} - -void * -guestfs_get_private (guestfs_h *g, const char *key) -{ - if (g->pda == NULL) - return NULL; /* no keys have been set */ - - const struct pda_entry k = { .key = bad_cast (key) }; - struct pda_entry *entry = hash_lookup (g->pda, &k); - if (entry) - return entry->data; - else - return NULL; -} - -/* Iterator. */ -void * -guestfs_first_private (guestfs_h *g, const char **key_rtn) -{ - if (g->pda == NULL) - return NULL; - - g->pda_next = hash_get_first (g->pda); - - /* Ignore any keys with NULL data pointers. */ - while (g->pda_next && g->pda_next->data == NULL) - g->pda_next = hash_get_next (g->pda, g->pda_next); - - if (g->pda_next == NULL) - return NULL; - - *key_rtn = g->pda_next->key; - return g->pda_next->data; -} - -void * -guestfs_next_private (guestfs_h *g, const char **key_rtn) -{ - if (g->pda == NULL) - return NULL; - - if (g->pda_next == NULL) - return NULL; - - /* Walk to the next key with a non-NULL data pointer. */ - do { - g->pda_next = hash_get_next (g->pda, g->pda_next); - } while (g->pda_next && g->pda_next->data == NULL); - - if (g->pda_next == NULL) - return NULL; - - *key_rtn = g->pda_next->key; - return g->pda_next->data; -} - -/* When tracing, be careful how we print BufferIn parameters which - * usually contain large amounts of binary data (RHBZ#646822). - */ -void -guestfs___print_BufferIn (FILE *out, const char *buf, size_t buf_size) -{ - size_t i; - size_t orig_size = buf_size; - - if (buf_size > 256) - buf_size = 256; - - fputc ('"', out); - - for (i = 0; i < buf_size; ++i) { - if (c_isprint (buf[i])) - fputc (buf[i], out); - else - fprintf (out, "\\x%02x", (unsigned char) buf[i]); - } - - fputc ('"', out); - - if (orig_size > buf_size) - fprintf (out, - _("<truncated, original size %zu bytes>"), orig_size); -} - -void -guestfs___print_BufferOut (FILE *out, const char *buf, size_t buf_size) -{ - guestfs___print_BufferIn (out, buf, buf_size); -} - -void -guestfs___free_string_list (char **argv) -{ - size_t i; - for (i = 0; argv[i] != NULL; ++i) - free (argv[i]); - free (argv); -} - -char * -guestfs__canonical_device_name (guestfs_h *g, const char *device) -{ - char *ret; - - if (STRPREFIX (device, "/dev/hd") || - STRPREFIX (device, "/dev/vd")) { - ret = safe_strdup (g, device); - ret[5] = 's'; - } - else if (STRPREFIX (device, "/dev/mapper/") || - STRPREFIX (device, "/dev/dm-")) { - /* XXX hide errors */ - ret = guestfs_lvm_canonical_lv_name (g, device); - if (ret == NULL) - ret = safe_strdup (g, device); - } - else - ret = safe_strdup (g, device); - - return ret; /* caller frees */ -} diff --git a/src/private-data.c b/src/private-data.c new file mode 100644 index 00000000..870ec101 --- /dev/null +++ b/src/private-data.c @@ -0,0 +1,148 @@ +/* libguestfs + * Copyright (C) 2009-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "c-ctype.h" +#include "hash.h" +#include "hash-pjw.h" + +#include "guestfs.h" +#include "guestfs-internal.h" + +/* Note the private data area is allocated lazily, since the vast + * majority of callers will never use it. This means g->pda is + * likely to be NULL. + */ +struct pda_entry { + char *key; /* key */ + void *data; /* opaque user data pointer */ +}; + +static size_t +hasher (void const *x, size_t table_size) +{ + struct pda_entry const *p = x; + return hash_pjw (p->key, table_size); +} + +static bool +comparator (void const *x, void const *y) +{ + struct pda_entry const *a = x; + struct pda_entry const *b = y; + return STREQ (a->key, b->key); +} + +static void +freer (void *x) +{ + if (x) { + struct pda_entry *p = x; + free (p->key); + free (p); + } +} + +void +guestfs_set_private (guestfs_h *g, const char *key, void *data) +{ + if (g->pda == NULL) { + g->pda = hash_initialize (16, NULL, hasher, comparator, freer); + if (g->pda == NULL) + g->abort_cb (); + } + + struct pda_entry *new_entry = safe_malloc (g, sizeof *new_entry); + new_entry->key = safe_strdup (g, key); + new_entry->data = data; + + struct pda_entry *old_entry = hash_delete (g->pda, new_entry); + freer (old_entry); + + struct pda_entry *entry = hash_insert (g->pda, new_entry); + if (entry == NULL) + g->abort_cb (); + assert (entry == new_entry); +} + +static inline char * +bad_cast (char const *s) +{ + return (char *) s; +} + +void * +guestfs_get_private (guestfs_h *g, const char *key) +{ + if (g->pda == NULL) + return NULL; /* no keys have been set */ + + const struct pda_entry k = { .key = bad_cast (key) }; + struct pda_entry *entry = hash_lookup (g->pda, &k); + if (entry) + return entry->data; + else + return NULL; +} + +/* Iterator. */ +void * +guestfs_first_private (guestfs_h *g, const char **key_rtn) +{ + if (g->pda == NULL) + return NULL; + + g->pda_next = hash_get_first (g->pda); + + /* Ignore any keys with NULL data pointers. */ + while (g->pda_next && g->pda_next->data == NULL) + g->pda_next = hash_get_next (g->pda, g->pda_next); + + if (g->pda_next == NULL) + return NULL; + + *key_rtn = g->pda_next->key; + return g->pda_next->data; +} + +void * +guestfs_next_private (guestfs_h *g, const char **key_rtn) +{ + if (g->pda == NULL) + return NULL; + + if (g->pda_next == NULL) + return NULL; + + /* Walk to the next key with a non-NULL data pointer. */ + do { + g->pda_next = hash_get_next (g->pda, g->pda_next); + } while (g->pda_next && g->pda_next->data == NULL); + + if (g->pda_next == NULL) + return NULL; + + *key_rtn = g->pda_next->key; + return g->pda_next->data; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 00000000..aaf4fa5d --- /dev/null +++ b/src/utils.c @@ -0,0 +1,36 @@ +/* libguestfs + * Copyright (C) 2009-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "guestfs.h" +#include "guestfs-internal.h" + +void +guestfs___free_string_list (char **argv) +{ + size_t i; + for (i = 0; argv[i] != NULL; ++i) + free (argv[i]); + free (argv); +} |