[Libguestfs] [PATCH 2/5] daemon: add a way to check for the version of augeas
Richard W.M. Jones
rjones at redhat.com
Fri Sep 5 12:08:59 UTC 2014
On Thu, Sep 04, 2014 at 05:18:28PM +0200, Pino Toscano wrote:
> Query augeas for its version when required, i.e. only once when using
> the new augeas_is_version function.
> ---
> daemon/augeas.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> daemon/daemon.h | 16 +++++++-
> 2 files changed, 131 insertions(+), 1 deletion(-)
>
> diff --git a/daemon/augeas.c b/daemon/augeas.c
> index 74f3ba7..8dc6a7c 100644
> --- a/daemon/augeas.c
> +++ b/daemon/augeas.c
> @@ -24,10 +24,46 @@
> #include <unistd.h>
>
> #include <augeas.h>
> +#include <pcre.h>
>
> #include "daemon.h"
> #include "actions.h"
> #include "optgroups.h"
> +#include "xstrtol.h"
> +
> +#ifdef HAVE_ATTRIBUTE_CLEANUP
> +#define CLEANUP_PCRE_FREE __attribute__((cleanup(cleanup_pcre_free)))
> +
> +static void
> +cleanup_pcre_free (void *ptr)
> +{
> + pcre *re = * (pcre **) ptr;
> +
> + if (re != NULL)
> + pcre_free (re);
> +}
> +
> +#else
> +#define CLEANUP_PCRE_FREE
> +#endif
> +
> +#define FPRINTF_AUGEAS_ERROR(aug,fs,...) \
> + do { \
> + int code = aug_error (aug); \
> + if (code == AUG_ENOMEM) \
> + reply_with_error (fs ": augeas out of memory", ##__VA_ARGS__); \
> + else { \
> + const char *message = aug_error_message (aug); \
> + const char *minor = aug_error_minor_message (aug); \
> + const char *details = aug_error_details (aug); \
> + fprintf (stderr, fs ": %s%s%s%s%s", ##__VA_ARGS__, \
> + message, \
> + minor ? ": " : "", minor ? minor : "", \
> + details ? ": " : "", details ? details : ""); \
> + } \
> + } while (0)
> +
> +int augeas_version;
>
> /* The Augeas handle. We maintain a single handle per daemon, which
> * is all that is necessary and reduces the complexity of the API
> @@ -35,6 +71,86 @@
> */
> static augeas *aug = NULL;
>
> +void
> +aug_read_version (void)
> +{
> + CLEANUP_AUG_CLOSE augeas *ah = NULL;
> + int r;
> + const char *str;
> + CLEANUP_PCRE_FREE pcre *re = NULL;
> + const char *errptr;
> + int erroffset;
> + size_t len;
> +#define N_MATCHES 4
> + int vec[N_MATCHES * 4];
> + unsigned long int major = 0, minor = 0, patch = 0;
> +
> + if (augeas_version != 0)
> + return;
> +
> + /* Optimization: do not load the files nor the lenses, since we are
> + * only interested in the version.
> + */
> + ah = aug_init ("/", NULL, AUG_NO_ERR_CLOSE | AUG_NO_LOAD | AUG_NO_STDINC);
> + if (!ah) {
> + FPRINTF_AUGEAS_ERROR (ah, "augeas initialization failed");
> + return;
> + }
> +
> + if (aug_error (ah) != AUG_NOERROR) {
> + FPRINTF_AUGEAS_ERROR (ah, "aug_init");
> + return;
> + }
> +
> + r = aug_get (ah, "/augeas/version", &str);
> + if (r != 1) {
> + FPRINTF_AUGEAS_ERROR (ah, "aug_get");
> + return;
> + }
Wow, that is tedious. Be nice if Augeas had an API call to get the
version fields directly ...
I would be tempted to use sscanf to parse up the version number here.
The code would be a lot shorter and simpler.
But yes, ACK, although sscanf better.
Rich.
> + re = pcre_compile ("(\\d+)\\.(\\d+)(\\.(\\d+))?",
> + 0, &errptr, &erroffset, NULL);
> + if (re == NULL) {
> + fprintf (stderr, "cannot compile the augeas version regexp\n");
> + return;
> + }
> +
> + len = strlen (str);
> + r = pcre_exec (re, NULL, str, len, 0, 0, vec, sizeof (vec) / sizeof (vec[0]));
> + if (r == PCRE_ERROR_NOMATCH) {
> + fprintf (stderr, "cannot match the version string in '%s'\n", str);
> + return;
> + }
> +
> + if (r > 1) {
> + if (xstrtoul (&str[vec[2]], NULL, 10, &major, NULL) != LONGINT_OK) {
> + fprintf (stderr, "could not parse '%*s' as integer\n",
> + vec[3]-vec[2], &str[vec[2]]);
> + return;
> + }
> + }
> + if (r > 2) {
> + if (xstrtoul (&str[vec[4]], NULL, 10, &minor, NULL) != LONGINT_OK) {
> + fprintf (stderr, "could not parse '%*s' as integer\n",
> + vec[5]-vec[4], &str[vec[4]]);
> + return;
> + }
> + }
> + if (r > 4) {
> + if (xstrtoul (&str[vec[8]], NULL, 10, &patch, NULL) != LONGINT_OK) {
> + fprintf (stderr, "could not parse '%*s' as integer\n",
> + vec[9]-vec[8], &str[vec[8]]);
> + return;
> + }
> + }
> +
> + if (verbose)
> + fprintf (stderr, "augeas version: %ld.%ld.%ld\n", major, minor, patch);
> +
> + augeas_version = (int) ((major << 16) | (minor << 8) | patch);
> +#undef N_MATCHES
> +}
> +
> /* Clean up the augeas handle on daemon exit. */
> void aug_finalize (void) __attribute__((destructor));
> void
> diff --git a/daemon/daemon.h b/daemon/daemon.h
> index b9e7402..0ccbc9e 100644
> --- a/daemon/daemon.h
> +++ b/daemon/daemon.h
> @@ -228,8 +228,22 @@ extern void copy_lvm (void);
> /*-- in zero.c --*/
> extern void wipe_device_before_mkfs (const char *device);
>
> -/*-- in augeas.c, hivex.c, journal.c --*/
> +/*-- in augeas.c --*/
> +extern void aug_read_version (void);
> extern void aug_finalize (void);
> +
> +/* The version of augeas, saved as:
> + * (MAJOR << 16) | (MINOR << 8) | PATCH
> + */
> +extern int augeas_version;
> +static inline int
> +augeas_is_version (int major, int minor, int patch)
> +{
> + aug_read_version (); /* Lazy version reading. */
> + return augeas_version >= ((major << 16) | (minor << 8) | patch);
> +}
> +
> +/*-- hivex.c, journal.c --*/
> extern void hivex_finalize (void);
> extern void journal_finalize (void);
>
> --
> 1.9.3
>
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://www.redhat.com/mailman/listinfo/libguestfs
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
More information about the Libguestfs
mailing list