summaryrefslogtreecommitdiffstats
path: root/source3/lib/server_id_db_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/server_id_db_util.c')
-rw-r--r--source3/lib/server_id_db_util.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/source3/lib/server_id_db_util.c b/source3/lib/server_id_db_util.c
new file mode 100644
index 0000000..e73af24
--- /dev/null
+++ b/source3/lib/server_id_db_util.c
@@ -0,0 +1,99 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Utils around server_id_db with more dependencies
+ * Copyright (C) Volker Lendecke 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "server_id_db_util.h"
+#include "lib/util/server_id.h"
+#include "serverid.h"
+#include "lib/util/samba_util.h"
+
+static int server_id_db_check_exclusive(
+ struct server_id_db *db, const char *name,
+ unsigned num_servers, struct server_id *servers);
+
+int server_id_db_set_exclusive(struct server_id_db *db, const char *name)
+{
+ int ret;
+ unsigned num_servers;
+ struct server_id *servers;
+
+ ret = server_id_db_add(db, name);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = server_id_db_lookup(db, name, talloc_tos(),
+ &num_servers, &servers);
+ if (ret != 0) {
+ goto done;
+ }
+
+ /*
+ * Remove entries from the server_id_db for processes that have died
+ * and could not clean up. This is racy, as two processes could
+ * simultaneously try to register a name. Both would succeed in the
+ * server_id_db_add call, and both would see their peer active during
+ * the check_exclusive call. Both would get an EEXIST, and nobody
+ * would be able to register itself. But this is okay, as this is
+ * meant to be a cleanup routine, and normally only one daemon should
+ * start up at a time anyway. Getting this "right" would mean we would
+ * have to add locking to server_id_db, or add a dependency on
+ * serverids_exist to server_id_db. Both are too heavy-weight for my
+ * taste.
+ */
+
+ ret = server_id_db_check_exclusive(db, name, num_servers, servers);
+ TALLOC_FREE(servers);
+
+done:
+ if (ret != 0) {
+ server_id_db_remove(db, name);
+ }
+ return ret;
+}
+
+static int server_id_db_check_exclusive(
+ struct server_id_db *db, const char *name,
+ unsigned num_servers, struct server_id *servers)
+{
+ struct server_id me = server_id_db_pid(db);
+ unsigned i;
+
+ for (i=0; i<num_servers; i++) {
+ int ret;
+
+ if (server_id_same_process(&me, &servers[i])) {
+ /*
+ * I am always around ... :-)
+ */
+ continue;
+ }
+
+ if (serverid_exists(&servers[i])) {
+ return EEXIST;
+ }
+
+ ret = server_id_db_prune_name(db, name, servers[i]);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}