2 * Copyright (C) 2011 Red Hat, Jeff Layton <jlayton@redhat.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 * This file contains the code to manage the sqlite backend database for the
24 * clstated upcall daemon.
26 * The main database is called main.sqlite and contains the following tables:
28 * parameters: simple key/value pairs for storing database info
30 * clients: one column containing a BLOB with the as sent by the client
31 * and a timestamp (in epoch seconds) of when the record was
34 * FIXME: should we also record the fsid being accessed?
39 #endif /* HAVE_CONFIG_H */
47 #include <sys/types.h>
51 #include <linux/limits.h>
55 #define CLD_SQLITE_SCHEMA_VERSION 1
58 #define CLD_SQLITE_BUSY_TIMEOUT 10000
60 /* private data structures */
62 /* global variables */
64 /* reusable pathname and sql command buffer */
65 static char buf[PATH_MAX];
67 /* global database handle */
70 /* forward declarations */
72 /* make a directory, ignoring EEXIST errors unless it's not a directory */
74 mkdir_if_not_exist(const char *dirname)
79 ret = mkdir(dirname, S_IRWXU);
80 if (ret && errno != EEXIST)
83 ret = stat(dirname, &statbuf);
87 if (!S_ISDIR(statbuf.st_mode))
93 /* Open the database and set up the database handle for it */
95 sqlite_prepare_dbh(const char *topdir)
99 /* Do nothing if the database handle is already set up */
103 ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", topdir);
107 buf[PATH_MAX - 1] = '\0';
109 ret = sqlite3_open(buf, &dbh);
110 if (ret != SQLITE_OK) {
111 xlog(L_ERROR, "Unable to open main database: %d", ret);
116 ret = sqlite3_busy_timeout(dbh, CLD_SQLITE_BUSY_TIMEOUT);
117 if (ret != SQLITE_OK) {
118 xlog(L_ERROR, "Unable to set sqlite busy timeout: %d", ret);
127 * Open the "main" database, and attempt to initialize it by creating the
128 * parameters table and inserting the schema version into it. Ignore any errors
129 * from that, and then attempt to select the version out of it again. If the
130 * version appears wrong, then assume that the DB is corrupt or has been
131 * upgraded, and return an error. If all of that works, then attempt to create
132 * the "clients" table.
135 sqlite_maindb_init(const char *topdir)
139 sqlite3_stmt *stmt = NULL;
141 ret = mkdir_if_not_exist(topdir);
145 ret = sqlite_prepare_dbh(topdir);
149 /* Try to create table */
150 ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS parameters "
151 "(key TEXT PRIMARY KEY, value TEXT);",
153 if (ret != SQLITE_OK) {
154 xlog(L_ERROR, "Unable to create parameter table: %d", ret);
158 /* insert version into table -- ignore error if it fails */
159 ret = snprintf(buf, sizeof(buf),
160 "INSERT OR IGNORE INTO parameters values (\"version\", "
161 "\"%d\");", CLD_SQLITE_SCHEMA_VERSION);
164 } else if ((size_t)ret >= sizeof(buf)) {
169 ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err);
170 if (ret != SQLITE_OK) {
171 xlog(L_ERROR, "Unable to insert into parameter table: %d",
176 ret = sqlite3_prepare_v2(dbh,
177 "SELECT value FROM parameters WHERE key == \"version\";",
179 if (ret != SQLITE_OK) {
180 xlog(L_ERROR, "Unable to prepare select statement: %d", ret);
184 /* check schema version */
185 ret = sqlite3_step(stmt);
186 if (ret != SQLITE_ROW) {
187 xlog(L_ERROR, "Select statement execution failed: %s",
188 sqlite3_errmsg(dbh));
192 /* process SELECT result */
193 ret = sqlite3_column_int(stmt, 0);
194 if (ret != CLD_SQLITE_SCHEMA_VERSION) {
195 xlog(L_ERROR, "Unsupported database schema version! "
196 "Expected %d, got %d.",
197 CLD_SQLITE_SCHEMA_VERSION, ret);
202 /* now create the "clients" table */
203 ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS clients "
204 "(id BLOB PRIMARY KEY, time INTEGER);",
206 if (ret != SQLITE_OK) {
207 xlog(L_ERROR, "Unable to create clients table: %s", err);
212 sqlite3_finalize(stmt);
217 xlog(L_ERROR, "sqlite error: %s", err);
220 sqlite3_finalize(stmt);
226 * Create a client record
228 * Returns a non-zero sqlite error code, or SQLITE_OK (aka 0)
231 sqlite_insert_client(const unsigned char *clname, const size_t namelen)
234 sqlite3_stmt *stmt = NULL;
236 ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients VALUES "
237 "(?, strftime('%s', 'now'));", -1,
239 if (ret != SQLITE_OK) {
240 xlog(L_ERROR, "%s: insert statement prepare failed: %s",
241 __func__, sqlite3_errmsg(dbh));
245 ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
247 if (ret != SQLITE_OK) {
248 xlog(L_ERROR, "%s: bind blob failed: %s", __func__,
249 sqlite3_errmsg(dbh));
253 ret = sqlite3_step(stmt);
254 if (ret == SQLITE_DONE)
257 xlog(L_ERROR, "%s: unexpected return code from insert: %s",
258 __func__, sqlite3_errmsg(dbh));
261 xlog(D_GENERAL, "%s: returning %d", __func__, ret);
262 sqlite3_finalize(stmt);
266 /* Remove a client record */
268 sqlite_remove_client(const unsigned char *clname, const size_t namelen)
271 sqlite3_stmt *stmt = NULL;
273 ret = sqlite3_prepare_v2(dbh, "DELETE FROM clients WHERE id==?", -1,
275 if (ret != SQLITE_OK) {
276 xlog(L_ERROR, "%s: statement prepare failed: %s",
277 __func__, sqlite3_errmsg(dbh));
281 ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
283 if (ret != SQLITE_OK) {
284 xlog(L_ERROR, "%s: bind blob failed: %s", __func__,
285 sqlite3_errmsg(dbh));
289 ret = sqlite3_step(stmt);
290 if (ret == SQLITE_DONE)
293 xlog(L_ERROR, "%s: unexpected return code from delete: %d",
297 xlog(D_GENERAL, "%s: returning %d", __func__, ret);
298 sqlite3_finalize(stmt);
303 * Is the given clname in the clients table? If so, then update its timestamp
304 * and return success. If the record isn't present, or the update fails, then
308 sqlite_check_client(const unsigned char *clname, const size_t namelen)
311 sqlite3_stmt *stmt = NULL;
313 ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE "
314 "id==?", -1, &stmt, NULL);
315 if (ret != SQLITE_OK) {
316 xlog(L_ERROR, "%s: unable to prepare update statement: %s",
317 __func__, sqlite3_errmsg(dbh));
321 ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
323 if (ret != SQLITE_OK) {
324 xlog(L_ERROR, "%s: bind blob failed: %s",
325 __func__, sqlite3_errmsg(dbh));
329 ret = sqlite3_step(stmt);
330 if (ret != SQLITE_ROW) {
331 xlog(L_ERROR, "%s: unexpected return code from select: %d",
336 ret = sqlite3_column_int(stmt, 0);
337 xlog(D_GENERAL, "%s: select returned %d rows", __func__, ret);
343 sqlite3_finalize(stmt);
345 ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET "
346 "time=strftime('%s', 'now') WHERE id==?",
348 if (ret != SQLITE_OK) {
349 xlog(L_ERROR, "%s: unable to prepare update statement: %s",
350 __func__, sqlite3_errmsg(dbh));
354 ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
356 if (ret != SQLITE_OK) {
357 xlog(L_ERROR, "%s: bind blob failed: %s",
358 __func__, sqlite3_errmsg(dbh));
362 ret = sqlite3_step(stmt);
363 if (ret == SQLITE_DONE)
366 xlog(L_ERROR, "%s: unexpected return code from update: %s",
367 __func__, sqlite3_errmsg(dbh));
370 xlog(D_GENERAL, "%s: returning %d", __func__, ret);
371 sqlite3_finalize(stmt);
376 * remove any client records that were not reclaimed since grace_start.
379 sqlite_remove_unreclaimed(time_t grace_start)
384 ret = snprintf(buf, sizeof(buf), "DELETE FROM clients WHERE time < %ld",
388 } else if ((size_t)ret >= sizeof(buf)) {
393 ret = sqlite3_exec(dbh, buf, NULL, NULL, &err);
394 if (ret != SQLITE_OK)
395 xlog(L_ERROR, "%s: delete failed: %s", __func__, err);
397 xlog(D_GENERAL, "%s: returning %d", __func__, ret);