more like samba offline test
authorAndrew Tridgell <tridge@samba.org>
Tue, 5 Feb 2008 04:04:34 +0000 (15:04 +1100)
committerAndrew Tridgell <tridge@samba.org>
Tue, 5 Feb 2008 04:04:34 +0000 (15:04 +1100)
blade_console.exp [changed mode: 0644->0755]
isoffline_smb.c [new file with mode: 0644]

old mode 100644 (file)
new mode 100755 (executable)
index fc7b075..fc6fe98
@@ -1,6 +1,6 @@
 #!/usr/bin/expect -f
 
-set node "[lrange $argv 1 1]"
+set node "[lrange $argv 0 1]"
 
 spawn telnet 9.155.61.31
 expect "username: "
diff --git a/isoffline_smb.c b/isoffline_smb.c
new file mode 100644 (file)
index 0000000..bb5a364
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+  demonstration of checking if a file is offline using DMAPI, with
+  shortcut tricks using st_atime and st_blocks
+
+  Build with
+      gcc -o isoffline isoffline.c -ldmapi
+
+  Andrew Tridgell (tridgell@au1.ibm.com) July 2007
+ */
+
+#include <stdio.h>
+#include <dmapi.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+/* optimisation tunables - used to avoid the DMAPI slow path */
+#define FILE_IS_ONLINE_RATIO      0.5
+#define FILE_IS_ONLINE_ATIME      60
+
+#define DMAPI_SESSION_NAME "samba"
+#define DMAPI_TRACE 10
+
+static dm_sessid_t samba_dmapi_session = DM_NO_SESSION;
+
+#define DEBUG(lvl, x) printf x
+#define DEBUGADD(lvl, x) printf x
+
+/* 
+   Initialise DMAPI session. The session is persistant kernel state,
+   so it might already exist, in which case we merely want to
+   reconnect to it. This function should be called as root.
+ */
+static int dmapi_init_session(void)
+{
+       char    buf[DM_SESSION_INFO_LEN];
+       size_t  buflen;
+       uint        nsessions = 5;
+       dm_sessid_t *sessions = NULL;
+       int i, err;
+       char *version;
+
+       if (dm_init_service(&version) < 0) {
+               DEBUG(0,("dm_init_service failed - disabling DMAPI\n"));
+               return -1;
+       }
+
+       ZERO_STRUCT(buf);
+
+       do {
+               dm_sessid_t *new_sessions;
+               nsessions *= 2;
+               new_sessions = TALLOC_REALLOC_ARRAY(NULL, sessions, 
+                                                   dm_sessid_t, nsessions);
+               if (new_sessions == NULL) {
+                       talloc_free(sessions);
+                       return -1;
+               }
+               sessions = new_sessions;
+               err = dm_getall_sessions(nsessions, sessions, &nsessions);
+       } while (err == -1 && errno == E2BIG);
+
+       if (err == -1) {
+               DEBUGADD(DMAPI_TRACE,
+                       ("failed to retrieve DMAPI sessions: %s\n",
+                       strerror(errno)));
+               talloc_free(sessions);
+               return -1;
+       }
+
+       for (i = 0; i < nsessions; ++i) {
+               err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
+               buf[sizeof(buf) - 1] = '\0';
+               if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
+                       samba_dmapi_session = sessions[i];
+                       DEBUGADD(DMAPI_TRACE,
+                               ("attached to existing DMAPI session "
+                                "named '%s'\n", buf));
+                       break;
+               }
+       }
+
+       talloc_free(sessions);
+
+       /* No session already defined. */
+       if (samba_dmapi_session == DM_NO_SESSION) {
+               err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
+                                       &samba_dmapi_session);
+               if (err < 0) {
+                       DEBUGADD(DMAPI_TRACE,
+                               ("failed to create new DMAPI session: %s\n",
+                               strerror(errno)));
+                       samba_dmapi_session = DM_NO_SESSION;
+                       return -1;
+               }
+
+               DEBUG(0,("created new DMAPI session named '%s' for %s\n", 
+                        DMAPI_SESSION_NAME, version));
+       }
+
+       if (samba_dmapi_session != DM_NO_SESSION) {
+               set_effective_capability(DMAPI_ACCESS_CAPABILITY);
+       }
+
+       /* 
+          Note that we never end the DMAPI session. It gets re-used
+          if possible
+        */
+
+       return 0;
+}
+
+
+/* 
+   return a pointer to our dmapi session if available
+   This assumes you have called dmapi_have_session() first
+ */
+const void *dmapi_get_current_session(void) 
+{
+       if (samba_dmapi_session == DM_NO_SESSION) {
+               return NULL;
+       }
+       return (void *)&samba_dmapi_session;
+}
+
+/*
+  this must be the first dmapi call you make in Samba. It will initialise dmapi
+  if available and tell you if you can get a dmapi session. This should be called in
+  the client specific child process
+ */
+BOOL dmapi_have_session(void)
+{
+       static BOOL initialised;
+       if (!initialised) {
+               initialised = true;
+               become_root();
+               dmapi_init_session();
+               unbecome_root();
+       }
+       return samba_dmapi_session != DM_NO_SESSION;
+}
+
+
+/*
+  see if a file is offline
+
+  return -1 on failure. Set *offline to true/false according to
+  offline status
+ */
+static int is_offline(char *fname, time_t now, bool *offline)
+{
+       struct stat st;
+       void *handle=NULL;
+       size_t handle_len=0;
+       size_t rlen;
+       int ret;
+       dm_attrname_t dmAttrName;
+       /* keep some state between calls, to save on session creation calls */
+       static struct dmapi_state {
+               dm_sessid_t sid;
+               void *handle;
+               size_t handle_len;
+       } state;
+
+       if (state.sid == 0) {
+               /* create a new session if needed */
+               if (dm_create_session(DM_NO_SESSION, "samba", &state.sid) != 0) {
+                       return -1;
+               }
+       }
+
+       /* try shortcut methods first */
+       if (stat(fname, &st) != 0) {
+               return -1;
+       }
+
+       /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
+          then assume its not offline (it may not be 100%, as it could be sparse) */
+       if (512 * (off_t)st.st_blocks > st.st_size * FILE_IS_ONLINE_RATIO) {
+               *offline = false;
+               return 0;
+       }
+
+       /* go the slow DMAPI route */
+       if (dm_path_to_handle(fname, &handle, &handle_len) != 0) {
+               return -1;
+       }
+
+       memset(&dmAttrName, 0, sizeof(dmAttrName));
+       strcpy((char *)&dmAttrName.an_chars[0], "IBMObj");
+
+       ret = dm_get_dmattr(state.sid, handle, handle_len, 
+                           DM_NO_TOKEN, &dmAttrName, 0, NULL, &rlen);
+
+       /* its offline if the IBMObj attribute exists */
+       *offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+
+       dm_handle_free(handle, handle_len);
+       return 0;       
+}
+
+
+int main(int argc, char *argv[])
+{
+       int i;
+       time_t now = time(NULL);
+       now = time(NULL);
+       if (argc < 2) {
+               printf("isoffline <fname...>\n");
+               exit(1);
+       }
+       for (i=1;i<argc;i++) {
+               bool offline;
+               if (is_offline(argv[i], now, &offline) == -1) {
+                       perror(argv[i]);
+                       exit(1);
+               }
+               printf("%s\t%s\n", offline?"offline":"online ", argv[i]);
+       }
+       return 0;
+}