2
Unix SMB/CIFS implementation.
5
Copyright (C) James Peach 2006
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
#define DBGC_CLASS DBGC_DMAPI
29
int dmapi_init_session(void) { return -1; }
30
uint32 dmapi_file_flags(const char * const path) { return 0; }
31
BOOL dmapi_have_session(void) { return False; }
35
#ifdef HAVE_XFS_DMAPI_H
36
#include <xfs/dmapi.h>
37
#elif defined(HAVE_SYS_DMI_H)
39
#elif defined(HAVE_SYS_JFSDMAPI_H)
40
#include <sys/jfsdmapi.h>
41
#elif defined(HAVE_SYS_DMAPI_H)
42
#include <sys/dmapi.h>
45
#define DMAPI_SESSION_NAME "samba"
46
#define DMAPI_TRACE 10
48
static dm_sessid_t dmapi_session = DM_NO_SESSION;
50
/* Initialise the DMAPI interface. Make sure that we only end up initialising
51
* once per process to avoid resource leaks across different DMAPI
54
static int init_dmapi_service(void)
61
if (mypid != lastpid) {
65
if (dm_init_service(&version) < 0) {
69
DEBUG(0, ("Initializing DMAPI: %s\n", version));
75
BOOL dmapi_have_session(void)
77
return dmapi_session != DM_NO_SESSION;
80
static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
82
dm_sessid_t *nsessions;
84
nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
85
if (nsessions == NULL) {
86
TALLOC_FREE(sessions);
93
/* Initialise DMAPI session. The session is persistant kernel state, so it
94
* might already exist, in which case we merely want to reconnect to it. This
95
* function should be called as root.
97
int dmapi_init_session(void)
99
char buf[DM_SESSION_INFO_LEN];
103
dm_sessid_t *sessions = NULL;
107
/* If we aren't root, something in the following will fail due to lack
108
* of privileges. Aborting seems a little extreme.
110
SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
112
dmapi_session = DM_NO_SESSION;
113
if (init_dmapi_service() < 0) {
119
if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
123
err = dm_getall_sessions(nsessions, sessions, &nsessions);
125
if (errno == E2BIG) {
130
DEBUGADD(DMAPI_TRACE,
131
("failed to retrieve DMAPI sessions: %s\n",
133
TALLOC_FREE(sessions);
137
for (i = 0; i < nsessions; ++i) {
138
err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
139
buf[sizeof(buf) - 1] = '\0';
140
if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
141
dmapi_session = sessions[i];
142
DEBUGADD(DMAPI_TRACE,
143
("attached to existing DMAPI session "
144
"named '%s'\n", buf));
149
TALLOC_FREE(sessions);
151
/* No session already defined. */
152
if (dmapi_session == DM_NO_SESSION) {
153
err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
156
DEBUGADD(DMAPI_TRACE,
157
("failed to create new DMAPI session: %s\n",
159
dmapi_session = DM_NO_SESSION;
163
DEBUGADD(DMAPI_TRACE,
164
("created new DMAPI session named '%s'\n",
165
DMAPI_SESSION_NAME));
168
/* Note that we never end the DMAPI session. This enables child
169
* processes to continue to use the session after we exit. It also lets
170
* you run a second Samba server on different ports without any
177
/* Reattach to an existing dmapi session. Called from service processes that
178
* might not be running as root.
180
static int reattach_dmapi_session(void)
182
char buf[DM_SESSION_INFO_LEN];
185
if (dmapi_session != DM_NO_SESSION ) {
188
/* NOTE: On Linux, this call opens /dev/dmapi, costing us a
189
* file descriptor. Ideally, we would close this when we fork.
191
if (init_dmapi_service() < 0) {
192
dmapi_session = DM_NO_SESSION;
197
if (dm_query_session(dmapi_session, sizeof(buf),
199
/* Session is stale. Disable DMAPI. */
200
dmapi_session = DM_NO_SESSION;
205
set_effective_capability(DMAPI_ACCESS_CAPABILITY);
207
DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
214
uint32 dmapi_file_flags(const char * const path)
216
static int attached = 0;
219
dm_eventset_t events = {0};
223
size_t dm_handle_len;
227
/* If a DMAPI session has been initialised, then we need to make sure
228
* we are attached to it and have the correct privileges. This is
229
* necessary to be able to do DMAPI operations across a fork(2). If
230
* it fails, there is no liklihood of that failure being transient.
232
* Note that this use of the static attached flag relies on the fact
233
* that dmapi_file_flags() is never called prior to forking the
234
* per-client server process.
236
if (dmapi_have_session() && !attached) {
238
if (reattach_dmapi_session() < 0) {
243
err = dm_path_to_handle(CONST_DISCARD(char *, path),
244
&dm_handle, &dm_handle_len);
246
DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
247
path, strerror(errno)));
249
if (errno != EPERM) {
253
/* Linux capabilities are broken in that changing our
254
* user ID will clobber out effective capabilities irrespective
255
* of whether we have set PR_SET_KEEPCAPS. Fortunately, the
256
* capabilities are not removed from our permitted set, so we
257
* can re-acquire them if necessary.
260
set_effective_capability(DMAPI_ACCESS_CAPABILITY);
262
err = dm_path_to_handle(CONST_DISCARD(char *, path),
263
&dm_handle, &dm_handle_len);
266
("retrying dm_path_to_handle(%s): %s\n",
267
path, strerror(errno)));
272
err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
273
DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
275
DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
276
path, strerror(errno)));
277
dm_handle_free(dm_handle, dm_handle_len);
281
/* We figure that the only reason a DMAPI application would be
282
* interested in trapping read events is that part of the file is
285
DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
287
if (DMEV_ISSET(DM_EVENT_READ, events)) {
288
flags = FILE_ATTRIBUTE_OFFLINE;
291
dm_handle_free(dm_handle, dm_handle_len);
293
if (flags & FILE_ATTRIBUTE_OFFLINE) {
294
DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
300
#endif /* USE_DMAPI */