Currently, postfix creates (empty, table-less) sqlite database if not exists,
which is kinda unexpected provided postfix can not even load data to it.
Also, the database is always open in read-write mode, despite postfix only
performs queries.

Also, when open actually fails, the error message is unhelpful:

Unfortunately, sqlite does not give good hint about the reason why
the database can't be open, for example:

  fatal: sqlite:/etc/postfix/db.cf: Can't open database: \
        unable to open database file?

Obviously this is an sqlite omission/defect, but we can work around it
in postfix by also providing the strerror(errno) here.

This patch does a few things:

 1. It changes sqlite3_open() into sqlite3_open_v2() which accepts
    2 more arguments, notable open flags (similar to open(2)) - where
    we only pass SQLITE_OPEN_READONLY, without SQLITE_OPEN_CREATE.

 2. It replaces msg_fatal() call when we weren't able to open the
    database file into dict_surrogate() like in other places when
    open error occurs, and continues.

 3. it calls a new common function dict_sqlite_free() to free the just
    allocated DICT_SQLITE, in the same manner as dict_sqlite_close()
    does (the function is copied from there).

 4. It makes the error message much more useful by including the
    database file name it tried to open, and strerror(errno) (%m),
    so the error message (when attempting to use the dict_surrogate)
    becomes:

  fatal: sqlite:/etc/postfix/db.cf: open database t.dbx: \
        unable to open database file: No such file or directory

sqlite3_open_v2() is available since sqlite version 3.5.0 (see
https://www.sqlite.org/34to35.html), and compatibility wrapper is
provided for older releases, exactly like sqlite3_prepare_v2(). 

Signed-off-by: Michael Tokarev <m...@tls.msk.ru>

diff --git a/src/global/dict_sqlite.c b/src/global/dict_sqlite.c
index 7d6608a6..c26d4045 100644
--- a/src/global/dict_sqlite.c
+++ b/src/global/dict_sqlite.c
@@ -59,6 +59,9 @@
 #if !defined(SQLITE_VERSION_NUMBER) || (SQLITE_VERSION_NUMBER < 3005004)
 #define sqlite3_prepare_v2 sqlite3_prepare
 #endif
+#if !defined(SQLITE_VERSION_NUMBER) || (SQLITE_VERSION_NUMBER < 3005000)
+#define sqlite3_open_v2(fname,ppDB,flags,zVfs) sqlite_open(fname,ppDB)
+#endif
 
 /* Utility library. */
 
@@ -102,6 +105,21 @@ static void dict_sqlite_quote(DICT *dict, const char 
*raw_text, VSTRING *result)
     sqlite3_free(quoted_text);
 }
 
+/* dict_sqlite_free - free the database-related fields */
+
+static void dict_sqlite_free(DICT_SQLITE *dict_sqlite)
+{
+    cfg_parser_free(dict_sqlite->parser);
+    myfree(dict_sqlite->dbpath);
+    myfree(dict_sqlite->query);
+    myfree(dict_sqlite->result_format);
+    if (dict_sqlite->ctx)
+       db_common_free_ctx(dict_sqlite->ctx);
+    if (dict_sqlite->dict.fold_buf)
+       vstring_free(dict_sqlite->dict.fold_buf);
+    dict_free(&dict_sqlite->dict);
+}
+
 /* dict_sqlite_close - close the database */
 
 static void dict_sqlite_close(DICT *dict)
@@ -114,15 +132,8 @@ static void dict_sqlite_close(DICT *dict)
 
     if (sqlite3_close(dict_sqlite->db) != SQLITE_OK)
        msg_fatal("%s: close %s failed", myname, dict_sqlite->parser->name);
-    cfg_parser_free(dict_sqlite->parser);
-    myfree(dict_sqlite->dbpath);
-    myfree(dict_sqlite->query);
-    myfree(dict_sqlite->result_format);
-    if (dict_sqlite->ctx)
-       db_common_free_ctx(dict_sqlite->ctx);
-    if (dict->fold_buf)
-       vstring_free(dict->fold_buf);
-    dict_free(dict);
+
+    dict_sqlite_free(dict_sqlite);
 }
 
 /* dict_sqlite_lookup - find database entry */
@@ -320,9 +331,15 @@ DICT   *dict_sqlite_open(const char *name, int open_flags, 
int dict_flags)
     dict_sqlite->parser = parser;
     sqlite_parse_config(dict_sqlite, name);
 
-    if (sqlite3_open(dict_sqlite->dbpath, &dict_sqlite->db))
-       msg_fatal("%s:%s: Can't open database: %s\n",
-                 DICT_TYPE_SQLITE, name, sqlite3_errmsg(dict_sqlite->db));
+    if (sqlite3_open_v2(dict_sqlite->dbpath, &dict_sqlite->db,
+                       SQLITE_OPEN_READONLY, NULL)) {
+       DICT *dict = dict_surrogate(DICT_TYPE_SQLITE, name, open_flags,
+                           dict_flags, "%s:%s: open database %s: %s: %m",
+                           DICT_TYPE_SQLITE, name, dict_sqlite->dbpath,
+                           sqlite3_errmsg(dict_sqlite->db));
+       dict_sqlite_free(dict_sqlite);
+       return dict;
+    }
 
     dict_sqlite->dict.owner = cfg_get_owner(dict_sqlite->parser);
 
_______________________________________________
Postfix-devel mailing list -- postfix-devel@postfix.org
To unsubscribe send an email to postfix-devel-le...@postfix.org

Reply via email to