From f8fbd9e7346ee0c3b09271ec2cdb589282eae1c9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 25 Sep 2020 11:52:11 +0200 Subject: [PATCH] keyboxd: Make use of the config table * kbx/backend-sqlite.c (DATABASE_VERSION): New. (table_definitions): Make column name of table config unique. (create_or_open_database): Read and set the database version. (get_config_value, set_config_value): New. -- Well, kind of. For now we just store the database version. Note that for existing databases the config table should first be dropped so that the UNIQUE constraint can be used. Signed-off-by: Werner Koch --- kbx/backend-sqlite.c | 121 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/kbx/backend-sqlite.c b/kbx/backend-sqlite.c index c31415694..f03cf1a31 100644 --- a/kbx/backend-sqlite.c +++ b/kbx/backend-sqlite.c @@ -96,7 +96,10 @@ static sqlite3 *database_hd; /* A lockfile used make sure only we are accessing the database. */ static dotlock_t database_lock; +/* The version of our current database schema. */ +#define DATABASE_VERSION 1 +/* Table definitions for the database. */ static struct { const char *sql; @@ -111,7 +114,7 @@ static struct * created = */ { "CREATE TABLE IF NOT EXISTS config (" - "name TEXT NOT NULL," + "name TEXT NOT NULL UNIQUE," "value TEXT NOT NULL " ")", 1 }, @@ -189,8 +192,12 @@ static struct }; +/*-- prototypes --*/ +static gpg_error_t get_config_value (const char *name, char **r_value); +static gpg_error_t set_config_value (const char *name, const char *value); + /* Take a lock for accessing SQLite. */ static void acquire_mutex (void) @@ -528,6 +535,9 @@ create_or_open_database (const char *filename) gpg_error_t err; int res; int idx; + char *value; + int dbversion; + int setdbversion = 0; if (database_hd) return 0; /* Already initialized. */ @@ -588,12 +598,52 @@ create_or_open_database (const char *filename) if (table_definitions[idx].special == 1) { /* Check and create dbversion etc entries. */ - // FIXME + err = get_config_value ("dbversion", &value); + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + { + dbversion = 0; + setdbversion = 1; + } + else if (err) + { + log_error ("error reading database version: %s\n", + gpg_strerror (err)); + err = 0; + dbversion = 0; + } + else if ((dbversion = atoi (value)) < 1) + { + log_error ("database version %d is not valid\n", dbversion); + dbversion = 0; + } + log_info ("database version: %d\n", dbversion); + + xfree (value); + err = get_config_value ("created", &value); + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + log_info ("database created: %.50s\n", "[unknown]"); + else if (err) + log_error ("error getting database creation date: %s\n", + gpg_strerror (err)); + else + log_info ("database created: %.50s\n", value); + + xfree (value); + value = NULL; } } if (!opt.quiet) log_info (_("database '%s' created\n"), filename); + + if (setdbversion) + { + err = set_config_value ("dbversion", STR2(DATABASE_VERSION)); + if (!err) + err = set_config_value ("created", isotimestamp (gnupg_get_time ())); + } + + err = 0; leave: @@ -717,6 +767,73 @@ be_sqlite_commit (void) } +/* Return a value from the config table. NAME most not have quotes + * etc. If no error is returned the caller must xfree the value + * stored at R_VALUE. On error NULL is stored there. */ +static gpg_error_t +get_config_value (const char *name, char **r_value) +{ + gpg_error_t err; + sqlite3_stmt *stmt; + char *sqlstr; + const char *s; + + *r_value = NULL; + + sqlstr = strconcat ("SELECT value FROM config WHERE name='", name, "'", NULL); + if (!sqlstr) + return gpg_error_from_syserror (); + + err = run_sql_prepare (sqlstr, NULL, &stmt); + xfree (sqlstr); + if (err) + return err; + + err = run_sql_step_for_select (stmt); + if (gpg_err_code (err) == GPG_ERR_SQL_ROW) + { + s = sqlite3_column_text (stmt, 0); + *r_value = xtrystrdup (s? s : ""); + if (!*r_value) + err = gpg_error_from_syserror (); + else + err = 0; + } + else if (gpg_err_code (err) == GPG_ERR_SQL_DONE) + err = gpg_error (GPG_ERR_NOT_FOUND); + else + log_assert (err); /* We'll never see 0 here. */ + + sqlite3_finalize (stmt); + + return err; +} + + +/* Insert or update a value in the config table. */ +static gpg_error_t +set_config_value (const char *name, const char *value) +{ + gpg_error_t err; + sqlite3_stmt *stmt; + + err = run_sql_prepare ("INSERT OR REPLACE INTO config(name,value)" + " VALUES(?1,?2)", NULL, &stmt); + if (err) + return err; + + err = run_sql_bind_text (stmt, 1, name); + if (!err) + err = run_sql_bind_text (stmt, 2, value); + if (!err) + err = run_sql_step (stmt); + + sqlite3_finalize (stmt); + + return err; +} + + /* Run a select for the search given by (DESC,NDESC). The data is not * returned but stored in the request item. */ static gpg_error_t