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(a)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