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, see <http://www.gnu.org/licenses/>.
24 #define DBGC_CLASS DBGC_DMAPI
28 int dmapi_init_session(void) { return -1; }
29 uint32 dmapi_file_flags(const char * const path) { return 0; }
30 BOOL dmapi_have_session(void) { return False; }
34 #ifdef HAVE_XFS_DMAPI_H
35 #include <xfs/dmapi.h>
36 #elif defined(HAVE_SYS_DMI_H)
38 #elif defined(HAVE_SYS_JFSDMAPI_H)
39 #include <sys/jfsdmapi.h>
40 #elif defined(HAVE_SYS_DMAPI_H)
41 #include <sys/dmapi.h>
42 #elif defined(HAVE_DMAPI_H)
46 #define DMAPI_SESSION_NAME "samba"
47 #define DMAPI_TRACE 10
49 static dm_sessid_t dmapi_session = DM_NO_SESSION;
51 /* Initialise the DMAPI interface. Make sure that we only end up initialising
52 * once per process to avoid resource leaks across different DMAPI
55 static int init_dmapi_service(void)
62 if (mypid != lastpid) {
66 if (dm_init_service(&version) < 0) {
70 DEBUG(0, ("Initializing DMAPI: %s\n", version));
76 BOOL dmapi_have_session(void)
78 return dmapi_session != DM_NO_SESSION;
81 static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
83 dm_sessid_t *nsessions;
85 nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
86 if (nsessions == NULL) {
87 TALLOC_FREE(sessions);
94 /* Initialise DMAPI session. The session is persistant kernel state, so it
95 * might already exist, in which case we merely want to reconnect to it. This
96 * function should be called as root.
98 int dmapi_init_session(void)
100 char buf[DM_SESSION_INFO_LEN];
104 dm_sessid_t *sessions = NULL;
108 /* If we aren't root, something in the following will fail due to lack
109 * of privileges. Aborting seems a little extreme.
111 SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
113 dmapi_session = DM_NO_SESSION;
114 if (init_dmapi_service() < 0) {
120 if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
124 err = dm_getall_sessions(nsessions, sessions, &nsessions);
126 if (errno == E2BIG) {
131 DEBUGADD(DMAPI_TRACE,
132 ("failed to retrieve DMAPI sessions: %s\n",
134 TALLOC_FREE(sessions);
138 for (i = 0; i < nsessions; ++i) {
139 err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
140 buf[sizeof(buf) - 1] = '\0';
141 if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
142 dmapi_session = sessions[i];
143 DEBUGADD(DMAPI_TRACE,
144 ("attached to existing DMAPI session "
145 "named '%s'\n", buf));
150 TALLOC_FREE(sessions);
152 /* No session already defined. */
153 if (dmapi_session == DM_NO_SESSION) {
154 err = dm_create_session(DM_NO_SESSION,
155 CONST_DISCARD(char *,
159 DEBUGADD(DMAPI_TRACE,
160 ("failed to create new DMAPI session: %s\n",
162 dmapi_session = DM_NO_SESSION;
166 DEBUGADD(DMAPI_TRACE,
167 ("created new DMAPI session named '%s'\n",
168 DMAPI_SESSION_NAME));
171 /* Note that we never end the DMAPI session. This enables child
172 * processes to continue to use the session after we exit. It also lets
173 * you run a second Samba server on different ports without any
180 /* Reattach to an existing dmapi session. Called from service processes that
181 * might not be running as root.
183 static int reattach_dmapi_session(void)
185 char buf[DM_SESSION_INFO_LEN];
188 if (dmapi_session != DM_NO_SESSION ) {
191 /* NOTE: On Linux, this call opens /dev/dmapi, costing us a
192 * file descriptor. Ideally, we would close this when we fork.
194 if (init_dmapi_service() < 0) {
195 dmapi_session = DM_NO_SESSION;
200 if (dm_query_session(dmapi_session, sizeof(buf),
202 /* Session is stale. Disable DMAPI. */
203 dmapi_session = DM_NO_SESSION;
208 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
210 DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
217 uint32 dmapi_file_flags(const char * const path)
219 static int attached = 0;
222 dm_eventset_t events = {0};
226 size_t dm_handle_len;
230 /* If a DMAPI session has been initialised, then we need to make sure
231 * we are attached to it and have the correct privileges. This is
232 * necessary to be able to do DMAPI operations across a fork(2). If
233 * it fails, there is no liklihood of that failure being transient.
235 * Note that this use of the static attached flag relies on the fact
236 * that dmapi_file_flags() is never called prior to forking the
237 * per-client server process.
239 if (dmapi_have_session() && !attached) {
241 if (reattach_dmapi_session() < 0) {
246 /* AIX has DMAPI but no POSIX capablities support. In this case,
247 * we need to be root to do DMAPI manipulations.
249 #ifndef HAVE_POSIX_CAPABILITIES
253 err = dm_path_to_handle(CONST_DISCARD(char *, path),
254 &dm_handle, &dm_handle_len);
256 DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
257 path, strerror(errno)));
259 if (errno != EPERM) {
263 /* Linux capabilities are broken in that changing our
264 * user ID will clobber out effective capabilities irrespective
265 * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
266 * capabilities are not removed from our permitted set, so we
267 * can re-acquire them if necessary.
270 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
272 err = dm_path_to_handle(CONST_DISCARD(char *, path),
273 &dm_handle, &dm_handle_len);
276 ("retrying dm_path_to_handle(%s): %s\n",
277 path, strerror(errno)));
282 err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
283 DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
285 DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
286 path, strerror(errno)));
287 dm_handle_free(dm_handle, dm_handle_len);
291 /* We figure that the only reason a DMAPI application would be
292 * interested in trapping read events is that part of the file is
295 DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
297 if (DMEV_ISSET(DM_EVENT_READ, events)) {
298 flags = FILE_ATTRIBUTE_OFFLINE;
301 dm_handle_free(dm_handle, dm_handle_len);
303 if (flags & FILE_ATTRIBUTE_OFFLINE) {
304 DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
309 #ifndef HAVE_POSIX_CAPABILITIES
316 #endif /* USE_DMAPI */