]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/nfsdcld/sqlite.c
nfsdcld: add support for dropping capabilities
[nfs-utils.git] / utils / nfsdcld / sqlite.c
index a198c34aa6537737a350da2081a0819007482336..bb2519de804d727cc5ae79299b5aa73dac89a7c0 100644 (file)
@@ -38,6 +38,7 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <dirent.h>
 #include <errno.h>
 #include <event.h>
 #include <stdbool.h>
 
 #define CLD_SQLITE_SCHEMA_VERSION 1
 
-#ifndef CLD_SQLITE_TOPDIR
-#define CLD_SQLITE_TOPDIR NFS_STATEDIR "/nfsdcld"
-#endif
-
 /* in milliseconds */
 #define CLD_SQLITE_BUSY_TIMEOUT 10000
 
@@ -111,7 +108,7 @@ sqlite_maindb_init(char *topdir)
        char *err = NULL;
        sqlite3_stmt *stmt = NULL;
 
-       sqlite_topdir = topdir ? topdir : CLD_SQLITE_TOPDIR;
+       sqlite_topdir = topdir;
 
        ret = mkdir_if_not_exist(sqlite_topdir);
        if (ret)
@@ -287,3 +284,103 @@ out_err:
        sqlite3_finalize(stmt);
        return ret;
 }
+
+/*
+ * Is the given clname in the clients table? If so, then update its timestamp
+ * and return success. If the record isn't present, or the update fails, then
+ * return an error.
+ */
+int
+sqlite_check_client(const unsigned char *clname, const size_t namelen)
+{
+       int ret;
+       sqlite3_stmt *stmt = NULL;
+
+       ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE "
+                                     "id==?", -1, &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               xlog(L_ERROR, "%s: unable to prepare update statement: %s",
+                               __func__, sqlite3_errmsg(dbh));
+               goto out_err;
+       }
+
+       ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
+                               SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               xlog(L_ERROR, "%s: bind blob failed: %s",
+                               __func__, sqlite3_errmsg(dbh));
+               goto out_err;
+       }
+
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_ROW) {
+               xlog(L_ERROR, "%s: unexpected return code from select: %d",
+                               __func__, ret);
+               goto out_err;
+       }
+
+       ret = sqlite3_column_int(stmt, 0);
+       xlog(D_GENERAL, "%s: select returned %d rows", ret);
+       if (ret != 1) {
+               ret = -EACCES;
+               goto out_err;
+       }
+
+       sqlite3_finalize(stmt);
+       stmt = NULL;
+       ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET "
+                                     "time=strftime('%s', 'now') WHERE id==?",
+                                -1, &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               xlog(L_ERROR, "%s: unable to prepare update statement: %s",
+                               __func__, sqlite3_errmsg(dbh));
+               goto out_err;
+       }
+
+       ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
+                               SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               xlog(L_ERROR, "%s: bind blob failed: %s",
+                               __func__, sqlite3_errmsg(dbh));
+               goto out_err;
+       }
+
+       ret = sqlite3_step(stmt);
+       if (ret == SQLITE_DONE)
+               ret = SQLITE_OK;
+       else
+               xlog(L_ERROR, "%s: unexpected return code from update: %s",
+                               __func__, sqlite3_errmsg(dbh));
+
+out_err:
+       xlog(D_GENERAL, "%s: returning %d", __func__, ret);
+       sqlite3_finalize(stmt);
+       return ret;
+}
+
+/*
+ * remove any client records that were not reclaimed since grace_start.
+ */
+int
+sqlite_remove_unreclaimed(time_t grace_start)
+{
+       int ret;
+       char *err = NULL;
+
+       ret = snprintf(buf, sizeof(buf), "DELETE FROM clients WHERE time < %ld",
+                       grace_start);
+       if (ret < 0) {
+               return ret;
+       } else if ((size_t)ret >= sizeof(buf)) {
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = sqlite3_exec(dbh, buf, NULL, NULL, &err);
+       if (ret != SQLITE_OK)
+               xlog(L_ERROR, "%s: delete failed: %s", __func__, err);
+
+       xlog(D_GENERAL, "%s: returning %d", __func__, ret);
+       sqlite3_free(err);
+       return ret;
+}