source: branches/samba-3.0/source/smbd/dmapi.c@ 223

Last change on this file since 223 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 7.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 DMAPI Support routines
4
5 Copyright (C) James Peach 2006
6
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.
11
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.
16
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.
20*/
21
22#include "includes.h"
23
24#undef DBGC_CLASS
25#define DBGC_CLASS DBGC_DMAPI
26
27#ifndef USE_DMAPI
28
29int dmapi_init_session(void) { return -1; }
30uint32 dmapi_file_flags(const char * const path) { return 0; }
31BOOL dmapi_have_session(void) { return False; }
32
33#else /* USE_DMAPI */
34
35#ifdef HAVE_XFS_DMAPI_H
36#include <xfs/dmapi.h>
37#elif defined(HAVE_SYS_DMI_H)
38#include <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)
44#include <dmapi.h>
45#endif
46
47#define DMAPI_SESSION_NAME "samba"
48#define DMAPI_TRACE 10
49
50static dm_sessid_t dmapi_session = DM_NO_SESSION;
51
52/* Initialise the DMAPI interface. Make sure that we only end up initialising
53 * once per process to avoid resource leaks across different DMAPI
54 * implementations.
55 */
56static int init_dmapi_service(void)
57{
58 static pid_t lastpid;
59
60 pid_t mypid;
61
62 mypid = sys_getpid();
63 if (mypid != lastpid) {
64 char *version;
65
66 lastpid = mypid;
67 if (dm_init_service(&version) < 0) {
68 return -1;
69 }
70
71 DEBUG(0, ("Initializing DMAPI: %s\n", version));
72 }
73
74 return 0;
75}
76
77BOOL dmapi_have_session(void)
78{
79 return dmapi_session != DM_NO_SESSION;
80}
81
82static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
83{
84 dm_sessid_t *nsessions;
85
86 nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
87 if (nsessions == NULL) {
88 TALLOC_FREE(sessions);
89 return NULL;
90 }
91
92 return nsessions;
93}
94
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.
98 */
99int dmapi_init_session(void)
100{
101 char buf[DM_SESSION_INFO_LEN];
102 size_t buflen;
103
104 uint nsessions = 10;
105 dm_sessid_t *sessions = NULL;
106
107 int i, err;
108
109 /* If we aren't root, something in the following will fail due to lack
110 * of privileges. Aborting seems a little extreme.
111 */
112 SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
113
114 dmapi_session = DM_NO_SESSION;
115 if (init_dmapi_service() < 0) {
116 return -1;
117 }
118
119retry:
120
121 if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
122 return -1;
123 }
124
125 err = dm_getall_sessions(nsessions, sessions, &nsessions);
126 if (err < 0) {
127 if (errno == E2BIG) {
128 nsessions *= 2;
129 goto retry;
130 }
131
132 DEBUGADD(DMAPI_TRACE,
133 ("failed to retrieve DMAPI sessions: %s\n",
134 strerror(errno)));
135 TALLOC_FREE(sessions);
136 return -1;
137 }
138
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));
147 break;
148 }
149 }
150
151 TALLOC_FREE(sessions);
152
153 /* No session already defined. */
154 if (dmapi_session == DM_NO_SESSION) {
155 err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
156 &dmapi_session);
157 if (err < 0) {
158 DEBUGADD(DMAPI_TRACE,
159 ("failed to create new DMAPI session: %s\n",
160 strerror(errno)));
161 dmapi_session = DM_NO_SESSION;
162 return -1;
163 }
164
165 DEBUGADD(DMAPI_TRACE,
166 ("created new DMAPI session named '%s'\n",
167 DMAPI_SESSION_NAME));
168 }
169
170 /* Note that we never end the DMAPI session. This enables child
171 * processes to continue to use the session after we exit. It also lets
172 * you run a second Samba server on different ports without any
173 * conflict.
174 */
175
176 return 0;
177}
178
179/* Reattach to an existing dmapi session. Called from service processes that
180 * might not be running as root.
181 */
182static int reattach_dmapi_session(void)
183{
184 char buf[DM_SESSION_INFO_LEN];
185 size_t buflen;
186
187 if (dmapi_session != DM_NO_SESSION ) {
188 become_root();
189
190 /* NOTE: On Linux, this call opens /dev/dmapi, costing us a
191 * file descriptor. Ideally, we would close this when we fork.
192 */
193 if (init_dmapi_service() < 0) {
194 dmapi_session = DM_NO_SESSION;
195 unbecome_root();
196 return -1;
197 }
198
199 if (dm_query_session(dmapi_session, sizeof(buf),
200 buf, &buflen) < 0) {
201 /* Session is stale. Disable DMAPI. */
202 dmapi_session = DM_NO_SESSION;
203 unbecome_root();
204 return -1;
205 }
206
207 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
208
209 DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
210 unbecome_root();
211 }
212
213 return 0;
214}
215
216uint32 dmapi_file_flags(const char * const path)
217{
218 static int attached = 0;
219
220 int err;
221 dm_eventset_t events = {0};
222 uint nevents;
223
224 void *dm_handle;
225 size_t dm_handle_len;
226
227 uint32 flags = 0;
228
229 /* If a DMAPI session has been initialised, then we need to make sure
230 * we are attached to it and have the correct privileges. This is
231 * necessary to be able to do DMAPI operations across a fork(2). If
232 * it fails, there is no liklihood of that failure being transient.
233 *
234 * Note that this use of the static attached flag relies on the fact
235 * that dmapi_file_flags() is never called prior to forking the
236 * per-client server process.
237 */
238 if (dmapi_have_session() && !attached) {
239 attached++;
240 if (reattach_dmapi_session() < 0) {
241 return 0;
242 }
243 }
244
245 /* AIX has DMAPI but no POSIX capablities support. In this case,
246 * we need to be root to do DMAPI manipulations.
247 */
248#ifndef HAVE_POSIX_CAPABILITIES
249 become_root();
250#endif
251
252 err = dm_path_to_handle(CONST_DISCARD(char *, path),
253 &dm_handle, &dm_handle_len);
254 if (err < 0) {
255 DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
256 path, strerror(errno)));
257
258 if (errno != EPERM) {
259 goto done;
260 }
261
262 /* Linux capabilities are broken in that changing our
263 * user ID will clobber out effective capabilities irrespective
264 * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
265 * capabilities are not removed from our permitted set, so we
266 * can re-acquire them if necessary.
267 */
268
269 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
270
271 err = dm_path_to_handle(CONST_DISCARD(char *, path),
272 &dm_handle, &dm_handle_len);
273 if (err < 0) {
274 DEBUG(DMAPI_TRACE,
275 ("retrying dm_path_to_handle(%s): %s\n",
276 path, strerror(errno)));
277 goto done;
278 }
279 }
280
281 err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
282 DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
283 if (err < 0) {
284 DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
285 path, strerror(errno)));
286 dm_handle_free(dm_handle, dm_handle_len);
287 goto done;
288 }
289
290 /* We figure that the only reason a DMAPI application would be
291 * interested in trapping read events is that part of the file is
292 * offline.
293 */
294 DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
295 path, events));
296 if (DMEV_ISSET(DM_EVENT_READ, events)) {
297 flags = FILE_ATTRIBUTE_OFFLINE;
298 }
299
300 dm_handle_free(dm_handle, dm_handle_len);
301
302 if (flags & FILE_ATTRIBUTE_OFFLINE) {
303 DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
304 }
305
306done:
307
308#ifndef HAVE_POSIX_CAPABILITIES
309 unbecome_root();
310#endif
311
312 return flags;
313}
314
315#endif /* USE_DMAPI */
Note: See TracBrowser for help on using the repository browser.