2003-01-30 Marcus Brinkmann <marcus@g10code.de>
+ * gpgme.texi (Engine Information): Rename member part to
+ file_name.
+
* gpgme.texi (Protocols and Engines): Document
gpgme_get_protocol_name.
convert this to a string with @code{gpgme_get_protocol_name} for
printing.
-@item const char *path
-This is a string holding the path to the executable of the crypto
+@item const char *file_name
+This is a string holding the file name of the executable of the crypto
engine. Currently, it is never @code{NULL}, but using @code{NULL} is
reserved for future use, so always check before you use it.
2003-01-30 Marcus Brinkmann <marcus@g10code.de>
+ * engine-backend.h (struct engine_ops): Rename get_path to
+ get_file_name.
+ * gpgme.h (struct _gpgme_engine_info): Rename member path to
+ file_name.
+ * version.c: Do not include <stdio.h>, <stdlib.h>, context.h and
+ util.h. Other clean ups.
+ (parse_version_number): Protect more seriously against
+ overflow.
+ (gpgme_get_engine_info): Move to ...
+ * engine.c (gpgme_get_engine_info): ... here.
+ (_gpgme_engine_get_info): Function removed.
+ (_gpgme_engine_get_path): Make static and rename to ...
+ (engine_get_file_name): .. this.
+ (_gpgme_engine_get_version): Make static and rename to ...
+ (engine_get_version): ... this.
+ (_gpgme_engine_get_req_version): Make static and rename to ...
+ (engine_get_req_version): ... this.
+ * engine.h (_gpgme_engine_get_path, _gpgme_engine_get_version,
+ _gpgme_engine_req_version, _gpgme_engine_get_info.): Remove
+ prototypes.
+
* gpgme.h (enum GpgmeProtocol): Remove GPGME_PROTOCOL_AUTO.
* gpgme.c (gpgme_set_protocol): Don't handle GPGME_PROTOCOL_AUTO.
(gpgme_get_protocol_name): New function.
struct engine_ops
{
/* Static functions. */
- const char *(*get_path) (void);
+ const char *(*get_file_name) (void);
const char *(*get_version) (void);
const char *(*get_req_version) (void);
GpgmeError (*new) (void **r_engine);
#endif
};
-
-/* Get the path of the engine for PROTOCOL. */
-const char *
-_gpgme_engine_get_path (GpgmeProtocol proto)
+\f
+/* Get the file name of the engine for PROTOCOL. */
+static const char *
+engine_get_file_name (GpgmeProtocol proto)
{
if (proto > DIM (engine_ops))
return NULL;
- if (engine_ops[proto] && engine_ops[proto]->get_path)
- return (*engine_ops[proto]->get_path) ();
+ if (engine_ops[proto] && engine_ops[proto]->get_file_name)
+ return (*engine_ops[proto]->get_file_name) ();
else
return NULL;
}
/* Get the version number of the engine for PROTOCOL. */
-const char *
-_gpgme_engine_get_version (GpgmeProtocol proto)
+static const char *
+engine_get_version (GpgmeProtocol proto)
{
if (proto > DIM (engine_ops))
return NULL;
/* Get the required version number of the engine for PROTOCOL. */
-const char *
-_gpgme_engine_get_req_version (GpgmeProtocol proto)
+static const char *
+engine_get_req_version (GpgmeProtocol proto)
{
if (proto > DIM (engine_ops))
return NULL;
GpgmeError
gpgme_engine_check_version (GpgmeProtocol proto)
{
- return _gpgme_compare_versions (_gpgme_engine_get_version (proto),
- _gpgme_engine_get_req_version (proto))
+ return _gpgme_compare_versions (engine_get_version (proto),
+ engine_get_req_version (proto))
? 0 : GPGME_Invalid_Engine;
}
-const char *
-_gpgme_engine_get_info (GpgmeProtocol proto)
+/* Get the information about the configured and installed engines. A
+ pointer to the first engine in the statically allocated linked list
+ is returned in *INFO. If an error occurs, it is returned. */
+GpgmeError
+gpgme_get_engine_info (GpgmeEngineInfo *info)
{
- static const char fmt[] = " <engine>\n"
- " <protocol>%s</protocol>\n"
- " <version>%s</version>\n"
- " <path>%s</path>\n"
- " </engine>\n";
- static const char *const strproto[3] = { "OpenPGP", "CMS", NULL };
- static const char *engine_info[3]; /* FIXME: MAX_PROTO + 1*/
+ static GpgmeEngineInfo engine_info;
DEFINE_STATIC_LOCK (engine_info_lock);
- if (proto > 2 /* FIXME MAX_PROTO */ || !strproto[proto])
- return NULL;
-
LOCK (engine_info_lock);
- if (!engine_info[proto])
+ if (!engine_info)
{
- const char *path = _gpgme_engine_get_path (proto);
- const char *version = _gpgme_engine_get_version (proto);
+ GpgmeEngineInfo *lastp = &engine_info;
+ GpgmeProtocol proto_list[] = { GPGME_PROTOCOL_OpenPGP,
+ GPGME_PROTOCOL_CMS };
+ int proto;
- if (path && version)
+ for (proto = 0; proto < DIM (proto_list); proto++)
{
- char *info = malloc (strlen (fmt) + strlen (strproto[proto])
- + strlen (path) + strlen (version) + 1);
- if (!info)
- info = " <engine>\n"
- " <error>Out of core</error>\n"
- " </engine>";
- else
- sprintf (info, fmt, strproto[proto], version, path);
- engine_info[proto] = info;
+ const char *file_name = engine_get_file_name (proto_list[proto]);
+
+ if (!file_name)
+ continue;
+
+ *lastp = malloc (sizeof (*engine_info));
+ if (!*lastp)
+ {
+ while (engine_info)
+ {
+ GpgmeEngineInfo next_info = engine_info->next;
+ free (engine_info);
+ engine_info = next_info;
+ }
+ UNLOCK (engine_info_lock);
+ return GPGME_Out_Of_Core;
+ }
+
+ (*lastp)->protocol = proto_list[proto];
+ (*lastp)->file_name = file_name;
+ (*lastp)->version = engine_get_version (proto_list[proto]);
+ (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
+ lastp = &(*lastp)->next;
}
}
UNLOCK (engine_info_lock);
- return engine_info[proto];
+ *info = engine_info;
+ return 0;
}
-
+\f
GpgmeError
_gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine)
{
EngineObject engine;
- const char *path;
+ const char *file_name;
const char *version;
if (proto > DIM (engine_ops))
if (!engine_ops[proto])
return GPGME_Invalid_Engine;
- path = _gpgme_engine_get_path (proto);
- version = _gpgme_engine_get_version (proto);
- if (!path || !version)
+ file_name = engine_get_file_name (proto);
+ version = engine_get_version (proto);
+ if (!file_name || !version)
return GPGME_Invalid_Engine;
engine = calloc (1, sizeof *engine);
#include "types.h"
-/* Get the path of the engine for PROTOCOL. */
-const char *_gpgme_engine_get_path (GpgmeProtocol proto);
-
-/* Get the version number of the engine for PROTOCOL. */
-const char *_gpgme_engine_get_version (GpgmeProtocol proto);
-
-/* Get the version number of the engine for PROTOCOL. */
-const char *_gpgme_engine_req_version (GpgmeProtocol proto);
-
-/* Verify the version requirement for the engine for PROTOCOL. */
-const char *_gpgme_engine_get_info (GpgmeProtocol proto);
-
GpgmeError _gpgme_engine_new (GpgmeProtocol proto, EngineObject *r_engine);
void _gpgme_engine_release (EngineObject engine);
void _gpgme_engine_set_status_handler (EngineObject engine,
/* The protocol ID. */
GpgmeProtocol protocol;
- /* The path to the engine binary. */
- const char *path;
+ /* The file name of the engine binary. */
+ const char *file_name;
/* The version string of the installed engine. */
const char *version;
#if HAVE_CONFIG_H
#include <config.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <ctype.h>
#include "gpgme.h"
-#include "context.h"
-#include "sema.h"
-#include "util.h"
-#include "key.h" /* for key_cache_init */
#include "io.h"
+/* For _gpgme_sema_subsystem_init (). */
+#include "sema.h"
+
+/* For _gpgme_key_cache_init (). */
+#include "key.h"
+\f
+/* Bootstrap the subsystems needed for concurrent operation. This
+ must be done once at startup. We can not guarantee this using a
+ lock, though, because the semaphore subsystem needs to be
+ initialized itself before it can be used. So we expect that the
+ user performs the necessary syncrhonization. */
static void
do_subsystem_inits (void)
{
if (done)
return;
+
_gpgme_sema_subsystem_init ();
_gpgme_key_cache_init ();
done = 1;
}
-static const char*
-parse_version_number (const char *s, int *number)
+
+/* Read the next number in the version string STR and return it in
+ *NUMBER. Return a pointer to the tail of STR after parsing, or
+ *NULL if the version string was invalid. */
+static const char *
+parse_version_number (const char *str, int *number)
{
+#define MAXVAL ((INT_MAX - 10) / 10)
int val = 0;
- if (*s == '0' && isdigit(s[1]))
- return NULL; /* Leading zeros are not allowed. */
- for (; isdigit(*s); s++)
+ /* Leading zeros are not allowed. */
+ if (*str == '0' && isdigit(str[1]))
+ return NULL;
+
+ while (isdigit (*str) && val <= MAXVAL)
{
val *= 10;
- val += *s - '0';
+ val += *(str++) - '0';
}
*number = val;
- return val < 0 ? NULL : s;
+ return val > MAXVAL ? NULL : str;
}
+
+/* Parse the version string STR in the format MAJOR.MINOR.MICRO (for
+ example, 9.3.2) and return the components in MAJOR, MINOR and MICRO
+ as integers. The function returns the tail of the string that
+ follows the version number. This might be te empty string if there
+ is nothing following the version number, or a patchlevel. The
+ function returns NULL if the version string is not valid. */
static const char *
-parse_version_string (const char *s, int *major, int *minor, int *micro)
+parse_version_string (const char *str, int *major, int *minor, int *micro)
{
- s = parse_version_number (s, major);
- if (!s || *s != '.')
+ str = parse_version_number (str, major);
+ if (!str || *str != '.')
return NULL;
- s++;
- s = parse_version_number (s, minor);
- if (!s || *s != '.')
+ str++;
+
+ str = parse_version_number (str, minor);
+ if (!str || *str != '.')
return NULL;
- s++;
- s = parse_version_number (s, micro);
- if (!s)
+ str++;
+
+ str = parse_version_number (str, micro);
+ if (!str)
return NULL;
- return s; /* Patchlevel. */
+
+ /* A patchlevel might follow. */
+ return str;
}
+
const char *
_gpgme_compare_versions (const char *my_version,
- const char *req_version)
+ const char *rq_version)
{
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
- if (!req_version)
+ if (!rq_version)
return my_version;
if (!my_version)
return NULL;
my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
if (!my_plvl)
- return NULL; /* Very strange: our own version is bogus. */
- rq_plvl = parse_version_string(req_version,
- &rq_major, &rq_minor, &rq_micro);
+ return NULL;
+
+ rq_plvl = parse_version_string (rq_version, &rq_major, &rq_minor, &rq_micro);
if (!rq_plvl)
- return NULL; /* Requested version string is invalid. */
+ return NULL;
if (my_major > rq_major
- || (my_major == rq_major && my_minor > rq_minor)
+ || (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
- && my_micro == rq_micro
- && strcmp( my_plvl, rq_plvl ) >= 0))
- {
- return my_version;
- }
+ && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
+ return my_version;
+
return NULL;
}
-/**
- * gpgme_check_version:
- * @req_version: A string with a version
- *
- * Check that the the version of the library is at minimum the requested one
- * and return the version string; return NULL if the condition is not
- * met. If a NULL is passed to this function, no check is done and
- * the version string is simply returned. It is a pretty good idea to
- * run this function as soon as possible, because it also intializes
- * some subsystems. In a multithreaded environment if should be called
- * before the first thread is created.
- *
- * Return value: The version string or NULL
- **/
+
+/* Check that the the version of the library is at minimum the
+ requested one and return the version string; return NULL if the
+ condition is not met. If a NULL is passed to this function, no
+ check is done and the version string is simply returned.
+
+ This function must be run once at startup, as it also initializes
+ some subsystems. Its invocation must be synchronized against
+ calling any of the other functions in a multi-threaded
+ environments. */
const char *
gpgme_check_version (const char *req_version)
{
return _gpgme_compare_versions (VERSION, req_version);
}
-
-/* Get the information about the configured and installed engines. A
- pointer to the first engine in the statically allocated linked list
- is returned in *INFO. If an error occurs, it is returned. */
-GpgmeError
-gpgme_get_engine_info (GpgmeEngineInfo *info)
-{
- static GpgmeEngineInfo engine_info;
- DEFINE_STATIC_LOCK (engine_info_lock);
-
- LOCK (engine_info_lock);
- if (!engine_info)
- {
- GpgmeEngineInfo *lastp = &engine_info;
- GpgmeProtocol proto_list[] = { GPGME_PROTOCOL_OpenPGP,
- GPGME_PROTOCOL_CMS };
- int proto;
-
- for (proto = 0; proto < DIM (proto_list); proto++)
- {
- const char *path = _gpgme_engine_get_path (proto_list[proto]);
-
- if (!path)
- continue;
-
- *lastp = malloc (sizeof (*engine_info));
- if (!*lastp)
- {
- while (engine_info)
- {
- GpgmeEngineInfo next_info = engine_info->next;
- free (engine_info);
- engine_info = next_info;
- }
- UNLOCK (engine_info_lock);
- return GPGME_Out_Of_Core;
- }
-
- (*lastp)->protocol = proto_list[proto];
- (*lastp)->path = path;
- (*lastp)->version = _gpgme_engine_get_version (proto_list[proto]);
- (*lastp)->req_version
- = _gpgme_engine_get_req_version (proto_list[proto]);
- lastp = &(*lastp)->next;
- }
- }
- UNLOCK (engine_info_lock);
- *info = engine_info;
- return 0;
-}
-
\f
#define LINELENGTH 80
+/* Retrieve the version number from the --version output of the
+ program FILE_NAME. */
char *
-_gpgme_get_program_version (const char *const path)
+_gpgme_get_program_version (const char *const file_name)
{
char line[LINELENGTH] = "";
int linelen = 0;
char *mark = NULL;
int rp[2];
int nread;
- char *argv[] = {NULL /* path */, "--version", 0};
+ char *argv[] = {NULL /* file_name */, "--version", 0};
struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
int status;
- if (!path)
+ if (!file_name)
return NULL;
- argv[0] = (char *) path;
+ argv[0] = (char *) file_name;
if (_gpgme_io_pipe (rp, 1) < 0)
return NULL;
pfd[0].fd = rp[1];
cfd[0].fd = rp[1];
- status = _gpgme_io_spawn (path, argv, cfd, pfd);
+ status = _gpgme_io_spawn (file_name, argv, cfd, pfd);
if (status < 0)
{
_gpgme_io_close (rp[0]);
2003-01-30 Marcus Brinkmann <marcus@g10code.de>
+ * t-engine-info.c: Use file_name instead path throughout.
+
* Makefile.am (TESTS): Add t-engine-info.
* t-engine-info.c: New file.
* gpg/t-encrypt.c (main): Don't print engine info.
\f
void
check_engine_info (GpgmeEngineInfo info, GpgmeProtocol protocol,
- const char *path, const char *req_version)
+ const char *file_name, const char *req_version)
{
if (info->protocol != protocol)
{
info->protocol, protocol);
exit (1);
}
- if (strcmp (info->path, path))
+ if (strcmp (info->file_name, file_name))
{
- fprintf (stderr, "Unexpected path to executable %s (expected %s instead)",
- info->path, path);
+ fprintf (stderr, "Unexpected file name to executable %s (expected %s instead)",
+ info->file_name, file_name);
exit (1);
}
if (strcmp (info->req_version, req_version))