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 3 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>
43 #elif defined(HAVE_DMAPI_H)
47 #define DMAPI_SESSION_NAME "samba"
48 #define DMAPI_TRACE 10
50 static dm_sessid_t dmapi_session
= DM_NO_SESSION
;
52 /* Initialise the DMAPI interface. Make sure that we only end up initialising
53 * once per process to avoid resource leaks across different DMAPI
56 static int init_dmapi_service(void)
63 if (mypid
!= lastpid
) {
67 if (dm_init_service(&version
) < 0) {
71 DEBUG(0, ("Initializing DMAPI: %s\n", version
));
77 BOOL
dmapi_have_session(void)
79 return dmapi_session
!= DM_NO_SESSION
;
82 static dm_sessid_t
*realloc_session_list(dm_sessid_t
* sessions
, int count
)
84 dm_sessid_t
*nsessions
;
86 nsessions
= TALLOC_REALLOC_ARRAY(NULL
, sessions
, dm_sessid_t
, count
);
87 if (nsessions
== NULL
) {
88 TALLOC_FREE(sessions
);
95 /* Initialise DMAPI session. The session is persistant kernel state, so it
96 * might already exist, in which case we merely want to reconnect to it. This
97 * function should be called as root.
99 int dmapi_init_session(void)
101 char buf
[DM_SESSION_INFO_LEN
];
105 dm_sessid_t
*sessions
= NULL
;
109 /* If we aren't root, something in the following will fail due to lack
110 * of privileges. Aborting seems a little extreme.
112 SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
114 dmapi_session
= DM_NO_SESSION
;
115 if (init_dmapi_service() < 0) {
121 if ((sessions
= realloc_session_list(sessions
, nsessions
)) == NULL
) {
125 err
= dm_getall_sessions(nsessions
, sessions
, &nsessions
);
127 if (errno
== E2BIG
) {
132 DEBUGADD(DMAPI_TRACE
,
133 ("failed to retrieve DMAPI sessions: %s\n",
135 TALLOC_FREE(sessions
);
139 for (i
= 0; i
< nsessions
; ++i
) {
140 err
= dm_query_session(sessions
[i
], sizeof(buf
), buf
, &buflen
);
141 buf
[sizeof(buf
) - 1] = '\0';
142 if (err
== 0 && strcmp(DMAPI_SESSION_NAME
, buf
) == 0) {
143 dmapi_session
= sessions
[i
];
144 DEBUGADD(DMAPI_TRACE
,
145 ("attached to existing DMAPI session "
146 "named '%s'\n", buf
));
151 TALLOC_FREE(sessions
);
153 /* No session already defined. */
154 if (dmapi_session
== DM_NO_SESSION
) {
155 err
= dm_create_session(DM_NO_SESSION
,
156 CONST_DISCARD(char *,
160 DEBUGADD(DMAPI_TRACE
,
161 ("failed to create new DMAPI session: %s\n",
163 dmapi_session
= DM_NO_SESSION
;
167 DEBUGADD(DMAPI_TRACE
,
168 ("created new DMAPI session named '%s'\n",
169 DMAPI_SESSION_NAME
));
172 /* Note that we never end the DMAPI session. This enables child
173 * processes to continue to use the session after we exit. It also lets
174 * you run a second Samba server on different ports without any
181 /* Reattach to an existing dmapi session. Called from service processes that
182 * might not be running as root.
184 static int reattach_dmapi_session(void)
186 char buf
[DM_SESSION_INFO_LEN
];
189 if (dmapi_session
!= DM_NO_SESSION
) {
192 /* NOTE: On Linux, this call opens /dev/dmapi, costing us a
193 * file descriptor. Ideally, we would close this when we fork.
195 if (init_dmapi_service() < 0) {
196 dmapi_session
= DM_NO_SESSION
;
201 if (dm_query_session(dmapi_session
, sizeof(buf
),
203 /* Session is stale. Disable DMAPI. */
204 dmapi_session
= DM_NO_SESSION
;
209 set_effective_capability(DMAPI_ACCESS_CAPABILITY
);
211 DEBUG(DMAPI_TRACE
, ("reattached DMAPI session\n"));
218 uint32
dmapi_file_flags(const char * const path
)
220 static int attached
= 0;
223 dm_eventset_t events
= {0};
227 size_t dm_handle_len
;
231 /* If a DMAPI session has been initialised, then we need to make sure
232 * we are attached to it and have the correct privileges. This is
233 * necessary to be able to do DMAPI operations across a fork(2). If
234 * it fails, there is no liklihood of that failure being transient.
236 * Note that this use of the static attached flag relies on the fact
237 * that dmapi_file_flags() is never called prior to forking the
238 * per-client server process.
240 if (dmapi_have_session() && !attached
) {
242 if (reattach_dmapi_session() < 0) {
247 /* AIX has DMAPI but no POSIX capablities support. In this case,
248 * we need to be root to do DMAPI manipulations.
250 #ifndef HAVE_POSIX_CAPABILITIES
254 err
= dm_path_to_handle(CONST_DISCARD(char *, path
),
255 &dm_handle
, &dm_handle_len
);
257 DEBUG(DMAPI_TRACE
, ("dm_path_to_handle(%s): %s\n",
258 path
, strerror(errno
)));
260 if (errno
!= EPERM
) {
264 /* Linux capabilities are broken in that changing our
265 * user ID will clobber out effective capabilities irrespective
266 * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
267 * capabilities are not removed from our permitted set, so we
268 * can re-acquire them if necessary.
271 set_effective_capability(DMAPI_ACCESS_CAPABILITY
);
273 err
= dm_path_to_handle(CONST_DISCARD(char *, path
),
274 &dm_handle
, &dm_handle_len
);
277 ("retrying dm_path_to_handle(%s): %s\n",
278 path
, strerror(errno
)));
283 err
= dm_get_eventlist(dmapi_session
, dm_handle
, dm_handle_len
,
284 DM_NO_TOKEN
, DM_EVENT_MAX
, &events
, &nevents
);
286 DEBUG(DMAPI_TRACE
, ("dm_get_eventlist(%s): %s\n",
287 path
, strerror(errno
)));
288 dm_handle_free(dm_handle
, dm_handle_len
);
292 /* We figure that the only reason a DMAPI application would be
293 * interested in trapping read events is that part of the file is
296 DEBUG(DMAPI_TRACE
, ("DMAPI event list for %s is %#llx\n",
298 if (DMEV_ISSET(DM_EVENT_READ
, events
)) {
299 flags
= FILE_ATTRIBUTE_OFFLINE
;
302 dm_handle_free(dm_handle
, dm_handle_len
);
304 if (flags
& FILE_ATTRIBUTE_OFFLINE
) {
305 DEBUG(DMAPI_TRACE
, ("%s is OFFLINE\n", path
));
310 #ifndef HAVE_POSIX_CAPABILITIES
317 #endif /* USE_DMAPI */