uci: use per-session save directory and register session destroy callback to purge...
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 3 Sep 2013 10:42:54 +0000 (12:42 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Tue, 3 Sep 2013 11:40:47 +0000 (13:40 +0200)
uci.c
uci.h

diff --git a/uci.c b/uci.c
index aba897ee330b43494826097a5d6e73998c6ced0f..34c6830742dcdb52956d26a88a865e15162e7661 100644 (file)
--- a/uci.c
+++ b/uci.c
@@ -168,6 +168,28 @@ rpc_uci_status(void)
        }
 }
 
+/*
+ * Setup per-session delta save directory. If the passed "sid" blob attribute
+ * pointer is NULL then the precedure was not invoked through the ubus-rpc so
+ * we do not perform session isolation and use the default save directory.
+ */
+static void
+rpc_uci_set_savedir(struct blob_attr *sid)
+{
+       char path[PATH_MAX];
+
+       if (!sid)
+       {
+               uci_set_savedir(cursor, "/tmp/.uci");
+               return;
+       }
+
+       snprintf(path, sizeof(path) - 1,
+                "/tmp/.uci-rpc-%s", (char *)blobmsg_data(sid));
+
+       uci_set_savedir(cursor, path);
+}
+
 /*
  * Test read access to given config. If the passed "sid" blob attribute pointer
  * is NULL then the precedure was not invoked through the ubus-rpc so we do not
@@ -176,6 +198,8 @@ rpc_uci_status(void)
 static bool
 rpc_uci_read_access(struct blob_attr *sid, struct blob_attr *config)
 {
+       rpc_uci_set_savedir(sid);
+
        if (!sid)
                return true;
 
@@ -191,6 +215,8 @@ rpc_uci_read_access(struct blob_attr *sid, struct blob_attr *config)
 static bool
 rpc_uci_write_access(struct blob_attr *sid, struct blob_attr *config)
 {
+       rpc_uci_set_savedir(sid);
+
        if (!sid)
                return true;
 
@@ -1085,6 +1111,69 @@ out:
 }
 
 
+/*
+ * Remove given delta save directory (if any).
+ */
+static void
+rpc_uci_purge_savedir(const char *path)
+{
+       DIR *d;
+       struct stat s;
+       struct dirent *e;
+       char file[PATH_MAX];
+
+       if (stat(path, &s) || !S_ISDIR(s.st_mode))
+               return;
+
+       if ((d = opendir(path)) != NULL)
+       {
+               while ((e = readdir(d)) != NULL)
+               {
+                       snprintf(file, sizeof(file) - 1, "%s/%s", path, e->d_name);
+
+                       if (stat(file, &s) || !S_ISREG(s.st_mode))
+                               continue;
+
+                       unlink(file);
+               }
+
+               closedir(d);
+
+               rmdir(path);
+       }
+}
+
+/*
+ * Session destroy callback to purge associated delta directory.
+ */
+static void
+rpc_uci_purge_savedir_cb(struct rpc_session *ses, void *priv)
+{
+       char path[PATH_MAX];
+
+       snprintf(path, sizeof(path) - 1, "/tmp/.uci-rpc-%s", ses->id);
+       rpc_uci_purge_savedir(path);
+}
+
+/*
+ * Removes all delta directories which match the /tmp/.uci-rpc-* pattern.
+ * This is used to clean up garbage when starting rpcd.
+ */
+static void
+rpc_uci_purge_savedirs(void)
+{
+       int i;
+       glob_t gl;
+
+       if (!glob("/tmp/.uci-rpc-*", 0, NULL, &gl))
+       {
+               for (i = 0; i < gl.gl_pathc; i++)
+                       rpc_uci_purge_savedir(gl.gl_pathv[i]);
+
+               globfree(&gl);
+       }
+}
+
 int rpc_uci_api_init(struct ubus_context *ctx)
 {
        static const struct ubus_method uci_methods[] = {
@@ -1110,10 +1199,17 @@ int rpc_uci_api_init(struct ubus_context *ctx)
                .n_methods = ARRAY_SIZE(uci_methods),
        };
 
+       static struct rpc_session_cb cb = {
+               .cb = rpc_uci_purge_savedir_cb
+       };
+
        cursor = uci_alloc_context();
 
        if (!cursor)
                return UBUS_STATUS_UNKNOWN_ERROR;
 
+       rpc_uci_purge_savedirs();
+       rpc_session_destroy_cb(&cb);
+
        return ubus_add_object(ctx, &obj);
 }
diff --git a/uci.h b/uci.h
index aa1e79707e03f3d054234db2db19b1dd60642442..a4f79e26ef6726a6baf89594a487292fd4748363 100644 (file)
--- a/uci.h
+++ b/uci.h
 #ifndef __RPC_UCI_H
 #define __RPC_UCI_H
 
+#include <glob.h>
+#include <limits.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include <inttypes.h>
 #include <libubus.h>
 #include <uci.h>