ctdb-logging: Move variable debug_extra from debug.*
[Samba.git] / source3 / lib / messages_dgm.c
blob659b835e9272daa5c0260e4d64e7e1bf91bd71fa
1 /*
2 * Unix SMB/CIFS implementation.
3 * Samba internal messaging functions
4 * Copyright (C) 2013 by Volker Lendecke
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "lib/util/data_blob.h"
22 #include "lib/util/debug.h"
23 #include "lib/unix_msg/unix_msg.h"
24 #include "system/filesys.h"
25 #include "lib/messages_dgm.h"
26 #include "lib/param/param.h"
27 #include "poll_funcs/poll_funcs_tevent.h"
28 #include "unix_msg/unix_msg.h"
30 struct messaging_dgm_context {
31 pid_t pid;
32 struct poll_funcs *msg_callbacks;
33 void *tevent_handle;
34 struct unix_msg_ctx *dgm_ctx;
35 char *cache_dir;
36 int lockfile_fd;
38 void (*recv_cb)(const uint8_t *msg,
39 size_t msg_len,
40 void *private_data);
41 void *recv_cb_private_data;
43 bool *have_dgm_context;
46 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
47 uint8_t *msg, size_t msg_len,
48 void *private_data);
50 static char *messaging_dgm_lockfile_name(TALLOC_CTX *mem_ctx,
51 const char *cache_dir,
52 pid_t pid)
54 return talloc_asprintf(mem_ctx, "%s/lck/%u", cache_dir,
55 (unsigned)pid);
58 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c);
60 static int messaging_dgm_lockfile_create(TALLOC_CTX *tmp_ctx,
61 const char *cache_dir,
62 uid_t dir_owner, pid_t pid,
63 int *plockfile_fd, uint64_t unique)
65 fstring buf;
66 char *dir;
67 char *lockfile_name;
68 int lockfile_fd;
69 struct flock lck;
70 int unique_len, ret;
71 ssize_t written;
72 bool ok;
74 dir = talloc_asprintf(tmp_ctx, "%s/lck", cache_dir);
75 if (dir == NULL) {
76 return ENOMEM;
79 ok = directory_create_or_exist_strict(dir, dir_owner, 0755);
80 TALLOC_FREE(dir);
81 if (!ok) {
82 ret = errno;
83 DEBUG(1, ("%s: Could not create lock directory: %s\n",
84 __func__, strerror(ret)));
85 return ret;
88 lockfile_name = messaging_dgm_lockfile_name(tmp_ctx, cache_dir,
89 (unsigned)pid);
90 if (lockfile_name == NULL) {
91 return ENOMEM;
94 /* no O_EXCL, existence check is via the fcntl lock */
96 lockfile_fd = open(lockfile_name, O_NONBLOCK|O_CREAT|O_WRONLY, 0644);
97 if (lockfile_fd == -1) {
98 ret = errno;
99 DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno)));
100 goto fail_free;
103 lck = (struct flock) {
104 .l_type = F_WRLCK,
105 .l_whence = SEEK_SET
108 ret = fcntl(lockfile_fd, F_SETLK, &lck);
109 if (ret == -1) {
110 ret = errno;
111 DEBUG(1, ("%s: fcntl failed: %s\n", __func__, strerror(ret)));
112 goto fail_close;
115 unique_len = snprintf(buf, sizeof(buf), "%ju\n", (uintmax_t)unique);
117 /* shorten a potentially preexisting file */
119 ret = ftruncate(lockfile_fd, unique_len);
120 if (ret == -1) {
121 ret = errno;
122 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__,
123 strerror(ret)));
124 goto fail_unlink;
127 written = write(lockfile_fd, buf, unique_len);
128 if (written != unique_len) {
129 ret = errno;
130 DEBUG(1, ("%s: write failed: %s\n", __func__, strerror(ret)));
131 goto fail_unlink;
134 TALLOC_FREE(lockfile_name);
135 *plockfile_fd = lockfile_fd;
136 return 0;
138 fail_unlink:
139 unlink(lockfile_name);
140 fail_close:
141 close(lockfile_fd);
142 fail_free:
143 TALLOC_FREE(lockfile_name);
144 return ret;
147 static int messaging_dgm_lockfile_remove(TALLOC_CTX *tmp_ctx,
148 const char *cache_dir, pid_t pid)
150 char *lockfile_name;
151 int ret;
153 lockfile_name = messaging_dgm_lockfile_name(
154 tmp_ctx, cache_dir, pid);
155 if (lockfile_name == NULL) {
156 return ENOMEM;
159 ret = unlink(lockfile_name);
160 if (ret == -1) {
161 ret = errno;
162 DEBUG(10, ("%s: unlink(%s) failed: %s\n", __func__,
163 lockfile_name, strerror(ret)));
166 TALLOC_FREE(lockfile_name);
167 return ret;
170 int messaging_dgm_init(TALLOC_CTX *mem_ctx,
171 struct tevent_context *ev,
172 struct server_id pid,
173 const char *cache_dir,
174 uid_t dir_owner,
175 void (*recv_cb)(const uint8_t *msg,
176 size_t msg_len,
177 void *private_data),
178 void *recv_cb_private_data,
179 struct messaging_dgm_context **pctx)
181 struct messaging_dgm_context *ctx;
182 int ret;
183 bool ok;
184 char *socket_dir;
185 struct sockaddr_un socket_address;
186 size_t sockname_len;
187 uint64_t cookie;
188 static bool have_dgm_context = false;
190 if (have_dgm_context) {
191 return EEXIST;
194 ctx = talloc_zero(mem_ctx, struct messaging_dgm_context);
195 if (ctx == NULL) {
196 goto fail_nomem;
198 ctx->pid = pid.pid;
199 ctx->recv_cb = recv_cb;
200 ctx->recv_cb_private_data = recv_cb_private_data;
202 ctx->cache_dir = talloc_strdup(ctx, cache_dir);
203 if (ctx->cache_dir == NULL) {
204 goto fail_nomem;
206 socket_dir = talloc_asprintf(ctx, "%s/msg", cache_dir);
207 if (socket_dir == NULL) {
208 goto fail_nomem;
211 socket_address = (struct sockaddr_un) { .sun_family = AF_UNIX };
212 sockname_len = snprintf(socket_address.sun_path,
213 sizeof(socket_address.sun_path),
214 "%s/%u", socket_dir, (unsigned)pid.pid);
215 if (sockname_len >= sizeof(socket_address.sun_path)) {
216 TALLOC_FREE(ctx);
217 return ENAMETOOLONG;
220 ret = messaging_dgm_lockfile_create(ctx, cache_dir, dir_owner, pid.pid,
221 &ctx->lockfile_fd, pid.unique_id);
222 if (ret != 0) {
223 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
224 __func__, strerror(ret)));
225 TALLOC_FREE(ctx);
226 return ret;
229 ctx->msg_callbacks = poll_funcs_init_tevent(ctx);
230 if (ctx->msg_callbacks == NULL) {
231 goto fail_nomem;
234 ctx->tevent_handle = poll_funcs_tevent_register(
235 ctx, ctx->msg_callbacks, ev);
236 if (ctx->tevent_handle == NULL) {
237 goto fail_nomem;
240 ok = directory_create_or_exist_strict(socket_dir, dir_owner, 0700);
241 if (!ok) {
242 DEBUG(1, ("Could not create socket directory\n"));
243 TALLOC_FREE(ctx);
244 return EACCES;
246 TALLOC_FREE(socket_dir);
248 unlink(socket_address.sun_path);
250 generate_random_buffer((uint8_t *)&cookie, sizeof(cookie));
252 ret = unix_msg_init(&socket_address, ctx->msg_callbacks, 1024, cookie,
253 messaging_dgm_recv, ctx, &ctx->dgm_ctx);
254 if (ret != 0) {
255 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret)));
256 TALLOC_FREE(ctx);
257 return ret;
259 talloc_set_destructor(ctx, messaging_dgm_context_destructor);
261 ctx->have_dgm_context = &have_dgm_context;
263 *pctx = ctx;
264 return 0;
266 fail_nomem:
267 TALLOC_FREE(ctx);
268 return ENOMEM;
271 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c)
274 * First delete the socket to avoid races. The lockfile is the
275 * indicator that we're still around.
277 unix_msg_free(c->dgm_ctx);
279 if (getpid() == c->pid) {
280 (void)messaging_dgm_lockfile_remove(c, c->cache_dir, c->pid);
282 close(c->lockfile_fd);
284 if (c->have_dgm_context != NULL) {
285 *c->have_dgm_context = false;
288 return 0;
291 int messaging_dgm_send(struct messaging_dgm_context *ctx, pid_t pid,
292 const struct iovec *iov, int iovlen)
294 struct sockaddr_un dst;
295 ssize_t dst_pathlen;
296 int ret;
298 dst = (struct sockaddr_un) { .sun_family = AF_UNIX };
300 dst_pathlen = snprintf(dst.sun_path, sizeof(dst.sun_path),
301 "%s/msg/%u", ctx->cache_dir, (unsigned)pid);
302 if (dst_pathlen >= sizeof(dst.sun_path)) {
303 return ENAMETOOLONG;
306 DEBUG(10, ("%s: Sending message to %u\n", __func__, (unsigned)pid));
308 ret = unix_msg_send(ctx->dgm_ctx, &dst, iov, iovlen);
310 return ret;
313 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
314 uint8_t *msg, size_t msg_len,
315 void *private_data)
317 struct messaging_dgm_context *dgm_ctx = talloc_get_type_abort(
318 private_data, struct messaging_dgm_context);
320 dgm_ctx->recv_cb(msg, msg_len, dgm_ctx->recv_cb_private_data);
323 int messaging_dgm_cleanup(struct messaging_dgm_context *ctx, pid_t pid)
325 char *lockfile_name, *socket_name;
326 int fd, ret;
327 struct flock lck = {};
329 lockfile_name = messaging_dgm_lockfile_name(
330 talloc_tos(), ctx->cache_dir, pid);
331 if (lockfile_name == NULL) {
332 return ENOMEM;
334 socket_name = talloc_asprintf(lockfile_name, "%s/msg/%u",
335 ctx->cache_dir, (unsigned)pid);
336 if (socket_name == NULL) {
337 TALLOC_FREE(lockfile_name);
338 return ENOMEM;
341 fd = open(lockfile_name, O_NONBLOCK|O_WRONLY, 0);
342 if (fd == -1) {
343 ret = errno;
344 if (ret != ENOENT) {
345 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__,
346 lockfile_name, strerror(ret)));
348 TALLOC_FREE(lockfile_name);
349 return ret;
352 lck.l_type = F_WRLCK;
353 lck.l_whence = SEEK_SET;
354 lck.l_start = 0;
355 lck.l_len = 0;
357 ret = fcntl(fd, F_SETLK, &lck);
358 if (ret != 0) {
359 ret = errno;
360 DEBUG(10, ("%s: Could not get lock: %s\n", __func__,
361 strerror(ret)));
362 TALLOC_FREE(lockfile_name);
363 close(fd);
364 return ret;
367 (void)unlink(socket_name);
368 (void)unlink(lockfile_name);
369 (void)close(fd);
371 TALLOC_FREE(lockfile_name);
372 return 0;
375 int messaging_dgm_wipe(struct messaging_dgm_context *ctx)
377 char *msgdir_name;
378 DIR *msgdir;
379 struct dirent *dp;
380 pid_t our_pid = getpid();
381 int ret;
384 * We scan the socket directory and not the lock directory. Otherwise
385 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
386 * and fcntl(SETLK).
389 msgdir_name = talloc_asprintf(talloc_tos(), "%s/msg", ctx->cache_dir);
390 if (msgdir_name == NULL) {
391 return ENOMEM;
394 msgdir = opendir(msgdir_name);
395 if (msgdir == NULL) {
396 ret = errno;
397 TALLOC_FREE(msgdir_name);
398 return ret;
400 TALLOC_FREE(msgdir_name);
402 while ((dp = readdir(msgdir)) != NULL) {
403 unsigned long pid;
405 pid = strtoul(dp->d_name, NULL, 10);
406 if (pid == 0) {
408 * . and .. and other malformed entries
410 continue;
412 if (pid == our_pid) {
414 * fcntl(F_GETLK) will succeed for ourselves, we hold
415 * that lock ourselves.
417 continue;
420 ret = messaging_dgm_cleanup(ctx, pid);
421 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
422 pid, ret ? strerror(ret) : "ok"));
424 closedir(msgdir);
426 return 0;
429 void *messaging_dgm_register_tevent_context(TALLOC_CTX *mem_ctx,
430 struct messaging_dgm_context *ctx,
431 struct tevent_context *ev)
433 return poll_funcs_tevent_register(mem_ctx, ctx->msg_callbacks, ev);