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/>.
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"
32 * This will carry enough for a socket path
34 char buf
[sizeof(struct sockaddr_un
)];
37 struct messaging_dgm_context
{
39 struct poll_funcs
*msg_callbacks
;
41 struct unix_msg_ctx
*dgm_ctx
;
42 struct sun_path_buf socket_dir
;
43 struct sun_path_buf lockfile_dir
;
46 void (*recv_cb
)(const uint8_t *msg
,
51 void *recv_cb_private_data
;
53 bool *have_dgm_context
;
56 static struct messaging_dgm_context
*global_dgm_context
;
58 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
59 uint8_t *msg
, size_t msg_len
,
60 int *fds
, size_t num_fds
,
63 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
);
65 static int messaging_dgm_lockfile_create(struct messaging_dgm_context
*ctx
,
66 pid_t pid
, int *plockfile_fd
,
71 struct sun_path_buf lockfile_name
;
76 ret
= snprintf(lockfile_name
.buf
, sizeof(lockfile_name
.buf
),
77 "%s/%u", ctx
->lockfile_dir
.buf
, (int)pid
);
78 if (ret
>= sizeof(lockfile_name
.buf
)) {
82 /* no O_EXCL, existence check is via the fcntl lock */
84 lockfile_fd
= open(lockfile_name
.buf
, O_NONBLOCK
|O_CREAT
|O_WRONLY
,
86 if (lockfile_fd
== -1) {
88 DEBUG(1, ("%s: open failed: %s\n", __func__
, strerror(errno
)));
92 lck
= (struct flock
) {
97 ret
= fcntl(lockfile_fd
, F_SETLK
, &lck
);
100 DEBUG(1, ("%s: fcntl failed: %s\n", __func__
, strerror(ret
)));
104 unique_len
= snprintf(buf
, sizeof(buf
), "%ju\n", (uintmax_t)unique
);
106 /* shorten a potentially preexisting file */
108 ret
= ftruncate(lockfile_fd
, unique_len
);
111 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__
,
116 written
= write(lockfile_fd
, buf
, unique_len
);
117 if (written
!= unique_len
) {
119 DEBUG(1, ("%s: write failed: %s\n", __func__
, strerror(ret
)));
123 *plockfile_fd
= lockfile_fd
;
127 unlink(lockfile_name
.buf
);
133 int messaging_dgm_init(struct tevent_context
*ev
,
135 const char *socket_dir
,
136 const char *lockfile_dir
,
137 void (*recv_cb
)(const uint8_t *msg
,
142 void *recv_cb_private_data
)
144 struct messaging_dgm_context
*ctx
;
146 struct sockaddr_un socket_address
;
148 static bool have_dgm_context
= false;
150 if (have_dgm_context
) {
154 ctx
= talloc_zero(NULL
, struct messaging_dgm_context
);
159 ctx
->recv_cb
= recv_cb
;
160 ctx
->recv_cb_private_data
= recv_cb_private_data
;
162 len
= strlcpy(ctx
->lockfile_dir
.buf
, lockfile_dir
,
163 sizeof(ctx
->lockfile_dir
.buf
));
164 if (len
>= sizeof(ctx
->lockfile_dir
.buf
)) {
169 len
= strlcpy(ctx
->socket_dir
.buf
, socket_dir
,
170 sizeof(ctx
->socket_dir
.buf
));
171 if (len
>= sizeof(ctx
->socket_dir
.buf
)) {
176 socket_address
= (struct sockaddr_un
) { .sun_family
= AF_UNIX
};
177 len
= snprintf(socket_address
.sun_path
,
178 sizeof(socket_address
.sun_path
),
179 "%s/%u", socket_dir
, (unsigned)ctx
->pid
);
180 if (len
>= sizeof(socket_address
.sun_path
)) {
185 ret
= messaging_dgm_lockfile_create(ctx
, ctx
->pid
, &ctx
->lockfile_fd
,
188 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
189 __func__
, strerror(ret
)));
194 ctx
->msg_callbacks
= poll_funcs_init_tevent(ctx
);
195 if (ctx
->msg_callbacks
== NULL
) {
199 ctx
->tevent_handle
= poll_funcs_tevent_register(
200 ctx
, ctx
->msg_callbacks
, ev
);
201 if (ctx
->tevent_handle
== NULL
) {
205 unlink(socket_address
.sun_path
);
207 ret
= unix_msg_init(&socket_address
, ctx
->msg_callbacks
, 1024,
208 messaging_dgm_recv
, ctx
, &ctx
->dgm_ctx
);
210 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret
)));
214 talloc_set_destructor(ctx
, messaging_dgm_context_destructor
);
216 ctx
->have_dgm_context
= &have_dgm_context
;
218 global_dgm_context
= ctx
;
226 static int messaging_dgm_context_destructor(struct messaging_dgm_context
*c
)
229 * First delete the socket to avoid races. The lockfile is the
230 * indicator that we're still around.
232 unix_msg_free(c
->dgm_ctx
);
234 if (getpid() == c
->pid
) {
235 struct sun_path_buf name
;
238 ret
= snprintf(name
.buf
, sizeof(name
.buf
), "%s/%u",
239 c
->lockfile_dir
.buf
, (unsigned)c
->pid
);
240 if (ret
>= sizeof(name
.buf
)) {
242 * We've checked the length when creating, so this
243 * should never happen
249 close(c
->lockfile_fd
);
251 if (c
->have_dgm_context
!= NULL
) {
252 *c
->have_dgm_context
= false;
258 void messaging_dgm_destroy(void)
260 TALLOC_FREE(global_dgm_context
);
263 int messaging_dgm_send(pid_t pid
,
264 const struct iovec
*iov
, int iovlen
,
265 const int *fds
, size_t num_fds
)
267 struct messaging_dgm_context
*ctx
= global_dgm_context
;
268 struct sockaddr_un dst
;
276 dst
= (struct sockaddr_un
) { .sun_family
= AF_UNIX
};
278 dst_pathlen
= snprintf(dst
.sun_path
, sizeof(dst
.sun_path
),
279 "%s/%u", ctx
->socket_dir
.buf
, (unsigned)pid
);
280 if (dst_pathlen
>= sizeof(dst
.sun_path
)) {
284 DEBUG(10, ("%s: Sending message to %u\n", __func__
, (unsigned)pid
));
286 ret
= unix_msg_send(ctx
->dgm_ctx
, &dst
, iov
, iovlen
, fds
, num_fds
);
291 static void messaging_dgm_recv(struct unix_msg_ctx
*ctx
,
292 uint8_t *msg
, size_t msg_len
,
293 int *fds
, size_t num_fds
,
296 struct messaging_dgm_context
*dgm_ctx
= talloc_get_type_abort(
297 private_data
, struct messaging_dgm_context
);
299 dgm_ctx
->recv_cb(msg
, msg_len
, fds
, num_fds
,
300 dgm_ctx
->recv_cb_private_data
);
303 int messaging_dgm_cleanup(pid_t pid
)
305 struct messaging_dgm_context
*ctx
= global_dgm_context
;
306 struct sun_path_buf lockfile_name
, socket_name
;
308 struct flock lck
= {};
314 len
= snprintf(socket_name
.buf
, sizeof(socket_name
.buf
), "%s/%u",
315 ctx
->socket_dir
.buf
, (unsigned)pid
);
316 if (len
>= sizeof(socket_name
.buf
)) {
320 len
= snprintf(lockfile_name
.buf
, sizeof(lockfile_name
.buf
), "%s/%u",
321 ctx
->lockfile_dir
.buf
, (unsigned)pid
);
322 if (len
>= sizeof(lockfile_name
.buf
)) {
326 fd
= open(lockfile_name
.buf
, O_NONBLOCK
|O_WRONLY
, 0);
330 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__
,
331 lockfile_name
.buf
, strerror(ret
)));
336 lck
.l_type
= F_WRLCK
;
337 lck
.l_whence
= SEEK_SET
;
341 ret
= fcntl(fd
, F_SETLK
, &lck
);
344 if ((ret
!= EACCES
) && (ret
!= EAGAIN
)) {
345 DEBUG(10, ("%s: Could not get lock: %s\n", __func__
,
352 DEBUG(10, ("%s: Cleaning up : %s\n", __func__
, strerror(ret
)));
354 (void)unlink(socket_name
.buf
);
355 (void)unlink(lockfile_name
.buf
);
360 int messaging_dgm_wipe(void)
362 struct messaging_dgm_context
*ctx
= global_dgm_context
;
365 pid_t our_pid
= getpid();
373 * We scan the socket directory and not the lock directory. Otherwise
374 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
378 msgdir
= opendir(ctx
->socket_dir
.buf
);
379 if (msgdir
== NULL
) {
383 while ((dp
= readdir(msgdir
)) != NULL
) {
386 pid
= strtoul(dp
->d_name
, NULL
, 10);
389 * . and .. and other malformed entries
393 if (pid
== our_pid
) {
395 * fcntl(F_GETLK) will succeed for ourselves, we hold
396 * that lock ourselves.
401 ret
= messaging_dgm_cleanup(pid
);
402 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
403 pid
, ret
? strerror(ret
) : "ok"));
410 void *messaging_dgm_register_tevent_context(TALLOC_CTX
*mem_ctx
,
411 struct tevent_context
*ev
)
413 struct messaging_dgm_context
*ctx
= global_dgm_context
;
418 return poll_funcs_tevent_register(mem_ctx
, ctx
->msg_callbacks
, ev
);