--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+
+The tests in this directory are a collection of suites that were developed
+over the time the DMAPI spec was being created and when DMAPI was being
+implemented on Irix. In many cases, each suite was built on an earlier suite.
+Many of these tests have been ported to work with XFS/DMAPI on linux 2.4; many
+are untouched from their Irix versions.
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <ctype.h>
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#include <malloc.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_read_invis(). The
+command line is:
+
+ read_invis [-o offset] [-l length] [-s sid] pathname
+
+where:
+'offset' is the offset of the start of the write (0 is the default),
+'length' is the length of the write in bytes (1 is the default),
+'sid' is the session ID whose events you you are interested in.
+'pathname' is the name of the file to be written.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+
+static void
+usage(void)
+{
+ int i;
+
+ fprintf(stderr, "usage:\t%s [-o offset] [-l length] "
+ "[-s sid] pathname\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ char *pathname = NULL;
+ dm_off_t offset = 0;
+ dm_size_t length = 1;
+ char *bufp = NULL;
+ void *hanp;
+ size_t hlen;
+ dm_ssize_t rc;
+ char *name;
+ int opt;
+ int i;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "o:l:s:")) != EOF) {
+ switch (opt) {
+ case 'o':
+ offset = atol(optarg);
+ break;
+ case 'l':
+ length = atol(optarg);
+ break;
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 1 != argc)
+ usage();
+ pathname = argv[optind];
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file's handle. */
+
+ if (dm_path_to_handle(pathname, &hanp, &hlen)) {
+ fprintf(stderr, "can't get handle for file %s\n", pathname);
+ exit(1);
+ }
+
+ if (length > 0) {
+ /* In case it is a realtime file, align the buffer on a
+ sufficiently big boundary.
+ */
+ if ((bufp = memalign(4096, length)) == NULL) {
+ fprintf(stderr, "malloc of %d bytes failed\n", length);
+ exit(1);
+ }
+ memset(bufp, '\0', length);
+ }
+
+ rc = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, offset, length, bufp);
+
+ if (rc < 0) {
+ fprintf(stderr, "dm_read_invis failed, %s\n", strerror(errno));
+ exit(1);
+ } else if (rc != length) {
+ fprintf(stderr, "expected to read %lld bytes, actually "
+ "read %lld\n", length, rc);
+ exit(1);
+ }
+ for (i = 0; i < rc; i++) {
+ if (isprint(bufp[i])) {
+ fprintf(stdout, "%c", bufp[i]);
+ } else {
+ fprintf(stdout, "\\%03d", bufp[i]);
+ }
+ }
+ dm_handle_free(hanp, hlen);
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_set_region(). The
+command line is:
+
+ set_region [-n nelem] [-o offset] [-l length] [-s sid] pathname [event...]
+
+where pathname is the name of a file, nelem is the number of regions to pass
+in the call, offset is the offset of the start of
+the managed region, and length is the length. sid is the session ID whose
+events you you are interested in, and event is zero or more managed region
+events to set.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+static struct {
+ char *name;
+ int value;
+} rg_events[3] = {
+ { "DM_REGION_READ", DM_REGION_READ },
+ { "DM_REGION_WRITE", DM_REGION_WRITE },
+ { "DM_REGION_TRUNCATE", DM_REGION_TRUNCATE }
+};
+static int nevents = sizeof(rg_events)/sizeof(rg_events[0]);
+
+
+static void
+usage(void)
+{
+ int i;
+
+ fprintf(stderr, "usage:\t%s [-n nelem] [-o offset] [-l length] "
+ "[-s sid] pathname [event...]\n", Progname);
+ fprintf(stderr, "possible events are:\n");
+ for (i = 0; i < nevents; i++)
+ fprintf(stderr, "%s (0x%x)\n", rg_events[i].name, rg_events[i].value);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_region_t region = { 0, 0, 0 };
+ dm_sessid_t sid = DM_NO_SESSION;
+ char *pathname = NULL;
+ u_int exactflag;
+ u_int nelem = 1;
+ void *hanp;
+ size_t hlen;
+ char *name;
+ int opt;
+ int i;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "n:o:l:s:")) != EOF) {
+ switch (opt) {
+ case 'n':
+ nelem = atol(optarg);
+ break;
+ case 'o':
+ region.rg_offset = atol(optarg);
+ break;
+ case 'l':
+ region.rg_size = atol(optarg);
+ break;
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 1 > argc)
+ usage();
+ pathname = argv[optind++];
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file's handle. */
+
+ if (dm_path_to_handle(pathname, &hanp, &hlen)) {
+ fprintf(stderr, "can't get handle for file %s\n", pathname);
+ exit(1);
+ }
+
+ for (; optind < argc; optind++) {
+ if (strspn(argv[optind], "0123456789") == strlen(argv[optind])){
+ region.rg_flags |= atol(argv[optind]);
+ continue;
+ }
+ for (i = 0; i < nevents; i++) {
+ if (!strcmp(argv[optind], rg_events[i].name))
+ break;
+ }
+ if (i == nevents) {
+ fprintf(stderr, "invalid event %s\n", argv[optind]);
+ exit(1);
+ }
+ region.rg_flags |= rg_events[i].value;
+ }
+
+ if (dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, nelem, ®ion,
+ &exactflag)) {
+ fprintf(stderr, "dm_set_region failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ fprintf(stdout, "exactflag is %s\n",
+ exactflag == DM_TRUE ? "True" : "False");
+ dm_handle_free(hanp, hlen);
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_set_return_on_destroy(). The
+command line is:
+
+ set_return_on_destroy [-s sid] pathname [attr]
+
+where pathname is the name of a file which resides in the filesystem of
+interest. attr is the name of the DMAPI attribute; if none is specified,
+then set-return-on-destroy will be disabled for the filesystem.
+sid is the session ID whose attribute you are interested in setting.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+static void
+usage(void)
+{
+ int i;
+
+ fprintf(stderr, "usage:\t%s [-s sid] pathname [attr]\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ char *pathname;
+ dm_attrname_t *attrnamep = NULL;
+ dm_boolean_t enable = DM_FALSE;
+ void *hanp;
+ size_t hlen;
+ char *name;
+ int opt;
+ int i;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "s:")) != EOF) {
+ switch (opt) {
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind == argc || optind + 2 < argc)
+ usage();
+ pathname = argv[optind++];
+ if (optind < argc) {
+ enable = DM_TRUE;
+ attrnamep = (dm_attrname_t *)argv[optind++];
+ }
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file's handle. */
+
+ if (dm_path_to_fshandle(pathname, &hanp, &hlen)) {
+ fprintf(stderr, "can't get filesystem handle for file %s, %s\n",
+ pathname, strerror(errno));
+ exit(1);
+ }
+
+ if (dm_set_return_on_destroy(sid, hanp, hlen, DM_NO_TOKEN,
+ attrnamep, enable)) {
+ fprintf(stderr, "dm_set_return_on_destroy failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ dm_handle_free(hanp, hlen);
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#include <malloc.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_write_invis(). The
+command line is:
+
+ write_invis [-c char] [-o offset] [-l length] [-s sid] pathname
+
+where:
+'char' is the character to use as a repeated pattern ('X' is the default),
+'offset' is the offset of the start of the write (0 is the default),
+'length' is the length of the write in bytes (1 is the default),
+'sid' is the session ID whose events you you are interested in.
+'pathname' is the name of the file to be written.
+
+DM_WRITE_SYNC is is not supported.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+
+static void
+usage(void)
+{
+ int i;
+
+ fprintf(stderr, "usage:\t%s [-c char] [-o offset] [-l length] "
+ "[-s sid] pathname\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ char *pathname = NULL;
+ dm_off_t offset = 0;
+ dm_size_t length = 1;
+ u_char ch = 'X';
+ void *bufp = NULL;
+ void *hanp;
+ size_t hlen;
+ dm_ssize_t rc;
+ char *name;
+ int opt;
+ int i;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "c:o:l:s:")) != EOF) {
+ switch (opt) {
+ case 'c':
+ ch = *optarg;
+ break;
+ case 'o':
+ offset = atol(optarg);
+ break;
+ case 'l':
+ length = atol(optarg);
+ break;
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 1 != argc)
+ usage();
+ pathname = argv[optind];
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file's handle. */
+
+ if (dm_path_to_handle(pathname, &hanp, &hlen)) {
+ fprintf(stderr, "can't get handle for file %s\n", pathname);
+ exit(1);
+ }
+
+ if (length > 0) {
+ /* In case it is a realtime file, align the buffer on a
+ sufficiently big boundary.
+ */
+ if ((bufp = memalign(4096, length)) == NULL) {
+ fprintf(stderr, "malloc of %d bytes failed\n", length);
+ exit(1);
+ }
+ memset(bufp, ch, length);
+ }
+
+ rc = dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN, 0, offset, length, bufp);
+
+ if (rc < 0) {
+ fprintf(stderr, "dm_write_invis failed, %s\n", strerror(errno));
+ exit(1);
+ } else if (rc != length) {
+ fprintf(stderr, "expected to write %lld bytes, actually "
+ "wrote %lld\n", length, rc);
+ exit(1);
+ }
+ dm_handle_free(hanp, hlen);
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#ifndef _DMFSAPI_DMPORT_H
+#define _DMFSAPI_DMPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**************************************************************************
+ * *
+ * DMF's use of DMAPI is based upon the X/Open document *
+ * Systems Management: Data Storage Managment (XDSM) API *
+ * dated February 1997. However, no implementation of DMAPI perfectly *
+ * matches the spec. Each implementation has some functions that it *
+ * didn't implement, non-standard functions that it added, differences *
+ * in function parameter types, return value types, number and order of *
+ * parameters, etc. There are also differences in the formats of some *
+ * of the DMAPI structures used by those functions. Finally, there are *
+ * many scalar values for which DMAPI assigned no particular size. For *
+ * example, a dm_fsid_t is 32 bits under Veritas and 64 bits under SGI. *
+ * *
+ * To hide the differences as much as possible, this include file tries *
+ * to shoehorn each DMAPI implementation into the XDSM mold as much as *
+ * possible. Functions which are not compatible with the XDSM spec are *
+ * redefined using wrapper routines to make them conform to the spec. *
+ * Functions which were not implemented have stubs defined which return *
+ * ENOSYS (see file stubs.c for all wrappers and stubs). In dmport.h, *
+ * missing structures and scalers are defined, incompatible typedefs are *
+ * redefined, etc. *
+ * *
+ * The goal is to reduce as much as possible the number of #ifdefs that *
+ * have to be added to DMF to handle specific DMAPI implementations. *
+ * Some #ifdefs may still be required because of semantic differences *
+ * between the XDSM spec definition and the actual implementation. *
+ * *
+ * Following all the implementation-specific definitions, dmport.h *
+ * includes a complete set of prototypes for all functions that are part *
+ * of the XDSM specification. This is done as a double-check. Should *
+ * any of the actual implementations change, the compiler should tip us *
+ * off by complaining about imcompatible function redefinitions. *
+ * *
+ **************************************************************************/
+
+
+/* ---------------- Veritas-specific hack documentation -----------------
+
+The following functions have no prototypes in the Veritas include file
+<sys/dmapi/dmapi.h>. They do not link either.
+
+extern int dm_handle_is_valid(void *, size_t);
+
+
+The following functions have prototypes in <sys/dmapi/dmapi.h>, but
+they do not link.
+
+extern int dm_getall_disp(dm_sessid_t, size_t, void *, size_t *);
+extern int dm_getall_dmattr(dm_sessid_t, void *, size_t,
+ dm_token_t, size_t, void *, size_t *);
+
+
+The following functions have no prototypes in <sys/dmapi/dmapi.h> but do link.
+
+extern int dm_obj_ref_hold(dm_sessid_t, dm_token_t, void *, size_t);
+extern int dm_obj_ref_rele(dm_sessid_t, dm_token_t, void *, size_t);
+extern int dm_obj_ref_query(dm_sessid_t, dm_token_t, void *, size_t);
+
+
+The following Veritas prototypes are different in some way from the
+spec prototypes, either in parameter types, return value types, or in
+some semantic way. Look below to see the spec versions of the prototypes.
+
+extern int dm_downgrade_right(dm_sessid_t, void *, size_t,
+ dm_token_t, int, dm_right_t);
+extern int dm_get_config_events(void *, size_t, u_int,
+ dm_eventset_t *, u_int *);
+extern int dm_get_events(dm_sessid_t, u_int, int, size_t, void *, size_t *);
+extern int dm_get_mountinfo(dm_sessid_t, dm_token_t, void *, size_t,
+ size_t, void *, size_t *);
+extern int dm_init_service(void);
+extern int dm_make_handle(dev_t , long, long, void **, size_t *);
+extern int dm_make_fshandle(dev_t , void **, size_t *);
+extern dev_t dm_handle_to_dev(void *, size_t);
+extern long dm_handle_to_fgen(void *, size_t);
+extern long dm_handle_to_ino(void *, size_t);
+extern int dm_pending(dm_sessid_t, void *, size_t, dm_token_t, int);
+extern dm_ssize_t dm_read_invis(dm_sessid_t, void *, size_t,
+ dm_token_t, dm_off_t, dm_ssize_t, void *);
+extern dm_ssize_t dm_write_invis(dm_sessid_t, void *, size_t,
+ dm_token_t, dm_off_t, dm_ssize_t, void *, int);
+extern int dm_request_right(dm_sessid_t, void *, size_t,
+ dm_token_t, int, dm_right_t);
+extern int dm_set_inherit(dm_sessid_t, void *, size_t,
+ dm_token_t, dm_attrname_t *, u_int);
+extern int dm_set_return_ondestroy(dm_sessid_t, void *, size_t,
+ dm_token_t, dm_attrname_t *, int);
+extern int dm_upgrade_right(dm_sessid_t, void *, size_t,
+ dm_token_t, int, dm_right_t);
+extern int dm_set_region(dm_sessid_t, void *, size_t,
+ dm_token_t, u_int, dm_region_t *, u_int *);
+extern dm_ssize_t dm_sync_by_handle(dm_sessid_t, void *, size_t, dm_token_t);
+
+
+The following Veritas prototype exists in <sys/dmapi/dmapi.h> but
+does not appear in the spec.
+
+extern void dm_attach_event(dm_sessid_t, dm_token_t);
+
+The following functions exist in the Veritas library libdmi.a, but have no
+prototypes within <sys/dmapi/dmapi.h>. Their function is unknown.
+
+dm_attach_event_nofork
+dm_event_query
+dm_event_valid
+dm_get_disp
+dm_set_resident
+dmregion_compare
+kdm_get_eventinfo
+kdm_get_sessioninfo
+
+-------------- end of Veritas-specific hack documentation --------------- */
+
+#ifdef VERITAS_21
+
+#include <sys/types.h>
+
+#include <sys/dmapi/dmapi.h>
+
+/* Rename functions whose prototypes clash with the XDSM standard. (Library
+ routines map from XDSM functions back to Veritas functions.)
+*/
+
+#define dm_downgrade_right xvfs_dm_downgrade_right
+#define dm_fd_to_handle xvfs_dm_fd_to_handle
+#define dm_get_events xvfs_dm_get_events
+#define dm_get_mountinfo xvfs_dm_get_mountinfo
+#define dm_handle_to_ino xvfs_dm_handle_to_ino
+#define dm_init_service xvfs_dm_init_service
+#define dm_make_fshandle xvfs_dm_make_fshandle
+#define dm_make_handle xvfs_dm_make_handle
+#define dm_path_to_fshandle xvfs_dm_path_to_fshandle
+#define dm_path_to_handle xvfs_dm_path_to_handle
+#define dm_pending xvfs_dm_pending
+#define dm_read_invis xvfs_dm_read_invis
+#define dm_write_invis xvfs_dm_write_invis
+#define dm_request_right xvfs_dm_request_right
+#define dm_set_inherit xvfs_dm_set_inherit
+#define dm_set_region xvfs_dm_set_region
+#define dm_sync_by_handle xvfs_dm_sync_by_handle
+#define dm_upgrade_right xvfs_dm_upgrade_right
+
+
+#define DM_ATTR_NAME_SIZE 8
+#undef DM_ATTRNAME_SIZE
+#define DM_VER_STR_CONTENTS "Veritas DMAPI V1.0"
+
+#define DM_EV_WAIT 0x1
+#define DM_RR_WAIT 0x1
+#undef DM_WAIT
+#undef DM_NOWAIT
+#undef DM_EVENT_NOWAIT
+
+#define DM_CONFIG_INHERIT_ATTRIBS (DM_CONFIG_LOCK_UPGRADE + 1)
+#undef DM_CONFIG_INHERIT
+#define DM_CONFIG_MAX_HANDLE_SIZE (DM_CONFIG_INHERIT_ATTRIBS + 1)
+#undef DM_CONFIG_MAX_FILE_HANDLE_SIZE
+#define DM_CONFIG_MAX_ATTR_ON_DESTROY (DM_CONFIG_MAX_HANDLE_SIZE + 1)
+#undef DM_CONFIG_MAX_ATTR_BYTES_ON_DESTROY
+#define DM_CONFIG_OBJ_REF (DM_CONFIG_MAX_ATTR_ON_DESTROY + 1)
+#define DM_CONFIG_DTIME_OVERLOAD (DM_CONFIG_OBJ_REF + 1)
+#undef DM_CONFIG_MAX
+
+#define DM_AT_DTIME DM_AT_DTIMES
+
+/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all
+ the time fields while XDSM uses 'time_t' structures. Define some symbols
+ that can be used for the time fields with all implementation types.
+*/
+
+#define FA_ATIME fa_atime.tv_sec
+#define FA_MTIME fa_atime.tv_sec
+#define FA_CTIME fa_ctime.tv_sec
+#define FA_DTIME fa_dtime.tv_sec
+
+#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */
+
+#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */
+
+/* Rename one event to match the XDSM standard. */
+
+#define DM_EVENT_CLOSE (DM_EVENT_DESTROY + 1)
+#undef DM_EVENT_CLOSED
+
+/* DM_EVENT_CANCEL is defined above DM_EVENT_MAX, and is unsupported. */
+
+#undef DM_REGION_VALIDFLAG
+
+/* Add missing typedefs */
+
+typedef u_int dm_boolean_t;
+typedef dev_t dm_fsid_t; /* This could be made a uint64_t with work! */
+typedef long dm_igen_t;
+typedef long dm_ino_t;
+typedef u_int dm_sequence_t;
+
+
+/* Define missing fields within the various event structures. */
+
+#define ev_sequence ev_token /* for compilation only! Won't work! */
+
+#define ds_handle te_handle /* fix fields in dm_destroy_event_t */
+#define ds_attrname te_attrname
+#define ds_attrcopy te_attrdata
+
+
+struct dm_cancel_event { /* define missing dm_cancel_event_t */
+ dm_sequence_t ce_sequence;
+ dm_token_t ce_token;
+};
+typedef struct dm_cancel_event dm_cancel_event_t;
+
+
+struct dm_mount_event { /* define missing dm_mount_event_t */
+ mode_t me_mode;
+ dm_vardata_t me_handle1;
+ dm_vardata_t me_handle2;
+ dm_vardata_t me_name1;
+ dm_vardata_t me_name2;
+ dm_vardata_t me_roothandle;
+};
+typedef struct dm_mount_event dm_mount_event_t;
+
+
+/* Add the missing dm_timestruct_t structure used by dm_pending. */
+
+struct dm_timestruct {
+ time_t dm_tv_sec;
+ int dm_tv_nsec;
+};
+typedef struct dm_timestruct dm_timestruct_t;
+
+#endif
+
+
+
+/* -------------------- SGI-specific hack documentation -------------------
+
+ There are various fields within DMAPI structures that are not supported.
+ Fill in this information someday.
+
+ The following functions have prototypes defined in <sys/dmi.h> and have
+ entry points defined in libdm.so, but they are not actually implemented
+ within the kernel. They all return ENOSYS if called.
+
+ dm_clear_inherit
+ dm_create_by_handle
+ dm_get_bulkall
+ dm_getall_inherit
+ dm_mkdir_by_handle
+ dm_set_inherit
+ dm_symlink_by_handle
+
+ The DMAPI functions which deal with rights do not work as described in
+ the specification. While the functions exist and are callable, they
+ always return successfully without actually obtaining any locks within
+ the filesystem.
+
+ dm_downgrade_right
+ dm_query_right
+ dm_release_right
+ dm_request_right
+ dm_upgrade_right
+
+ The following non-standard SGI prototype is added to the DMAPI interface
+ so that real-time files may be migrated and recalled.
+
+ dm_get_dioinfo
+
+-------------- end of SGI-specific hack documentation --------------- */
+
+#ifdef __sgi
+
+#include <sys/dmi.h>
+
+/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all
+ the time fields while XDSM uses 'time_t' structures. Define some symbols
+ that can be used for the time fields with all implementation types.
+*/
+
+#define FA_ATIME fa_atime
+#define FA_MTIME fa_mtime
+#define FA_CTIME fa_ctime
+#define FA_DTIME fa_dtime
+
+#endif /* __sgi */
+
+#ifdef linux
+
+#include <linux/dmapi.h>
+
+/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all
+ the time fields while XDSM uses 'time_t' structures. Define some symbols
+ that can be used for the time fields with all implementation types.
+*/
+
+#define FA_ATIME fa_atime
+#define FA_MTIME fa_mtime
+#define FA_CTIME fa_ctime
+#define FA_DTIME fa_dtime
+
+#endif /* linux */
+
+/* ----------------------- XDSM standard prototypes ----------------------- */
+
+/* The following list provides the prototypes for all functions defined in
+ the DMAPI interface spec from X/Open (XDSM) dated February 1997. They
+ are here to force compiler errors in case the Veritas or SGI DMAPI
+ prototypes should ever change without our knowing about it.
+*/
+
+extern int
+dm_clear_inherit(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep);
+
+extern int
+dm_create_by_handle(
+ dm_sessid_t sid,
+ void *dirhanp,
+ size_t dirhlen,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen,
+ char *cname);
+
+extern int
+dm_create_session(
+ dm_sessid_t oldsid,
+ char *sessinfop,
+ dm_sessid_t *newsidp);
+
+extern int
+dm_create_userevent(
+ dm_sessid_t sid,
+ size_t msglen,
+ void *msgdatap,
+ dm_token_t *tokenp);
+
+extern int
+dm_destroy_session(
+ dm_sessid_t sid);
+
+extern int
+dm_downgrade_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token);
+
+extern int
+dm_fd_to_handle(
+ int fd,
+ void **hanpp,
+ size_t *hlenp);
+
+extern int
+dm_find_eventmsg(
+ dm_sessid_t sid,
+ dm_token_t token,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_allocinfo(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t *offp,
+ u_int nelem,
+ dm_extent_t *extentp,
+ u_int *nelemp);
+
+extern int
+dm_get_bulkall(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int mask,
+ dm_attrname_t *attrnamep,
+ dm_attrloc_t *locp,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_bulkattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int mask,
+ dm_attrloc_t *locp,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_config(
+ void *hanp,
+ size_t hlen,
+ dm_config_t flagname,
+ dm_size_t *retvalp);
+
+extern int
+dm_get_config_events(
+ void *hanp,
+ size_t hlen,
+ u_int nelem,
+ dm_eventset_t *eventsetp,
+ u_int *nelemp);
+
+extern int
+dm_get_dirattrs(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int mask,
+ dm_attrloc_t *locp,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_dmattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_eventlist(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int nelem,
+ dm_eventset_t *eventsetp,
+ u_int *nelemp);
+
+extern int
+dm_get_events(
+ dm_sessid_t sid,
+ u_int maxmsgs,
+ u_int flags,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_fileattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int mask,
+ dm_stat_t *statp);
+
+extern int
+dm_get_mountinfo(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_get_region(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int nelem,
+ dm_region_t *regbufp,
+ u_int *nelemp);
+
+extern int
+dm_getall_disp(
+ dm_sessid_t sid,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_getall_dmattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern int
+dm_getall_inherit(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int nelem,
+ dm_inherit_t *inheritbufp,
+ u_int *nelemp);
+
+extern int
+dm_getall_sessions(
+ u_int nelem,
+ dm_sessid_t *sidbufp,
+ u_int *nelemp);
+
+extern int
+dm_getall_tokens(
+ dm_sessid_t sid,
+ u_int nelem,
+ dm_token_t *tokenbufp,
+ u_int *nelemp);
+
+extern int
+dm_handle_cmp(
+ void *hanp1,
+ size_t hlen1,
+ void *hanp2,
+ size_t hlen2);
+
+extern void
+dm_handle_free(
+ void *hanp,
+ size_t hlen);
+
+extern u_int
+dm_handle_hash(
+ void *hanp,
+ size_t hlen);
+
+extern dm_boolean_t
+dm_handle_is_valid(
+ void *hanp,
+ size_t hlen);
+
+extern int
+dm_handle_to_fshandle(
+ void *hanp,
+ size_t hlen,
+ void **fshanpp,
+ size_t *fshlenp);
+
+extern int
+dm_handle_to_fsid(
+ void *hanp,
+ size_t hlen,
+ dm_fsid_t *fsidp);
+
+extern int
+dm_handle_to_igen(
+ void *hanp,
+ size_t hlen,
+ dm_igen_t *igenp);
+
+extern int
+dm_handle_to_ino(
+ void *hanp,
+ size_t hlen,
+ dm_ino_t *inop);
+
+extern int
+dm_handle_to_path(
+ void *dirhanp,
+ size_t dirhlen,
+ void *targhanp,
+ size_t targhlen,
+ size_t buflen,
+ char *pathbufp,
+ size_t *rlenp);
+
+extern int
+dm_init_attrloc(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrloc_t *locp);
+
+extern int
+dm_init_service(
+ char **versionstrpp);
+
+extern int
+dm_make_fshandle(
+ dm_fsid_t *fsidp,
+ void **hanpp,
+ size_t *hlenp);
+
+extern int
+dm_make_handle(
+ dm_fsid_t *fsidp,
+ dm_ino_t *inop,
+ dm_igen_t *igenp,
+ void **hanpp,
+ size_t *hlenp);
+
+extern int
+dm_mkdir_by_handle(
+ dm_sessid_t sid,
+ void *dirhanp,
+ size_t dirhlen,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen,
+ char *cname);
+
+extern int
+dm_move_event(
+ dm_sessid_t srcsid,
+ dm_token_t token,
+ dm_sessid_t targetsid,
+ dm_token_t *rtokenp);
+
+extern int
+dm_obj_ref_hold(
+ dm_sessid_t sid,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen);
+
+extern int
+dm_obj_ref_query(
+ dm_sessid_t sid,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen);
+
+extern int
+dm_obj_ref_rele(
+ dm_sessid_t sid,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen);
+
+extern int
+dm_path_to_fshandle(
+ char *path,
+ void **hanpp,
+ size_t *hlenp);
+
+extern int
+dm_path_to_handle(
+ char *path,
+ void **hanpp,
+ size_t *hlenp);
+
+extern int
+dm_pending(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_timestruct_t *delay);
+
+extern int
+dm_probe_hole(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t off,
+ dm_size_t len,
+ dm_off_t *roffp,
+ dm_size_t *rlenp);
+
+extern int
+dm_punch_hole(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t off,
+ dm_size_t len);
+
+extern int
+dm_query_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_right_t *rightp);
+
+extern int
+dm_query_session(
+ dm_sessid_t sid,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp);
+
+extern dm_ssize_t
+dm_read_invis(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t off,
+ dm_size_t len,
+ void *bufp);
+
+extern int
+dm_release_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token);
+
+extern int
+dm_remove_dmattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ int setdtime,
+ dm_attrname_t *attrnamep);
+
+extern int
+dm_request_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int flags,
+ dm_right_t right);
+
+extern int
+dm_respond_event(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_response_t response,
+ int reterror,
+ size_t buflen,
+ void *respbufp);
+
+extern int
+dm_send_msg(
+ dm_sessid_t targetsid,
+ dm_msgtype_t msgtype,
+ size_t buflen,
+ void *bufp);
+
+extern int
+dm_set_disp(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_eventset_t *eventsetp,
+ u_int maxevent);
+
+extern int
+dm_set_dmattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ int setdtime,
+ size_t buflen,
+ void *bufp);
+
+extern int
+dm_set_eventlist(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_eventset_t *eventsetp,
+ u_int maxevent);
+
+extern int
+dm_set_fileattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int mask,
+ dm_fileattr_t *attrp);
+
+extern int
+dm_set_inherit(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ mode_t mode);
+
+extern int
+dm_set_region(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int nelem,
+ dm_region_t *regbufp,
+ dm_boolean_t *exactflagp);
+
+extern int
+dm_set_return_on_destroy(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ dm_boolean_t enable);
+
+extern int
+dm_symlink_by_handle(
+ dm_sessid_t sid,
+ void *dirhanp,
+ size_t dirhlen,
+ dm_token_t token,
+ void *hanp,
+ size_t hlen,
+ char *cname,
+ char *path);
+
+extern int
+dm_sync_by_handle(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token);
+
+extern int
+dm_upgrade_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token);
+
+extern dm_ssize_t
+dm_write_invis(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ int flags,
+ dm_off_t off,
+ dm_size_t len,
+ void *bufp);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DMFSAPI_DMPORT_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+
+/*******************************************************************************
+*
+* NAME
+* find_test_session - find or create a test DMAPI session.
+*
+* DESCRIPTION
+* find_test_session() is used to find a test DMAPI session to
+* use. There is only one test session per host; all test processes
+* share the same session. If the session does not already exist,
+* then the first process to call find_test_session() causes
+* the session to be created.
+*
+* Note: It is possible for N different programs to call this routine
+* at the same time. Each would find that a test session does not
+* exist, and each one would then create a new test session. Since
+* excess test sessions are not automatically released on death of
+* process, we need to make sure that we don't leave such excess
+* sessions around. So, after creating a session we go back and find
+* the test session with the lowest session number. If it is ours,
+* great; we are done. If not, then we must destroy our session
+* and use the one with the lower session ID. There is still a risk
+* here of creating a session and crashing before it can be removed
+* again. To deal with this, the daemon will periodically remove all
+* test sessions except for the one with the lowest ID value.
+*
+* RETURN VALUE
+* None.
+*
+*******************************************************************************/
+
+#define TEST_MSG "DMAPI test session"
+
+static int
+session_compare(
+const void *a,
+const void *b)
+{
+ return(*((dm_sessid_t *)a) - *((dm_sessid_t *)b));
+}
+
+extern void
+find_test_session(
+ dm_sessid_t *session)
+{
+ char buffer[DM_SESSION_INFO_LEN];
+ dm_sessid_t *sidbuf = NULL;
+ dm_sessid_t new_session;
+ u_int allocelem = 0;
+ u_int nelem;
+ size_t rlen;
+ int error;
+ int rc;
+ u_int i;
+
+ /* Retrieve the list of all active sessions on the host. */
+
+ nelem = 100; /* a reasonable first guess */
+ do {
+ if (allocelem < nelem) {
+ allocelem = nelem;
+ sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf));
+ if (sidbuf == NULL) {
+ fprintf(stderr, "realloc of %d bytes failed\n",
+ nelem * sizeof(*sidbuf));
+ exit(1);
+ }
+ }
+ error = dm_getall_sessions(allocelem, sidbuf, &nelem);
+ } while (error < 0 && errno == E2BIG);
+
+ /* If an error occurred, translate it into something meaningful. */
+
+ if (error < 0) {
+ fprintf(stderr, "unexpected dm_getall_sessions failure, %s\n",
+ strerror(errno));
+ free(sidbuf);
+ exit(1);
+ }
+
+ /* We have the list of all active sessions. Scan the list looking
+ for an existing "test" session that we can use. The list must
+ first be sorted in case other processes happen to be creating test
+ sessions at the same time; we need to make sure that we pick the one
+ with the lowest session ID.
+ */
+
+ qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare);
+
+ for (i = 0; i < nelem; i++) {
+ error = dm_query_session(sidbuf[i], sizeof(buffer),
+ buffer, &rlen);
+ if (error < 0) {
+ fprintf(stderr, "unexpected dm_query_session "
+ "failure, %s\n", strerror(errno));
+ free(sidbuf);
+ exit(1);
+ }
+
+ if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG)))
+ break;
+ }
+ if (i < nelem) {
+ *session = (dm_sessid_t)sidbuf[i];
+ free(sidbuf);
+ return;
+ }
+
+ /* No test session exists, so we have to create one ourselves. */
+
+ if (dm_create_session(DM_NO_SESSION, TEST_MSG, &new_session) != 0) {
+ fprintf(stderr, "dm_create_session failed, %s\n",
+ strerror(errno));
+ free(sidbuf);
+ exit(1);
+ }
+
+ /* Now re-retrieve the list of active sessions. */
+
+ do {
+ if (allocelem < nelem) {
+ allocelem = nelem;
+ sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf));
+ if (sidbuf == NULL) {
+ fprintf(stderr, "realloc of %d bytes failed\n",
+ nelem * sizeof(*sidbuf));
+ exit(1);
+ }
+ }
+ error = dm_getall_sessions(allocelem, sidbuf, &nelem);
+ } while (error < 0 && errno == E2BIG);
+
+ if (error < 0) {
+ fprintf(stderr, "dm_getall_sessions failed, %s\n",
+ strerror(errno));
+ free(sidbuf);
+ exit(1);
+ }
+
+ /* Sort the session ID list into ascending ID order, then find the
+ test session with the lowest session ID. We better find at
+ least one since we created one!
+ */
+
+ qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare);
+
+ for (i = 0; i < nelem; i++) {
+ error = dm_query_session(sidbuf[i], sizeof(buffer),
+ buffer, &rlen);
+ if (error < 0) {
+ fprintf(stderr, "dm_query_session failed, %s\n",
+ strerror(errno));
+ free(sidbuf);
+ exit(1);
+ }
+ if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG)))
+ break;
+ }
+ if (i == nelem) {
+ fprintf(stderr, "can't find the session we created\n");
+ free(sidbuf);
+ exit(1);
+ }
+ *session = (dm_sessid_t)sidbuf[i];
+ free(sidbuf);
+
+ /* If the session we are going to use is not the one we created,
+ then we need to get rid of the created one.
+ */
+
+ if (*session != new_session) {
+ if ((new_session) != 0) {
+ fprintf(stderr, "dm_destroy_session failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+}
--- /dev/null
+/*
+ * Defines and structures for our pseudo HSM example
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIB_HSM_H
+#define _LIB_HSM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <lib/dmport.h>
+
+#define HANDLE_LEN 64 /* Swag for this example */
+#define HANDLE_STR ((HANDLE_LEN * 2) + 1) /* handle as ascii, plus null */
+#define IBUFSIZE 1024 /* input buffer size */
+#define CHUNKSIZE (1024*1024*4) /* write size */
+#define FENCEPOST_SIZE ((dm_size_t)(1024*8))
+#define ALL_AVAIL_MSGS 0
+
+/*
+ * Actions to be performed by the worker bees
+ */
+#define RESTORE_FILE "-r"
+#define INVAL_FILE "-i"
+
+#define WORKER_BEE "wbee"
+
+
+/*
+ * Names of DM attribute used for storing location of a file's data.
+ * DM attributes are 8 bytes, including NULL.
+ */
+
+#define DLOC_HAN "dhanloc" /* staging file handle */
+#define DLOC_HANLEN "dhanlen" /* staging handle length */
+
+/*
+ * Default log file
+ */
+#define LOG_DEFAULT "/tmp/dmig_log"
+
+struct ev_name_to_value {
+ char *name; /* name of event */
+ dm_eventtype_t value; /* value of event */
+};
+
+extern struct ev_name_to_value ev_names[];
+extern int ev_namecnt;
+
+
+struct rt_name_to_value {
+ char *name; /* name of right */
+ dm_right_t value; /* value of right */
+};
+
+extern struct rt_name_to_value rt_names[];
+extern int rt_namecnt;
+
+
+extern void hantoa(void *hanp, size_t hlen, char *handle_str);
+extern int atohan(char *handle_str, void **hanpp, size_t *hlenp);
+extern void print_handle(void *hanp, size_t hlen);
+extern void print_victim(void *hanp, size_t hlen, dm_off_t fsize);
+extern void errno_msg(char *fmt, ...);
+extern void err_msg(char *fmt, ...);
+extern int setup_dmapi(dm_sessid_t *sid);
+extern int get_dmchange(dm_sessid_t sid, void *hanp, size_t hlen,
+ dm_token_t token, u_int *change_start);
+extern int save_filedata(dm_sessid_t sid, void *hanp, size_t hlen,
+ int stg_fd, dm_size_t fsize);
+extern int restore_filedata(dm_sessid_t sid, void *hanp, size_t hlen,
+ dm_token_t token, void *stg_hanp, size_t stg_hlen, dm_off_t off);
+
+extern void find_test_session(dm_sessid_t *session);
+
+void
+print_one_mount_event(
+ void *msg);
+
+int
+print_one_message(
+ dm_eventmsg_t *msg);
+
+int
+handle_message(
+ dm_sessid_t sid,
+ dm_eventmsg_t *msg);
+
+extern char *date_to_string(
+ time_t timeval);
+
+extern char *mode_to_string(
+ mode_t mode);
+
+extern mode_t field_to_mode(
+ mode_t mode);
+
+extern int validate_state(
+ dm_stat_t *dmstat,
+ char *pathname,
+ int report_errors);
+
+extern char *emask_to_string(
+ dm_eventset_t emask);
+
+extern char *xflags_to_string(
+ u_int xflags);
+
+extern void print_state(
+ dm_stat_t *dmstat);
+
+extern void print_line(
+ dm_stat_t *dmstat);
+
+extern dm_eventtype_t
+ev_name_to_value(
+ char *name);
+
+extern char *
+ev_value_to_name(
+ dm_eventtype_t event);
+
+extern int
+rt_name_to_value(
+ char *name,
+ dm_right_t *rightp);
+
+extern char *
+rt_value_to_name(
+ dm_right_t right);
+
+extern int
+opaque_to_handle(
+ char *name,
+ void **hanpp,
+ size_t *hlenp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIB_HSM_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#define MAXNAMELEN 256
+#endif
+
+ /*
+ * Define some standard formats for the printf statements below.
+ */
+
+#define HDR "%s: token %d sequence %d\n"
+#define VALS "\t%-15s %s\n"
+#define VALD "\t%-15s %d\n"
+#ifdef __sgi
+#define VALLLD "\t%-15s %lld\n"
+#else
+#define VALLLD "\t%-15s %ld\n"
+#endif
+
+
+/*
+ Convert a mode_t field into a printable string.
+
+ Returns non-zero if the mode_t is invalid. The string is
+ returned in *ptr, whether there is an error or not.
+*/
+
+int
+format_mode(
+ mode_t mode,
+ char **ptr)
+{
+static char modestr[100];
+ char *typestr;
+ int error = 0;
+
+ if (S_ISFIFO(mode)) typestr = "FIFO";
+ else if(S_ISCHR (mode)) typestr = "Character Device";
+ else if(S_ISBLK (mode)) typestr = "Block Device";
+ else if(S_ISDIR (mode)) typestr = "Directory";
+ else if(S_ISREG (mode)) typestr = "Regular File";
+ else if(S_ISLNK (mode)) typestr = "Symbolic Link";
+ else if(S_ISSOCK(mode)) typestr = "Socket";
+ else {
+ typestr = "<unknown type>";
+ error++;
+ }
+
+ sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s",
+ mode,
+ mode & S_ISUID ? 's':' ',
+ mode & S_ISGID ? 'g':' ',
+ mode & S_ISVTX ? 't':' ',
+ mode & S_IRUSR ? 'r':'-',
+ mode & S_IWUSR ? 'w':'-',
+ mode & S_IXUSR ? 'x':'-',
+ mode & S_IRGRP ? 'r':'-',
+ mode & S_IWGRP ? 'w':'-',
+ mode & S_IXGRP ? 'x':'-',
+ mode & S_IROTH ? 'r':'-',
+ mode & S_IWOTH ? 'w':'-',
+ mode & S_IXOTH ? 'x':'-',
+ typestr);
+ *ptr = modestr;
+ return(error);
+}
+
+
+void
+print_one_mount_event(
+ void *msg)
+{
+ void *hanp1, *hanp2, *hanp3;
+ size_t hlen1, hlen2, hlen3;
+ char hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR];
+ void *namp1, *namp2;
+ size_t nlen1, nlen2;
+ char nams1[MAXNAMELEN], nams2[MAXNAMELEN];
+ mode_t mode;
+
+#if VERITAS_21
+ dm_namesp_event_t *msg_ne = (dm_namesp_event_t *)msg;
+
+/*
+ msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
+*/
+ hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *);
+ hlen1 = DM_GET_LEN (msg_ne, ne_handle1);
+ hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *);
+ hlen2 = DM_GET_LEN (msg_ne, ne_handle2);
+ namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *);
+ nlen1 = DM_GET_LEN (msg_ne, ne_name1);
+ namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *);
+ nlen2 = DM_GET_LEN (msg_ne, ne_name2);
+ hanp3 = NULL;
+ hlen3 = 0;
+ mode = msg_ne->ne_mode;
+#else
+ dm_mount_event_t *msg_me = (dm_mount_event_t *)msg;
+
+ hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *);
+ hlen1 = DM_GET_LEN(msg_me, me_handle1);
+ hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *);
+ hlen2 = DM_GET_LEN(msg_me, me_handle2);
+ namp1 = DM_GET_VALUE(msg_me, me_name1, void *);
+ nlen1 = DM_GET_LEN(msg_me, me_name1);
+ namp2 = DM_GET_VALUE(msg_me, me_name2, void *);
+ nlen2 = DM_GET_LEN(msg_me, me_name2);
+ hanp3 = DM_GET_VALUE(msg_me, me_roothandle, void *);
+ hlen3 = DM_GET_LEN(msg_me, me_roothandle);
+ mode = msg_me->me_mode;
+#endif /* VERITAS_21 */
+
+ if (hanp1 && hlen1) {
+ hantoa(hanp1, hlen1, hans1);
+ } else {
+ sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
+ }
+ if (hanp2 && hlen2) {
+ hantoa(hanp2, hlen2, hans2);
+ } else {
+ sprintf(hans2, "<BAD HANDLE, hlen %d>", hlen2);
+ }
+ if (hanp3 && hlen3) {
+ hantoa(hanp3, hlen3, hans3);
+ } else {
+ sprintf(hans3, "<BAD HANDLE, hlen %d>", hlen3);
+ }
+ if (namp1 && nlen1) {
+ strncpy(nams1, namp1, nlen1);
+ if (nlen1 != sizeof(nams1))
+ nams1[nlen1] = '\0';
+ } else {
+ sprintf(nams1, "<BAD STRING, nlen %d>", nlen1);
+ }
+ if (namp2 && nlen2) {
+ strncpy(nams2, namp2, nlen2);
+ if (nlen2 != sizeof(nams2))
+ nams2[nlen2] = '\0';
+ } else {
+ sprintf(nams2, "<BAD STRING, nlen %d>", nlen2);
+ }
+
+ printf(VALS VALS VALS VALS VALS VALD,
+ "fs handle", hans1,
+ "mtpt handle", hans2,
+ "mtpt path", nams1,
+ "media desig", nams2,
+ "root handle", hans3,
+ "mode", mode);
+}
+
+
+static int
+print_one_data_event(
+ dm_data_event_t *msg_de)
+{
+ char handle[HANDLE_STR];
+ void *hanp;
+ size_t hlen;
+
+ hanp = DM_GET_VALUE(msg_de, de_handle, void *);
+ hlen = DM_GET_LEN (msg_de, de_handle);
+
+ if (hanp && hlen) {
+ hantoa(hanp, hlen, handle);
+ } else {
+ sprintf(handle, "<BAD HANDLE, hlen %d>", hlen);
+ }
+
+ printf(VALS VALLLD VALLLD,
+ "file handle", handle,
+ "offset", msg_de->de_offset,
+ "length", msg_de->de_length);
+
+ return(0);
+}
+
+
+int
+print_one_message(
+ dm_eventmsg_t *msg)
+{
+ int pkt_error = 0;
+ int error;
+ dm_namesp_event_t *msg_ne;
+ void *hanp1, *hanp2, *namp1, *namp2;
+ u_int hlen1, hlen2, nlen1, nlen2;
+ char hans1[HANDLE_STR], hans2[HANDLE_STR];
+ char nams1[MAXNAMELEN], nams2[MAXNAMELEN];
+
+ /***** USER EVENTS *****/
+
+ if (msg->ev_type == DM_EVENT_USER) {
+ char *privp;
+ u_int plen, i;
+
+ printf(HDR,
+ "user", msg->ev_token, msg->ev_sequence);
+
+ /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */
+
+ privp = DM_GET_VALUE(msg, ev_data, char *);
+ plen = DM_GET_LEN (msg, ev_data);
+ if (plen) {
+ for (i = 0; i < plen; i++) {
+ if (!isprint(privp[i]) && !isspace(privp[i]))
+ break;
+ }
+ if (i == plen - 1 && privp[i] == '\0') {
+ printf(VALS,
+ "privdata", privp);
+ } else {
+ printf("\t%-15s ", "privdata");
+ for (i = 0; i < plen; i++) {
+ printf("%.2x", privp[i]);
+ }
+ printf("\n");
+ }
+ } else {
+ printf(VALS,
+ "privdata", "<NONE>");
+ }
+
+ /***** CANCEL EVENT *****/
+
+/* Not implemented on SGI or Veritas */
+
+ } else if (msg->ev_type == DM_EVENT_CANCEL) {
+ dm_cancel_event_t *msg_ce;
+
+ msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *);
+ printf(HDR VALD VALD,
+ "cancel", msg->ev_token, msg->ev_sequence,
+ "sequence", msg_ce->ce_sequence,
+ "token", msg_ce->ce_token);
+
+ /***** DATA EVENTS *****/
+
+ } else if (msg->ev_type == DM_EVENT_READ ||
+ msg->ev_type == DM_EVENT_WRITE ||
+ msg->ev_type == DM_EVENT_TRUNCATE) {
+ dm_data_event_t *msg_de;
+
+ msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *);
+
+ switch (msg->ev_type) {
+ case DM_EVENT_READ:
+ printf(HDR, "read", msg->ev_token, msg->ev_sequence);
+ break;
+
+ case DM_EVENT_WRITE:
+ printf(HDR, "write", msg->ev_token, msg->ev_sequence);
+ break;
+
+ case DM_EVENT_TRUNCATE:
+ printf(HDR, "truncate", msg->ev_token,
+ msg->ev_sequence);
+ break;
+ }
+ print_one_data_event(msg_de);
+
+ /***** DESTROY EVENT *****/
+
+ } else if (msg->ev_type == DM_EVENT_DESTROY) {
+ dm_destroy_event_t *msg_ds;
+ char attrname[DM_ATTR_NAME_SIZE + 1];
+ u_char *copy;
+ u_int clen;
+ u_int i;
+
+ msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *);
+ hanp1 = DM_GET_VALUE(msg_ds, ds_handle, void *);
+ hlen1 = DM_GET_LEN (msg_ds, ds_handle);
+ if (hanp1 && hlen1) {
+ hantoa(hanp1, hlen1, hans1);
+ } else {
+ sprintf(hans1, "<BAD HANDLE, hlen %d>", hlen1);
+ }
+ if (msg_ds->ds_attrname.an_chars[0] != '\0') {
+ strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname));
+ } else {
+ strcpy(attrname, "<NONE>");
+ }
+ printf(HDR VALS VALS,
+ "destroy", msg->ev_token, msg->ev_sequence,
+ "handle", hans1,
+ "attrname", attrname);
+ copy = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *);
+ clen = DM_GET_LEN (msg_ds, ds_attrcopy);
+ if (copy && clen) {
+ printf("\t%-15s ", "attrcopy");
+ for (i = 0; i < clen; i++) {
+ printf("%.2x", copy[i]);
+ }
+ printf("\n");
+ } else {
+ printf(VALS, "attrcopy", "<NONE>");
+ }
+
+ /***** MOUNT EVENT *****/
+
+ } else if (msg->ev_type == DM_EVENT_MOUNT) {
+ void *msg_body;
+
+ printf(HDR, "mount", msg->ev_token, msg->ev_sequence);
+#if !VERITAS_21
+ msg_body = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *);
+#else /* VERITAS_21 */
+ msg_body = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
+#endif /* VERITAS_21 */
+ print_one_mount_event(msg_body);
+
+ /***** NAMESPACE EVENTS *****/
+
+ } else {
+ char *type;
+
+ msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *);
+ hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *);
+ hlen1 = DM_GET_LEN (msg_ne, ne_handle1);
+ hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *);
+ hlen2 = DM_GET_LEN (msg_ne, ne_handle2);
+ namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *);
+ nlen1 = DM_GET_LEN (msg_ne, ne_name1);
+ namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *);
+ nlen2 = DM_GET_LEN (msg_ne, ne_name2);
+
+ if (hanp1 && hlen1) {
+ hantoa(hanp1, hlen1, hans1);
+ }
+ if (hanp2 && hlen2) {
+ hantoa(hanp2, hlen2, hans2);
+ }
+ if (namp1 && nlen1) {
+ strncpy(nams1, namp1, nlen1);
+ if (nlen1 != sizeof(nams1))
+ nams1[nlen1] = '\0';
+ }
+ if (namp2 && nlen2) {
+ strncpy(nams2, namp2, nlen2);
+ if (nlen2 != sizeof(nams2))
+ nams2[nlen2] = '\0';
+ }
+
+ if (msg->ev_type == DM_EVENT_PREUNMOUNT ||
+ msg->ev_type == DM_EVENT_UNMOUNT) {
+ if (msg_ne->ne_mode == 0) {
+ type = "NOFORCE";
+#if !VERITAS_21
+ } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) {
+#else
+ } else if (msg_ne->ne_mode > 0) {
+#endif
+ type = "FORCE";
+ } else {
+ type = "UNKNOWN";
+ pkt_error++;
+ }
+ } else if (msg->ev_type == DM_EVENT_CREATE ||
+ msg->ev_type == DM_EVENT_POSTCREATE ||
+ msg->ev_type == DM_EVENT_REMOVE ||
+ msg->ev_type == DM_EVENT_POSTREMOVE) {
+ if (format_mode(msg_ne->ne_mode, &type)) {
+ pkt_error++;
+ }
+ }
+
+ switch(msg->ev_type) {
+
+ case DM_EVENT_PREUNMOUNT:
+ printf(HDR VALS VALS VALS,
+ "preunmount", msg->ev_token, msg->ev_sequence,
+ "fs handle", hans1,
+ "root dir", hans2,
+ "unmount mode", type);
+ break;
+
+ case DM_EVENT_UNMOUNT:
+ printf(HDR VALS VALS VALD,
+ "unmount", msg->ev_token, msg->ev_sequence,
+ "fs handle", hans1,
+ "unmount mode", type,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_NOSPACE:
+ printf(HDR VALS,
+ "nospace", msg->ev_token, msg->ev_sequence,
+ "fs handle", hans1);
+ break;
+
+ case DM_EVENT_DEBUT: /* not supported on SGI */
+ printf(HDR VALS,
+ "debut", msg->ev_token, msg->ev_sequence,
+ "object", hans1);
+ break;
+
+ case DM_EVENT_CREATE:
+ printf(HDR VALS VALS VALS,
+ "create", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "name", nams1,
+ "mode bits", type);
+ break;
+
+ case DM_EVENT_POSTCREATE:
+ printf(HDR VALS VALS VALS VALS VALD,
+ "postcreate", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "new object", hans2,
+ "name", nams1,
+ "mode bits", type,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_REMOVE:
+ printf(HDR VALS VALS VALS,
+ "remove", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "name", nams1,
+ "mode bits", type);
+ break;
+
+ case DM_EVENT_POSTREMOVE:
+ printf(HDR VALS VALS VALS VALD,
+ "postremove", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "name", nams1,
+ "mode bits", type,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_RENAME:
+ printf(HDR VALS VALS VALS VALS,
+ "rename", msg->ev_token, msg->ev_sequence,
+ "old parent", hans1,
+ "new parent", hans2,
+ "old name", nams1,
+ "new name", nams2);
+ break;
+
+ case DM_EVENT_POSTRENAME:
+ printf(HDR VALS VALS VALS VALS VALD,
+ "postrename", msg->ev_token, msg->ev_sequence,
+ "old parent", hans1,
+ "new parent", hans2,
+ "old name", nams1,
+ "new name", nams2,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_SYMLINK:
+ printf(HDR VALS VALS VALS,
+ "symlink", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "name", nams1,
+ "contents", nams2);
+ break;
+
+ case DM_EVENT_POSTSYMLINK:
+ printf(HDR VALS VALS VALS VALS VALD,
+ "postsymlink", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "new object", hans2,
+ "name", nams1,
+ "contents", nams2,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_LINK:
+ printf(HDR VALS VALS VALS,
+ "link", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "source", hans2,
+ "name", nams1);
+ break;
+
+ case DM_EVENT_POSTLINK:
+ printf(HDR VALS VALS VALS VALD,
+ "postlink", msg->ev_token, msg->ev_sequence,
+ "parent dir", hans1,
+ "source", hans2,
+ "name", nams1,
+ "retcode", msg_ne->ne_retcode);
+ break;
+
+ case DM_EVENT_ATTRIBUTE:
+ printf(HDR VALS,
+ "attribute", msg->ev_token, msg->ev_sequence,
+ "object", hans1);
+ break;
+
+ case DM_EVENT_CLOSE: /* not supported on SGI */
+ printf(HDR VALS,
+ "close", msg->ev_token, msg->ev_sequence,
+ "object", hans1);
+ break;
+
+ default:
+ pkt_error++;
+ printf(HDR VALD,
+ "<UNKNOWN>", msg->ev_token, msg->ev_sequence,
+ "ev_type", msg->ev_type);
+ break;
+ }
+ }
+ return(pkt_error);
+}
+
+
+int
+handle_message(
+ dm_sessid_t sid,
+ dm_eventmsg_t *msg)
+{
+ int respond, response, respcode;
+ int error = 0;
+
+ if (print_one_message(msg))
+ error++;
+
+ /* Set the defaults for responding to events. */
+
+ respond = 1;
+ response = DM_RESP_CONTINUE;
+ respcode = 0;
+
+ /***** USER EVENTS *****/
+
+ switch (msg->ev_type) {
+ case DM_EVENT_USER:
+ if (msg->ev_token == DM_INVALID_TOKEN)
+ respond = 0;
+ break;
+
+ case DM_EVENT_CANCEL:
+ case DM_EVENT_DESTROY:
+ case DM_EVENT_POSTCREATE:
+ case DM_EVENT_POSTREMOVE:
+ case DM_EVENT_POSTRENAME:
+ case DM_EVENT_POSTSYMLINK:
+ case DM_EVENT_POSTLINK:
+ case DM_EVENT_ATTRIBUTE:
+ case DM_EVENT_CLOSE:
+ respond = 0;
+ break;
+
+ case DM_EVENT_MOUNT:
+ case DM_EVENT_READ:
+ case DM_EVENT_WRITE:
+ case DM_EVENT_TRUNCATE:
+ case DM_EVENT_PREUNMOUNT:
+ case DM_EVENT_UNMOUNT:
+ case DM_EVENT_DEBUT:
+ case DM_EVENT_CREATE:
+ case DM_EVENT_REMOVE:
+ case DM_EVENT_RENAME:
+ case DM_EVENT_SYMLINK:
+ case DM_EVENT_LINK:
+ break;
+
+ case DM_EVENT_NOSPACE:
+ response = DM_RESP_ABORT;
+ respcode = ENOSPC;
+ break;
+
+ default:
+ if (msg->ev_token == DM_INVALID_TOKEN)
+ respond = 0;
+ break;
+ }
+
+ /* Respond to those messages which require a response. */
+
+ if (respond) {
+ if (dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0)) {
+ errno_msg("Can't respond to event");
+ }
+ }
+ return(error);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <errno.h>
+
+#include <stdlib.h>
+#include <lib/dmport.h>
+
+
+/* See dmport.h for a description of why all these wrapper routines are
+ necessary. Because SGI defines stub routines for all functions it didn't
+ implement, no SGI-specific wrappers are required.
+*/
+
+
+#ifdef VERITAS_21
+
+/* The Veritas version of dm_downgrade_right has two additional parameters
+ not defined in the XDSM spec. Provide values that make dm_downgrade_right
+ work according to the spec.
+*/
+
+extern int
+xvfs_dm_downgrade_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token)
+{
+#undef dm_downgrade_right
+ return(dm_downgrade_right(sid, hanp, hlen, token, 0, DM_RIGHT_SHARED));
+}
+
+
+/* The last byte in a Veritas handle is a 'pad' byte which they don't bother
+ to initialize to zero. As a result, you can't do binary compares of
+ two handles to see if they are the same. This stub (along with others)
+ forces the pad byte to zero so that binary compares are possible
+*/
+
+extern int
+xvfs_dm_fd_to_handle(
+ int fd,
+ void **hanpp,
+ size_t *hlenp)
+{
+#undef dm_fd_to_handle
+ int rc;
+
+ if ((rc = dm_fd_to_handle(fd, hanpp, hlenp)) == 0) {
+ if (*hlenp == 16) {
+ char *cp = (char *)*hanpp;
+ cp[15] = '\0';
+ }
+ }
+ return(rc);
+}
+
+
+/* The Veritas version of dm_get_config_events has a slightly different name.
+*/
+
+extern int
+dm_get_config_events(
+ void *hanp,
+ size_t hlen,
+ u_int nelem,
+ dm_eventset_t *eventsetp,
+ u_int *nelemp)
+{
+ return(dm_get_config_event(hanp, hlen, nelem, eventsetp, nelemp));
+}
+
+
+/* In version 2.1 uflags was defined as 'int nowait', so a value of zero in
+ this field means that the caller wants to wait. In XDSM this was reversed,
+ where if the bottom bit of uflags is set then the caller wants to wait.
+ This routine makes the conversion.
+*/
+
+extern int
+xvfs_dm_get_events(
+ dm_sessid_t sid,
+ u_int maxmsgs,
+ u_int uflags,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp)
+{
+#undef dm_get_events
+ int nowait = 1;
+
+ if (uflags & DM_EV_WAIT)
+ nowait = 0;
+
+ return(dm_get_events(sid, maxmsgs, nowait, buflen, bufp, rlenp));
+}
+
+
+/* The Veritas version of dm_get_mountinfo has the parameters in a different
+ order than in the XDSM spec. Hide this in the wrapper.
+*/
+
+extern int
+xvfs_dm_get_mountinfo(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp)
+{
+#undef dm_get_mountinfo
+ return(dm_get_mountinfo(sid, token, hanp, hlen, buflen, bufp, rlenp));
+}
+
+
+/* Veritas does not support the dm_getall_disp function. Furthermore, their
+ dm_dispinfo_t structure is missing the _link field that is needed for the
+ DM_STEP_TO_NEXT() macro to work.
+*/
+
+extern int
+dm_getall_disp(
+ dm_sessid_t sid,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp)
+{
+ return(ENOSYS);
+}
+
+
+/* Veritas does not support the dm_getall_dmattr function. Furthermore, their
+ dm_attrlist_t structure is missing the _link field that is needed for the
+ DM_STEP_TO_NEXT() macro to work.
+*/
+
+extern int
+dm_getall_dmattr(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ size_t buflen,
+ void *bufp,
+ size_t *rlenp)
+{
+ return(ENOSYS);
+}
+
+
+/* Veritas does not support dm_handle_is_valid. We emulate it by checking
+ fields which have known values, as DMF uses this a lot.
+*/
+
+extern dm_boolean_t
+dm_handle_is_valid(
+ void *hanp,
+ size_t hlen)
+{
+ char *cp = (char *)hanp;
+
+ if (hlen != 16) {
+ return(DM_FALSE);
+ }
+ if (cp[15] != '\0') {
+ return(DM_FALSE);
+ }
+ switch (cp[14]) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ return(DM_FALSE);
+ }
+ switch (cp[13]) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return(DM_FALSE);
+ }
+ return(DM_TRUE);
+}
+
+
+/* Veritas uses a dev_t for their dm_fsid_t, and named their routines
+ accordingly. Hide this in the wrapper. Note that a dev_t is 32 bits
+ and the SGI dm_fsid_t is defined to be a uint64_t. If this gets to
+ be a problem (e.g. %x verus %llx), the Veritas dm_fsid_t could be made
+ to match SGI with a little casting here and there.
+*/
+
+extern int
+dm_handle_to_fsid(
+ void *hanp,
+ size_t hlen,
+ dm_fsid_t *fsidp)
+{
+ dev_t dev;
+
+ dev = dm_handle_to_dev(hanp, hlen);
+ *fsidp = (dm_fsid_t)dev;
+ return(0);
+}
+
+
+/* The Veritas dm_handle_to_fgen returns a long which is really the
+ file's generation number. dm_igen_t is typedef'd to be a long also,
+ so the cast here is safe.
+*/
+
+extern int
+dm_handle_to_igen(
+ void *hanp,
+ size_t hlen,
+ dm_igen_t *igenp)
+{
+#undef dm_handle_to_igen
+ long igen;
+
+ igen = (dm_igen_t)dm_handle_to_fgen(hanp, hlen);
+ *igenp = (dm_igen_t)igen;
+ return(0);
+}
+
+
+/* Veritas uses a long for their dm_ino_t, which is really an ino_t.
+ Hide this in the wrapper. Note that a ino_t is 32 bits and the SGI
+ dm_ino_t is defined to be a uint64_t. If this gets to be a problem
+ (e.g. %x verus %llx), the Veritas dm_ino_t could be made to match SGI
+ with a little casting here and there.
+*/
+
+
+extern int
+xvfs_dm_handle_to_ino(
+ void *hanp,
+ size_t hlen,
+ dm_ino_t *inop)
+{
+#undef dm_handle_to_ino
+ long ino;
+
+ ino = (dm_ino_t)dm_handle_to_ino(hanp, hlen);
+ *inop = (dm_ino_t)ino;
+ return(0);
+}
+
+
+/* Version 2.1 of the spec did not specify the versionstrpp parameter. This
+ code makes the routine appear to work correctly to the caller, but it
+ is not really able to do the runtime check that the parameter is
+ supposed to provide.
+*/
+
+extern int
+xvfs_dm_init_service(
+ char **versionstrpp)
+{
+#undef dm_init_service
+ *versionstrpp = DM_VER_STR_CONTENTS;
+ return(dm_init_service());
+}
+
+
+extern int
+xvfs_dm_make_fshandle(
+ dm_fsid_t *fsidp,
+ void **hanpp,
+ size_t *hlenp)
+{
+#undef dm_make_fshandle
+ dev_t dev;
+
+ dev = (dev_t)*fsidp;
+ return(dm_make_fshandle(dev, hanpp, hlenp));
+}
+
+
+extern int
+xvfs_dm_make_handle(
+ dm_fsid_t *fsidp,
+ dm_ino_t *inop,
+ dm_igen_t *igenp,
+ void **hanpp,
+ size_t *hlenp)
+{
+#undef dm_make_handle
+ dev_t dev;
+ long ino;
+ long igen;
+
+ dev = (dev_t)*fsidp;
+ ino = (long)*inop;
+ igen = (long)*igenp;
+ return(dm_make_handle(dev, ino, igen, hanpp, hlenp));
+}
+
+
+/* The last byte in a Veritas handle is a 'pad' byte which they don't bother
+ to initialize to zero. As a result, you can't do binary compares of
+ two handles to see if they are the same. This stub (along with others)
+ forces the pad byte to zero so that binary compares are possible
+*/
+
+extern int
+xvfs_dm_path_to_fshandle(
+ char *path,
+ void **fshanpp,
+ size_t *fshlenp)
+{
+#undef dm_path_to_fshandle
+ int rc;
+
+ if ((rc = dm_path_to_fshandle(path, fshanpp, fshlenp)) == 0) {
+ if (*fshlenp == 16) {
+ char *cp = (char *)*fshanpp;
+ cp[15] = '\0';
+ }
+ }
+ return(rc);
+}
+
+
+/* The last byte in a Veritas handle is a 'pad' byte which they don't bother
+ to initialize to zero. As a result, you can't do binary compares of
+ two handles to see if they are the same. This stub (along with others)
+ forces the pad byte to zero so that binary compares are possible
+*/
+
+extern int
+xvfs_dm_path_to_handle(
+ char *path,
+ void **hanpp,
+ size_t *hlenp)
+{
+#undef dm_path_to_handle
+ int rc;
+
+ if ((rc = dm_path_to_handle(path, hanpp, hlenp)) == 0) {
+ if (*hlenp == 16) {
+ char *cp = (char *)*hanpp;
+ cp[15] = '\0';
+ }
+ }
+ return(rc);
+}
+
+
+/* Veritas has a prototype for this function even though it is not
+ implemented.
+*/
+
+extern int
+xvfs_dm_pending(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_timestruct_t *delay)
+{
+#undef dm_pending
+ return(ENOSYS);
+}
+
+
+extern int
+xvfs_dm_read_invis(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t off,
+ dm_size_t len,
+ void *bufp)
+{
+#undef dm_read_invis
+ return(dm_read_invis(sid, hanp, hlen, token, off, (dm_ssize_t)len, bufp));
+}
+
+
+/* In version 2.1 uflags was defined as 'int nowait', so a value of zero in
+ this field means that the caller wants to wait. In XDSM this was reversed,
+ where if the bottom bit of uflags is set then the caller wants to wait.
+ This routine makes the conversion.
+*/
+
+extern int
+xvfs_dm_request_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int uflags,
+ dm_right_t right)
+{
+#undef dm_request_right
+ int nowait = 1;
+
+ if (uflags & DM_RR_WAIT)
+ nowait = 0;
+ return(dm_request_right(sid, hanp, hlen, token, nowait, right));
+}
+
+
+extern int
+xvfs_dm_set_inherit(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ mode_t mode)
+{
+#undef dm_set_inherit
+ return(dm_set_inherit(sid, hanp, hlen, token, attrnamep, (u_int)mode));
+}
+
+
+extern int
+xvfs_dm_set_region(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int nelem,
+ dm_region_t *regbufp,
+ dm_boolean_t *exactflagp)
+{
+#undef dm_set_region
+ return(dm_set_region(sid, hanp, hlen, token, nelem, regbufp, (u_int *)exactflagp));
+}
+
+
+extern int
+dm_set_return_on_destroy(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_attrname_t *attrnamep,
+ dm_boolean_t enable)
+{
+ return(dm_set_return_ondestroy(sid, hanp, hlen, token, attrnamep, (int)enable));
+}
+
+
+extern int
+xvfs_dm_sync_by_handle(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token)
+{
+#undef dm_sync_by_handle
+ return((int)dm_sync_by_handle(sid, hanp, hlen, token));
+}
+
+extern int
+xvfs_dm_upgrade_right(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token)
+{
+#undef dm_upgrade_right
+ return(dm_upgrade_right(sid, hanp, hlen, token, 0, DM_RIGHT_EXCL));
+}
+
+
+extern int
+xvfs_dm_write_invis(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ int flags,
+ dm_off_t off,
+ dm_size_t len,
+ void *bufp)
+{
+#undef dm_write_invis
+ return(dm_write_invis(sid, hanp, hlen, token, off, (dm_ssize_t)len, bufp, flags));
+}
+
+#endif
--- /dev/null
+/*
+ * Utility routines
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <time.h>
+#define S_IAMB (S_IRWXU|S_IRWXG|S_IRWXO)
+#endif
+
+#define S_MASK (S_ISUID|S_ISGID|S_ISVTX|S_IAMB)
+
+extern char *Progname;
+extern int errno;
+
+void err_msg(char *, ...);
+void errno_msg(char *, ...);
+
+struct ev_name_to_value ev_names[] = {
+ { "DM_EVENT_CANCEL", DM_EVENT_CANCEL },
+ { "DM_EVENT_MOUNT", DM_EVENT_MOUNT },
+ { "DM_EVENT_PREUNMOUNT", DM_EVENT_PREUNMOUNT },
+ { "DM_EVENT_UNMOUNT", DM_EVENT_UNMOUNT },
+ { "DM_EVENT_DEBUT", DM_EVENT_DEBUT },
+ { "DM_EVENT_CREATE", DM_EVENT_CREATE },
+ { "DM_EVENT_CLOSE", DM_EVENT_CLOSE },
+ { "DM_EVENT_POSTCREATE", DM_EVENT_POSTCREATE },
+ { "DM_EVENT_REMOVE", DM_EVENT_REMOVE },
+ { "DM_EVENT_POSTREMOVE", DM_EVENT_POSTREMOVE },
+ { "DM_EVENT_RENAME", DM_EVENT_RENAME },
+ { "DM_EVENT_POSTRENAME", DM_EVENT_POSTRENAME },
+ { "DM_EVENT_LINK", DM_EVENT_LINK },
+ { "DM_EVENT_POSTLINK", DM_EVENT_POSTLINK },
+ { "DM_EVENT_SYMLINK", DM_EVENT_SYMLINK },
+ { "DM_EVENT_POSTSYMLINK", DM_EVENT_POSTSYMLINK },
+ { "DM_EVENT_READ", DM_EVENT_READ },
+ { "DM_EVENT_WRITE", DM_EVENT_WRITE },
+ { "DM_EVENT_TRUNCATE", DM_EVENT_TRUNCATE },
+ { "DM_EVENT_ATTRIBUTE", DM_EVENT_ATTRIBUTE },
+ { "DM_EVENT_DESTROY", DM_EVENT_DESTROY },
+ { "DM_EVENT_NOSPACE", DM_EVENT_NOSPACE },
+ { "DM_EVENT_USER", DM_EVENT_USER }
+};
+
+int ev_namecnt = sizeof(ev_names) / sizeof(ev_names[0]);
+
+dm_eventtype_t
+ev_name_to_value(
+ char *name)
+{
+ int i;
+
+ for (i = 0; i < ev_namecnt; i++) {
+ if (!strcmp(name, ev_names[i].name))
+ return(ev_names[i].value);
+ }
+ return(DM_EVENT_INVALID);
+}
+
+char *
+ev_value_to_name(
+ dm_eventtype_t event)
+{
+ static char buffer[100];
+ int i;
+
+ for (i = 0; i < ev_namecnt; i++) {
+ if (event == ev_names[i].value)
+ return(ev_names[i].name);
+ }
+ sprintf(buffer, "Unknown Event Number %d\n", event);
+ return(buffer);
+}
+
+
+
+struct rt_name_to_value rt_names[] = {
+ { "DM_RIGHT_NULL", DM_RIGHT_NULL },
+ { "DM_RIGHT_SHARED", DM_RIGHT_SHARED },
+ { "DM_RIGHT_EXCL", DM_RIGHT_EXCL }
+};
+
+int rt_namecnt = sizeof(rt_names) / sizeof(rt_names[0]);
+
+int
+rt_name_to_value(
+ char *name,
+ dm_right_t *rightp)
+{
+ int i;
+
+ for (i = 0; i < rt_namecnt; i++) {
+ if (!strcmp(name, rt_names[i].name)) {
+ *rightp = rt_names[i].value;
+ return(0);
+ }
+ }
+ return(1);
+}
+
+
+char *
+rt_value_to_name(
+ dm_right_t right)
+{
+ int i;
+
+ for (i = 0; i < rt_namecnt; i++) {
+ if (right == rt_names[i].value)
+ return(rt_names[i].name);
+ }
+ return(NULL);
+}
+
+
+/*
+ * Convert a handle from (possibly) binary to ascii.
+ */
+void
+hantoa(
+ void *hanp,
+ size_t hlen,
+ char *handle_str)
+{
+ int i;
+ u_char *cp;
+
+ cp = (u_char *)hanp;
+ for (i=0;i<hlen; i++) {
+ sprintf(handle_str, "%.2x", *cp++);
+ handle_str += 2;
+ }
+ *handle_str = '\0'; /* Null-terminate to make it printable */
+}
+
+/*
+ * Convert a handle from ascii back to it's native binary representation
+ */
+
+int
+atohan(
+ char *handle_str,
+ void **hanpp,
+ size_t *hlenp)
+{
+ u_char handle[HANDLE_LEN];
+ char cur_char[3];
+ int i = 0;
+ u_long num;
+
+ if (strlen(handle_str) > HANDLE_LEN * 2){
+ return(EBADF);
+ }
+
+ while (*handle_str && *(handle_str + 1)) {
+ if (i == HANDLE_LEN){
+ return(EBADF);
+ }
+ cur_char[0] = *handle_str;
+ cur_char[1] = *(handle_str + 1);
+ cur_char[2] = '\0';
+ num = strtol(cur_char, (char **)0, 16);
+ handle[i++] = num & 0xff;
+ handle_str += 2;
+ }
+ if (*handle_str){
+ return(EBADF);
+ }
+ *hlenp = i;
+ if ((*hanpp = malloc(*hlenp)) == NULL)
+ return(ENOMEM);
+ memcpy(*hanpp, handle, *hlenp);
+ return(0);
+}
+
+
+int
+opaque_to_handle(
+ char *name,
+ void **hanpp,
+ size_t *hlenp)
+{
+ if (atohan(name, hanpp, hlenp)) {
+ /* not a handle */
+ } else if (dm_handle_is_valid(*hanpp, *hlenp) == DM_FALSE) {
+ dm_handle_free(*hanpp, *hlenp);
+ /* not a handle */
+ } else {
+ return(0);
+ }
+
+ /* Perhaps it is a pathname */
+
+ if (dm_path_to_handle(name, hanpp, hlenp)) {
+ return(errno);
+ }
+ return(0);
+}
+
+
+void
+print_handle(
+ void *hanp,
+ size_t hlen)
+{
+ char handle_str[HANDLE_STR];
+
+ if (hlen > HANDLE_LEN) {
+ printf("-- invalid hlen length %d --\n", hlen);
+ return;
+ }
+
+ printf("print_handle: ");
+ printf("%d\t", hlen);
+ hantoa(hanp, hlen, handle_str);
+ printf("%s\n ", handle_str);
+}
+
+void
+print_victim(
+ void *hanp,
+ size_t hlen,
+ dm_off_t fsize)
+{
+ char handle_str[HANDLE_STR];
+
+ if (hlen > HANDLE_LEN) {
+ printf("-- invalid length --\n");
+ return;
+ }
+
+ printf("%d\t", hlen);
+ hantoa(hanp, hlen, handle_str);
+ printf("%s ", handle_str);
+#ifdef __sgi
+ printf("\t%lld \n", fsize);
+#else
+ printf("\t%ld \n", fsize);
+#endif
+}
+
+
+/*
+ * Print out a simple error message, and include the errno
+ * string with it.
+ */
+void
+errno_msg(char *fmt, ...)
+{
+ va_list ap;
+ int old_errno;
+
+ old_errno = errno;
+ fprintf(stderr, "%s: ", Progname);
+
+ va_start(ap, fmt );
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ errno = old_errno;
+ perror("\n\tError");
+}
+
+/*
+ * Print out a simple error message
+ */
+void
+err_msg(char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s: ", Progname);
+
+ va_start(ap, fmt );
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+}
+
+
+/*
+ * Initialize the interface to the DMAPI
+ */
+int
+setup_dmapi(dm_sessid_t *sidp)
+{
+ char *cp;
+
+ if (dm_init_service(&cp) == -1) {
+ err_msg("%s/%d: Can't init dmapi", __FILE__, __LINE__);
+ return(1);
+ }
+ if (strcmp(cp, DM_VER_STR_CONTENTS)) {
+ err_msg("%s/%d: Compiled for a different version", __FILE__, __LINE__);
+ return(1);
+ }
+
+ find_test_session(sidp);
+ return(0);
+}
+
+/*
+ * Get the file's change indicator
+ */
+int
+get_dmchange(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ u_int *change_start)
+{
+ int error;
+ dm_stat_t statbuf;
+
+
+ error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_CFLAG, &statbuf);
+ if (error == -1) {
+ errno_msg("%s/%d: Can't stat file (%d)", __FILE__, __LINE__, errno);
+ return(1);
+ }
+ *change_start = statbuf.dt_change;
+ return(0);
+}
+
+
+/*
+ * Write a file's data to the staging file. We write the file out
+ * in 4meg chunks.
+ */
+int
+save_filedata(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ int stg_fd,
+ dm_size_t fsize)
+{
+ char *filebuf;
+ int i, nbufs;
+ int retval;
+ dm_ssize_t nread, lastbuf;
+ ssize_t nwrite;
+ dm_off_t off;
+
+ nbufs = fsize / CHUNKSIZE;
+ off = 0;
+ retval = 0;
+ filebuf = malloc(CHUNKSIZE);
+ if (filebuf == NULL) {
+ err_msg("%s/%d: Can't alloc memory for file buffer", __FILE__, __LINE__);
+ goto out;
+ }
+
+ for (i = 0; i<nbufs; i++) {
+ nread = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off,
+ (dm_ssize_t)CHUNKSIZE, filebuf);
+ if (nread != CHUNKSIZE) {
+#ifdef __sgi
+ errno_msg("%s/%d: invis read err: got %lld, expected %lld, buf %d",
+#else
+ errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
+#endif
+ __FILE__, __LINE__,
+ nread, (dm_ssize_t)CHUNKSIZE, i);
+ retval = 1;
+ goto out;
+ }
+ off += nread;
+
+ nwrite = write(stg_fd, filebuf, CHUNKSIZE);
+ if (nwrite != CHUNKSIZE) {
+ errno_msg("%s/%d: write err %d, expected %d, buf %d",
+ __FILE__, __LINE__,
+ nwrite, CHUNKSIZE, i);
+ retval = 1;
+ goto out;
+ }
+ }
+
+ lastbuf = fsize % CHUNKSIZE;
+ nread = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, off,
+ (dm_ssize_t)lastbuf, filebuf);
+ if (nread != lastbuf) {
+#ifdef __sgi
+ errno_msg("%s/%d: invis read error- got %lld, expected %lld, last buf",
+#else
+ errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
+#endif
+ __FILE__, __LINE__,
+ nread, lastbuf);
+ retval = 1;
+ goto out;
+ }
+
+ nwrite = write(stg_fd, filebuf, (int)lastbuf);
+ if (nwrite != lastbuf) {
+#ifdef __sgi
+ errno_msg("%s/%d: write error %d, expected %lld, last buffer",
+#else
+ errno_msg("%s/%d: write error %d, expected %d, last buffer",
+#endif
+ __FILE__, __LINE__,
+ nwrite, lastbuf);
+ retval = 1;
+ }
+out:
+ if (filebuf)
+ free(filebuf);
+
+ close(stg_fd);
+ return(retval);
+}
+
+
+
+/*
+ * Read a file's data from the staging file.
+ * Since we only have the staging file handle (not a file descriptor)
+ * we use dm_read_invis() to read the data.
+ *
+ * We stage the entire file in, regardless of how much was asked for,
+ * starting at the faulting offset.
+ */
+int
+restore_filedata(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ void *stg_hanp,
+ size_t stg_hlen,
+ dm_off_t off)
+{
+ char *filebuf;
+ int i, nbufs;
+ int error, retval;
+ dm_ssize_t nread, nwrite, lastbuf;
+ dm_off_t fsize;
+ dm_stat_t dm_statbuf;
+
+ error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_STAT,
+ &dm_statbuf);
+ if (error == -1) {
+ errno_msg("%s/%d: Can't get dm stats of file (%d)", __FILE__, __LINE__, errno);
+ return(1);
+ }
+
+ fsize = dm_statbuf.dt_size;
+ nbufs = fsize / CHUNKSIZE;
+ retval = 0;
+
+ filebuf = malloc(CHUNKSIZE);
+ if (filebuf == NULL) {
+ err_msg("%s/%d: Can't alloc memory for file buffer", __FILE__, __LINE__);
+ goto out;
+ }
+
+ for (i = 0; i<nbufs; i++) {
+ nread = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN,
+ off, (dm_ssize_t)CHUNKSIZE, filebuf);
+ if (nread != CHUNKSIZE) {
+ errno_msg("%s/%d: invis read err: got %d, expected %d, buf %d",
+ __FILE__, __LINE__,
+ nread, CHUNKSIZE, i);
+ retval = 1;
+ goto out;
+ }
+
+ nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, nread,
+ filebuf);
+ if (nwrite != nread) {
+ errno_msg("%s/%d: write error -got %d, expected %d, buf %d",
+ __FILE__, __LINE__,
+ nwrite, nread, i);
+ retval = 1;
+ goto out;
+ }
+ off += CHUNKSIZE;
+ }
+
+ lastbuf = fsize % CHUNKSIZE;
+ nread = dm_read_invis(sid, stg_hanp, stg_hlen, DM_NO_TOKEN, off,
+ (dm_ssize_t)lastbuf, filebuf);
+ if (nread != lastbuf) {
+ errno_msg("%s/%d: invis read error- got %d, expected %d, last buf",
+ __FILE__, __LINE__,
+ nread, lastbuf);
+ retval = 1;
+ goto out;
+ }
+
+ nwrite = dm_write_invis(sid, hanp, hlen, token, 0, off, lastbuf, filebuf);
+ if (nwrite != lastbuf) {
+ errno_msg("%s/%d: write error - got %d, expected %d, last buffer",
+ __FILE__, __LINE__,
+ nwrite, lastbuf);
+ retval = 1;
+ }
+out:
+ if (filebuf)
+ free(filebuf);
+ return(retval);
+}
+
+
+extern mode_t
+field_to_mode(
+ mode_t mode)
+{
+ switch (mode & S_IFMT) {
+
+ case S_IFBLK:
+ return(S_IFBLK);
+
+ case S_IFREG:
+ return(S_IFREG);
+
+ case S_IFDIR:
+ return(S_IFDIR);
+
+ case S_IFCHR:
+ return(S_IFCHR);
+
+ case S_IFIFO:
+ return(S_IFIFO);
+
+ case S_IFLNK:
+ return(S_IFLNK);
+
+ case S_IFSOCK:
+ return(S_IFSOCK);
+
+ default:
+ return(0);
+ }
+}
+
+
+extern int
+validate_state(
+ dm_stat_t *dmstat,
+ char *pathname,
+ int report_errors)
+{
+ struct stat statb;
+ int errors = 0;
+
+ /* Get the stat block for the file. */
+
+ if (lstat(pathname, &statb)) {
+ perror("stat failed");
+ exit(1);
+ }
+
+ /* Compare its fields against the dm_stat_t structure. */
+
+ if (dmstat->dt_dev != statb.st_dev) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_dev 0x%x, "
+ "statb.st_dev 0x%x\n", dmstat->dt_dev,
+ statb.st_dev);
+ }
+ errors++;
+ }
+ if (dmstat->dt_ino != statb.st_ino) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_ino %llx, "
+#if defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+ "statb.st_ino %llx\n",
+#else
+ "statb.st_ino %x\n",
+#endif
+ dmstat->dt_ino, statb.st_ino);
+ }
+ errors++;
+ }
+ if ((dmstat->dt_mode & S_IFMT) != field_to_mode(statb.st_mode)) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_mode (mode) %s, "
+ "statb.st_mode (mode) %s\n",
+ mode_to_string(dmstat->dt_mode),
+ mode_to_string(field_to_mode(statb.st_mode)));
+ }
+ errors++;
+ }
+ if ((dmstat->dt_mode & S_MASK) != (statb.st_mode & S_MASK)) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_mode (perm) 0%o, "
+ "statb.st_mode (perm) 0%o\n",
+ dmstat->dt_mode & S_MASK,
+ statb.st_mode & S_MASK);
+ }
+ errors++;
+ }
+ if (dmstat->dt_nlink != statb.st_nlink) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_nlink %d, "
+ "statb.st_nlink %d\n", dmstat->dt_nlink,
+ statb.st_nlink);
+ }
+ errors++;
+ }
+ if (dmstat->dt_uid != statb.st_uid) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_uid %d, "
+ "statb.st_uid %d\n", dmstat->dt_uid,
+ statb.st_uid);
+ }
+ errors++;
+ }
+ if (dmstat->dt_gid != statb.st_gid) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_gid %d, "
+ "statb.st_gid %d\n", dmstat->dt_gid,
+ statb.st_gid);
+ }
+ errors++;
+ }
+ if (dmstat->dt_rdev != statb.st_rdev) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_rdev 0x%x, "
+ "statb.st_rdev 0x%x\n", dmstat->dt_rdev,
+ statb.st_rdev);
+ }
+ errors++;
+ }
+ if (dmstat->dt_size != statb.st_size) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_size %lld, "
+#if defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+ "statb.st_size %lld\n",
+#else
+ "statb.st_size %d\n",
+#endif
+ dmstat->dt_size, statb.st_size);
+ }
+ errors++;
+ }
+ if (dmstat->dt_atime != statb.st_atime) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_atime %d, "
+ "statb.st_atime %d\n", dmstat->dt_atime,
+ statb.st_atime);
+ }
+ errors++;
+ }
+ if (dmstat->dt_mtime != statb.st_mtime) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_mtime %d, "
+ "statb.st_mtime %d\n", dmstat->dt_mtime,
+ statb.st_mtime);
+ }
+ errors++;
+ }
+ if (dmstat->dt_ctime != statb.st_ctime) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_ctime %d, "
+ "statb.st_ctime %d\n", dmstat->dt_ctime,
+ statb.st_ctime);
+ }
+ errors++;
+ }
+ if (dmstat->dt_dtime != statb.st_ctime) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_dtime %d, "
+ "statb.st_ctime %d\n", dmstat->dt_dtime,
+ statb.st_ctime);
+ }
+ errors++;
+ }
+ if (dmstat->dt_blksize != statb.st_blksize) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_blksize %d, "
+ "statb.st_blksize %d\n", dmstat->dt_blksize,
+ statb.st_blksize);
+ }
+ errors++;
+ }
+ if (dmstat->dt_blocks != statb.st_blocks) {
+ if (report_errors) {
+ fprintf(stdout, "ERROR:dmstat->dt_blocks %lld, "
+#if defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+ "statb.st_blocks %lld\n",
+#else
+ "statb.st_blocks %d\n",
+#endif
+ dmstat->dt_blocks, statb.st_blocks);
+ }
+ errors++;
+ }
+
+ if (errors && report_errors)
+ fprintf(stdout, "There were %d differences\n", errors);
+ return(errors);
+}
+
+
+extern char *
+date_to_string(
+ time_t timeval)
+{
+static char buffer[21];
+ char *tmstr;
+
+ if (timeval == (time_t)0) {
+ strcpy(buffer, "0");
+ } else {
+ tmstr = asctime(localtime(&timeval));
+ tmstr += 4;
+ strncpy(buffer, tmstr, 20);
+ buffer[20] = '\0';
+ }
+ return(buffer);
+}
+
+
+extern char *
+mode_to_string(
+ mode_t mode)
+{
+static char buffer[256];
+
+ switch (mode & S_IFMT) {
+
+ case S_IFBLK:
+ return("S_IFBLK");
+
+ case S_IFREG:
+ return("S_IFREG");
+
+ case S_IFDIR:
+ return("S_IFDIR");
+
+ case S_IFCHR:
+ return("S_IFCHR");
+
+ case S_IFIFO:
+ return("S_IFIFO");
+
+ case S_IFLNK:
+ return("S_IFLNK");
+
+ case S_IFSOCK:
+ return("S_IFSOCK");
+
+ default:
+ sprintf(buffer, "Invalid mode 0%o", mode & S_IFMT);
+ return(buffer);
+ }
+}
+
+
+extern char *
+emask_to_string(
+ dm_eventset_t emask)
+{
+static char buffer[256];
+ char *name;
+ int len = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (!DMEV_ISSET(i, emask))
+ continue;
+
+ switch (i) {
+ case DM_EVENT_CREATE:
+ name = "DM_EVENT_CREATE";
+ break;
+ case DM_EVENT_POSTCREATE:
+ name = "DM_EVENT_POSTCREATE";
+ break;
+ case DM_EVENT_REMOVE:
+ name = "DM_EVENT_REMOVE";
+ break;
+ case DM_EVENT_POSTREMOVE:
+ name = "DM_EVENT_POSTREMOVE";
+ break;
+ case DM_EVENT_RENAME:
+ name = "DM_EVENT_RENAME";
+ break;
+ case DM_EVENT_POSTRENAME:
+ name = "DM_EVENT_POSTRENAME";
+ break;
+ case DM_EVENT_LINK:
+ name = "DM_EVENT_LINK";
+ break;
+ case DM_EVENT_POSTLINK:
+ name = "DM_EVENT_POSTLINK";
+ break;
+ case DM_EVENT_SYMLINK:
+ name = "DM_EVENT_SYMLINK";
+ break;
+ case DM_EVENT_POSTSYMLINK:
+ name = "DM_EVENT_POSTSYMLINK";
+ break;
+ case DM_EVENT_READ:
+ name = "DM_EVENT_READ";
+ break;
+ case DM_EVENT_WRITE:
+ name = "DM_EVENT_WRITE";
+ break;
+ case DM_EVENT_TRUNCATE:
+ name = "DM_EVENT_TRUNCATE";
+ break;
+ case DM_EVENT_ATTRIBUTE:
+ name = "DM_EVENT_ATTRIBUTE";
+ break;
+ case DM_EVENT_DESTROY:
+ name = "DM_EVENT_DESTROY";
+ break;
+ default:
+ fprintf(stderr, "Unknown event type %d\n", i);
+ exit(1);
+ }
+ sprintf(buffer + len, "%c%s", (len ? '|' : '('), name);
+ len = strlen(buffer);
+ }
+
+ if (len == 0) {
+ sprintf(buffer, "(none)");
+ } else {
+ sprintf(buffer + len, ")");
+ }
+ return(buffer);
+}
+
+
+#if defined(__sgi) || defined(linux)
+
+extern char *
+xflags_to_string(
+ u_int xflags)
+{
+static char buffer[256];
+ int len = 0;
+
+ if (xflags & ~(DM_XFLAG_REALTIME|DM_XFLAG_PREALLOC|DM_XFLAG_HASATTR)) {
+ sprintf(buffer, "Invalid xflags 0%o", xflags);
+ return(buffer);
+ }
+
+ if (xflags & DM_XFLAG_REALTIME) {
+ sprintf(buffer + len, "%cREALTIME", (len ? '|' : '('));
+ len = strlen(buffer);
+ }
+ if (xflags & DM_XFLAG_PREALLOC) {
+ sprintf(buffer + len, "%cPREALLOC", (len ? '|' : '('));
+ len = strlen(buffer);
+ }
+ if (xflags & DM_XFLAG_HASATTR) {
+ sprintf(buffer + len, "%cHASATTR", (len ? '|' : '('));
+ len = strlen(buffer);
+ }
+ if (len == 0) {
+ sprintf(buffer, "(none)");
+ } else {
+ sprintf(buffer + len, ")");
+ }
+ return(buffer);
+}
+
+#endif
+
+
+extern void
+print_state(
+ dm_stat_t *dmstat)
+{
+ /* Print all the stat block fields. */
+
+ fprintf(stdout, "dt_dev 0x%x\n", dmstat->dt_dev);
+#ifdef __sgi
+ fprintf(stdout, "dt_ino %llx\n", dmstat->dt_ino);
+#else
+ fprintf(stdout, "dt_ino %x\n", dmstat->dt_ino);
+#endif
+ fprintf(stdout, "dt_mode (type) %s\n",
+ mode_to_string(dmstat->dt_mode));
+ fprintf(stdout, "dt_mode (perm) 0%o\n", dmstat->dt_mode & S_MASK);
+ fprintf(stdout, "dt_nlink %d\n", dmstat->dt_nlink);
+ fprintf(stdout, "dt_uid %d\n", dmstat->dt_uid);
+ fprintf(stdout, "dt_gid %d\n", dmstat->dt_gid);
+ fprintf(stdout, "dt_rdev 0x%x\n", dmstat->dt_rdev);
+#ifdef __sgi
+ fprintf(stdout, "dt_size %lld\n", dmstat->dt_size);
+#else
+ fprintf(stdout, "dt_size %d\n", dmstat->dt_size);
+#endif
+
+ fprintf(stdout, "dt_atime %s\n",
+ date_to_string(dmstat->dt_atime));
+ fprintf(stdout, "dt_mtime %s\n",
+ date_to_string(dmstat->dt_mtime));
+ fprintf(stdout, "dt_ctime %s\n",
+ date_to_string(dmstat->dt_ctime));
+
+ fprintf(stdout, "dt_blksize %d\n", dmstat->dt_blksize);
+#ifdef __sgi
+ fprintf(stdout, "dt_blocks %lld\n", dmstat->dt_blocks);
+#else
+ fprintf(stdout, "dt_blocks %d\n", dmstat->dt_blocks);
+#endif
+
+#if defined(__sgi) || defined(linux)
+ fprintf(stdout, "dt_xfs_igen %d\n", dmstat->dt_xfs_igen);
+ fprintf(stdout, "dt_xfs_xflags %s\n",
+ xflags_to_string(dmstat->dt_xfs_xflags));
+ fprintf(stdout, "dt_xfs_extsize %d\n", dmstat->dt_xfs_extsize);
+ fprintf(stdout, "dt_xfs_extents %d\n", dmstat->dt_xfs_extents);
+ fprintf(stdout, "dt_xfs_aextents %d\n", dmstat->dt_xfs_aextents);
+#endif
+
+ fputc('\n', stdout);
+
+ /* Print all other fields. */
+
+ fprintf(stdout, "emask %s\n",
+ emask_to_string(dmstat->dt_emask));
+ fprintf(stdout, "nevents %d\n", dmstat->dt_nevents);
+ fprintf(stdout, "pmanreg %d\n", dmstat->dt_pmanreg);
+ fprintf(stdout, "pers %d\n", dmstat->dt_pers);
+ fprintf(stdout, "dt_dtime %s\n",
+ date_to_string(dmstat->dt_dtime));
+ fprintf(stdout, "change %d\n", dmstat->dt_change);
+}
+
+
+extern void
+print_line(
+ dm_stat_t *dmstat)
+{
+ fprintf(stdout, "0x%x|", dmstat->dt_dev);
+#ifdef __sgi
+ fprintf(stdout, "%llx|", dmstat->dt_ino);
+#else
+ fprintf(stdout, "%x|", dmstat->dt_ino);
+#endif
+ fprintf(stdout, "%s|", mode_to_string(dmstat->dt_mode));
+ fprintf(stdout, "0%o|", dmstat->dt_mode & S_MASK);
+ fprintf(stdout, "%d|", dmstat->dt_nlink);
+ fprintf(stdout, "%d|", dmstat->dt_uid);
+ fprintf(stdout, "%d|", dmstat->dt_gid);
+ fprintf(stdout, "0x%x|", dmstat->dt_rdev);
+#ifdef __sgi
+ fprintf(stdout, "%lld|", dmstat->dt_size);
+#else
+ fprintf(stdout, "%d|", dmstat->dt_size);
+#endif
+
+ fprintf(stdout, "%s|", date_to_string(dmstat->dt_atime));
+ fprintf(stdout, "%s|", date_to_string(dmstat->dt_mtime));
+ fprintf(stdout, "%s|", date_to_string(dmstat->dt_ctime));
+
+ fprintf(stdout, "%d|", dmstat->dt_blksize);
+#ifdef __sgi
+ fprintf(stdout, "%lld|", dmstat->dt_blocks);
+#else
+ fprintf(stdout, "%d|", dmstat->dt_blocks);
+#endif
+
+#ifdef __sgi
+ fprintf(stdout, "%d|", dmstat->dt_xfs_igen);
+ fprintf(stdout, "%s|", xflags_to_string(dmstat->dt_xfs_xflags));
+ fprintf(stdout, "%d|", dmstat->dt_xfs_extsize);
+ fprintf(stdout, "%d|", dmstat->dt_xfs_extents);
+ fprintf(stdout, "%d|", dmstat->dt_xfs_aextents);
+#endif
+
+ /* Print all other fields. */
+
+ fprintf(stdout, "%s|", emask_to_string(dmstat->dt_emask));
+ fprintf(stdout, "%d|", dmstat->dt_nevents);
+ fprintf(stdout, "%d|", dmstat->dt_pmanreg);
+ fprintf(stdout, "%d|", dmstat->dt_pers);
+ fprintf(stdout, "%s|", date_to_string(dmstat->dt_dtime));
+ fprintf(stdout, "%d", dmstat->dt_change);
+
+ fputc('\n', stdout);
+}
--- /dev/null
+The files in this directory comprise a simple HSM example that uses
+the DMAPI. These files are distributed in the hope that they will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. These programs
+have been tested on an SGI platform (as of April 1995) and found
+to be suitably functional; however, there is no guarantee that they
+do, in fact, provide the functationality that is advertised. This
+is a long winded way of saying they probably have bugs; if you
+find 'em, fix 'em.
+
+Okay, now that we have the disclaimers out of the way, here are the details.
+
+ migfind
+ =======
+This will find all files of a specified size, and print out the handles.
+It is normally used like this:
+ migfind -s 800k /migfs >& cand_file
+
+This example will find all files greater than 800K in the /migfs filesystem,
+and put the handles (converted to ascii) in the file 'cand_file'. The output
+consists of three fields per line:
+ handle length filehandle file size in bytes
+
+ migout
+ ======
+migout reads a list of handles as created by migfind, and migrates
+the files data. The data is stored in files that are located in
+another directory. The usage is
+ migout /dmapi_fs/stagedir < cand_file
+
+This will all the files specified by handle in 'cand_file', and
+put their data in files located under the directory /dmapi_fs/stagedir'.
+The staging directory must be on a filesystem that supports
+the dmapi; the reason for this is to allow for a simplification
+in the code that stores the location of the data as a DM attribute
+(file handles are easier than path names).
+
+ migin
+ =====
+This daemon waits for DMAPI events and dispatches worker bees
+to actually stage the data in. The usage is:
+ migin -l dmapi_log /migfs
+migin will fork/exec a 'wbee' to either bring the data back from
+the staging directory, or to invalidate the file.
+
+
+Other programs:
+There are a couple of other programs in this directory.
+
+ mrmean
+ ======
+Simplist cleanup/debugging tool that will print information about
+the active sessions. If desired, it can also respond to outstanding
+events and destroy sessions that may have been left around from
+a process exiting unexpectedly.
+
+ mls
+ ===
+Simple ls type program to display information about a file, such
+as the managed region info, allocation info, event lists, and
+file handle.
+
--- /dev/null
+/*
+ * Simple utility to find all files above a certain size in
+ * a filesystem. The output is to stdout, and is of the form:
+ * filehandle length filehandle file size in bytes
+ *
+ * The list is not sorted in any way.
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include <lib/hsm.h>
+
+#define NUMLEN 16 /* arbitrary max len of input size */
+#define MAX_K (((u_int)LONG_MAX + 1) / 1024)
+#define MAX_M (((u_int)LONG_MAX + 1) / (1024*1024))
+
+
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+char *Progname;
+
+extern void print_victim(void *, size_t, dm_off_t);
+extern void err_msg(char *, ...);
+extern void errno_msg(char *, ...);
+
+int setup_dmapi(dm_sessid_t *);
+int scan_fs(dm_sessid_t, void *, size_t, dm_off_t);
+int verify_size(char *, dm_off_t *);
+void usage(char *);
+
+void
+usage(
+ char *prog)
+{
+ fprintf(stderr, "Usage: %s ", prog);
+ fprintf(stderr, " [-s file threshold]");
+ fprintf(stderr, " filesystem\n");
+}
+
+/*
+ * Convert an input string on the form 10m or 128K to something reasonable
+ */
+int
+verify_size(
+ char *str,
+ dm_off_t *sizep)
+{
+ char *cp;
+ dm_off_t size;
+
+ if (strlen(str) > NUMLEN) {
+ printf("Size %s is invalid \n", str);
+ return(1);
+ }
+
+ size = strtol(str,0,0);
+ if (size < 0 || size >= LONG_MAX ) {
+ printf("Size %d is invalid \n", size);
+ return(1);
+ }
+
+ cp = str;
+ while (isdigit(*cp))
+ cp++;
+ if (*cp == 'k' || *cp == 'K') {
+ if ( size >= (u_int) MAX_K) {
+#ifdef __sgi
+ printf("Size %lld is invalid\n", size);
+#else
+ printf("Size %ld is invalid\n", size);
+#endif
+ return(1);
+ }
+ size *= 1024;
+ } else if (*cp == 'm' || *cp == 'M') {
+ if ( size >= (u_int) MAX_M) {
+#ifdef __sgi
+ printf("Size %lld is invalid\n", size);
+#else
+ printf("Size %ld is invalid\n", size);
+#endif
+ return(1);
+ }
+ size *= (1024*1024);
+ }
+ *sizep = size;
+ return(0);
+}
+
+
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+
+ int c;
+ int error;
+ dm_off_t size;
+ char *fsname;
+ dm_sessid_t sid;
+ void *fs_hanp;
+ size_t fs_hlen;
+ char *sizep = "0";
+
+
+ Progname = argv[0];
+ size = 0;
+
+ while ((c = getopt(argc, argv, "s:")) != EOF) {
+ switch (c) {
+ case 's':
+ sizep = optarg;
+ break;
+
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (optind >= argc) {
+ usage(Progname);
+ exit(1);
+ }
+ /*
+ * Verify the input size string is legit
+ */
+ error = verify_size(sizep, &size);
+ if (error)
+ exit(1);
+
+ fsname = argv[optind];
+
+ /*
+ * Now we have our filesystem name and possibly a size threshold
+ * to look for. Init the dmapi, and get a filesystem handle so
+ * we can scan the filesystem
+ */
+ error = setup_dmapi(&sid);
+ if (error)
+ exit(1);
+
+ if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
+ errno_msg("Can't get filesystem handle");
+ exit(1);
+ }
+
+
+
+ /*
+ * Get the attributes of all files in the filesystem
+ */
+ error = scan_fs(sid, fs_hanp, fs_hlen, size);
+ if (error)
+ exit(1);
+
+
+ /*
+ * We're done, so we can shut down our session.
+ */
+ if (dm_destroy_session(sid) == -1) {
+ errno_msg("Can't close session");
+ exit(1);
+ }
+
+ return(0);
+
+}
+
+/*
+ * Get the attributes for all the files in a filesystem in bulk,
+ * and print out the handles and sizes of any that meet our target
+ * criteria.
+ *
+ * We are not interested in file names; if we were, then we would
+ * have to do a dm_get_dirattrs() on each directroy, then use
+ * dm_handle_to_path() to get the pathname.
+ */
+int
+scan_fs(
+ dm_sessid_t sid,
+ void *fs_hanp,
+ size_t fs_hlen,
+ dm_off_t target_size)
+{
+ u_int mask; /* attributes to scan for */
+ dm_stat_t *dm_statbuf, *sbuf; /* attributes buffer */
+ dm_attrloc_t locp; /* opaque location in fs */
+ size_t rlenp; /* ret length of stat info */
+ size_t buflen; /* length of stat buffer */
+ void *hanp; /* file handle */
+ size_t hlen; /* file handle */
+ int more; /* loop terminator */
+ int error;
+
+
+ /*
+ * Size the stat buffer to return info on 1K files at a time
+ */
+ buflen = sizeof(dm_stat_t) * 1024;
+#ifdef VERITAS_21
+ if (buflen > 65536)
+ buflen = 65536;
+#endif
+ dm_statbuf = (dm_stat_t *)calloc(1, buflen);
+ if (dm_statbuf == NULL) {
+ err_msg("Can't get memory for stat buffer");
+ return(1);
+ }
+
+
+ /*
+ * Initialize the offset opaque offset cookie that
+ * we use in successive calls to dm_get_bulkattr()
+ */
+ error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp);
+ if (error == -1) {
+ errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno);
+ free(dm_statbuf);
+ return(1);
+ }
+
+ /*
+ * Set our stat mask so that we'll only get the normal stat(2)
+ * info and the file's handle
+ */
+ mask = DM_AT_HANDLE | DM_AT_STAT;
+ do {
+ more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN,
+ mask, &locp, buflen, dm_statbuf, &rlenp);
+ if (more == -1) {
+ errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno);
+ break;
+ }
+
+ /*
+ * Walk through the stat buffer and pull out files
+ * that are of interest
+ *
+ * The stat buffer is variable length, so we must
+ * use the DM_STEP_TO_NEXT macro to access each individual
+ * dm_stat_t structure in the returned buffer.
+ */
+ sbuf = dm_statbuf;
+ while (sbuf != NULL) {
+ if (S_ISREG(sbuf->dt_mode) &&
+ sbuf->dt_size >= target_size) {
+ hanp = DM_GET_VALUE(sbuf, dt_handle, void *);
+ hlen = DM_GET_LEN(sbuf, dt_handle);
+
+ print_victim(hanp, hlen, sbuf->dt_size);
+ }
+ sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *);
+ }
+ } while (more == 1);
+
+ free(dm_statbuf);
+ if (more == -1)
+ return(1);
+
+ return(0);
+}
+
--- /dev/null
+/*
+ * Master migration daemon
+ *
+ * The master migration daemon waits for events on a file and
+ * spawns a child process to handle the event
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+
+#include <lib/hsm.h>
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+extern int errno;
+char *Progname;
+int Verbose;
+
+extern int setup_dmapi(dm_sessid_t *);
+extern void err_msg(char *, ...);
+extern void errno_msg(char *, ...);
+
+void event_loop(dm_sessid_t);
+int set_events(dm_sessid_t, void *, size_t);
+int mk_daemon(char *);
+void spawn_kid(dm_sessid_t, dm_token_t, char *);
+void migin_exit(void);
+void usage(char *);
+
+
+void
+usage(
+ char *prog)
+{
+ fprintf(stderr, "Usage: %s ", prog);
+ fprintf(stderr, " <-v verbose> ");
+ fprintf(stderr, " <-l logfile> ");
+ fprintf(stderr, "filesystem \n");
+}
+
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+
+ int c;
+ int error;
+ char *fsname, *logfile;
+ dm_sessid_t sid;
+ void *fs_hanp;
+ size_t fs_hlen;
+
+
+ Progname = argv[0];
+ fsname = NULL;
+ logfile = NULL;
+
+ while ((c = getopt(argc, argv, "vl:")) != EOF) {
+ switch (c) {
+ case 'v':
+ Verbose = 1;
+ break;
+ case 'l':
+ logfile = optarg;
+ break;
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (optind >= argc) {
+ usage(Progname);
+ exit(1);
+ }
+ fsname = argv[optind];
+ if (fsname == NULL) {
+ usage(Progname);
+ exit(1);
+ }
+ /*
+ * If no logfile name is specified, we'll just send
+ * all output to some file in /tmp
+ */
+ if (logfile == NULL)
+ logfile = LOG_DEFAULT;
+
+
+ /*
+ * Now we have our filesystem name and possibly a size threshold
+ * to look for. Init the dmapi, and get a filesystem handle so
+ * we can set up our events
+ */
+ error = setup_dmapi(&sid);
+ if (error)
+ exit(1);
+
+ if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) {
+ errno_msg("Can't get filesystem handle");
+ exit(1);
+ }
+
+ /*
+ * Turn ourselves into a daemon
+ */
+ error = mk_daemon(logfile);
+ if (error)
+ exit(1);
+
+
+ /*
+ * Set the event disposition so that our session will receive
+ * the managed region events (read, write, and truncate)
+ */
+ error = set_events(sid, fs_hanp, fs_hlen);
+ if (error)
+ exit(1);
+
+
+ /*
+ * Now wait forever for messages, spawning kids to
+ * do the actual work
+ */
+ event_loop(sid);
+ return(0);
+}
+
+/*
+ * Main event loop processing
+ */
+void
+event_loop(
+ dm_sessid_t sid)
+{
+ void *msgbuf;
+ size_t bufsize, rlen;
+ int error;
+ dm_eventmsg_t *msg;
+
+ /*
+ * We take a swag at a buffer size. If it's wrong, we can
+ * always resize it
+ */
+ bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN;
+ bufsize *= 16;
+ msgbuf = (void *)malloc(bufsize);
+ if (msgbuf == NULL) {
+ err_msg("Can't allocate memory for buffer");
+ goto out;
+ }
+
+ for (;;) {
+ error = dm_get_events(sid, ALL_AVAIL_MSGS, DM_EV_WAIT, bufsize,
+ msgbuf, &rlen);
+ if (error == -1) {
+ if (errno == E2BIG) {
+ free(msgbuf);
+ msgbuf = (void *)malloc(rlen);
+ if (msgbuf == NULL) {
+ err_msg("Can't resize msg buffer");
+ goto out;
+ }
+ continue;
+ }
+ errno_msg("Error getting events from DMAPI");
+ goto out;
+ }
+
+ /*
+ * Walk thru the message buffer, pull out each individual
+ * message, and dispatch the messages to child processes
+ * with the sid, token, and data. The children will
+ * respond to the events.
+ */
+ msg = (dm_eventmsg_t *)msgbuf;
+ while (msg != NULL ) {
+ if (Verbose) {
+ fprintf(stderr, "Received %s, token %d\n",
+ (msg->ev_type == DM_EVENT_READ ? "read" :
+ (msg->ev_type == DM_EVENT_WRITE ? "write" : "trunc")), msg->ev_token);
+ }
+ switch (msg->ev_type) {
+
+ case DM_EVENT_READ:
+ spawn_kid(sid, msg->ev_token, RESTORE_FILE);
+ break;
+
+ case DM_EVENT_WRITE:
+ case DM_EVENT_TRUNCATE:
+ spawn_kid(sid, msg->ev_token, INVAL_FILE);
+ break;
+
+ default:
+ err_msg("Invalid msg type %d\n", msg->ev_type);
+ break;
+ }
+ msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *);
+ }
+ }
+out:
+ if (msgbuf != NULL)
+ free(msgbuf);
+
+ migin_exit();
+}
+
+/*
+ * Fork and exec our worker bee to work on the file. If
+ * there is any error in fork/exec'ing the file, we have to
+ * supply the error return to the event. Once the child gets
+ * started, he/she/it will respond to the event for us.
+ */
+void
+spawn_kid(
+ dm_sessid_t sid,
+ dm_token_t token,
+ char *action)
+{
+ pid_t pid;
+ char sidbuf[sizeof(dm_sessid_t)];
+ char tokenbuf[sizeof(dm_token_t)];
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * We're in the child. Try and exec the worker bee
+ */
+ sprintf(sidbuf, "%d", sid);
+ sprintf(tokenbuf, "%d", token);
+ if (Verbose) {
+ fprintf(stderr, "execl(%s, %s, %s, -s, %s, -t, xs, 0)\n",
+ WORKER_BEE, WORKER_BEE, action, sidbuf, tokenbuf);
+ }
+ if (execl(WORKER_BEE, WORKER_BEE, action, "-s", sidbuf,
+ "-t", tokenbuf, NULL))
+ {
+ (void)dm_respond_event(sid, token, DM_RESP_ABORT,
+ errno, 0, 0);
+ exit(1);
+ }
+ }
+
+ if (pid < 0) {
+ err_msg("Can't fork worker bee");
+ (void)dm_respond_event(sid, token, DM_RESP_ABORT, errno,
+ 0, 0);
+ return;
+ }
+ return;
+
+}
+
+
+/*
+ * Set the event disposition of the managed region events
+ */
+int
+set_events(
+ dm_sessid_t sid,
+ void *fs_hanp,
+ size_t fs_hlen)
+{
+ dm_eventset_t eventlist;
+
+ DMEV_ZERO(eventlist);
+ DMEV_SET(DM_EVENT_READ, eventlist);
+ DMEV_SET(DM_EVENT_WRITE, eventlist);
+ DMEV_SET(DM_EVENT_TRUNCATE, eventlist);
+
+ if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &eventlist,
+ DM_EVENT_MAX) == -1)
+ {
+ errno_msg("Can't set event disposition");
+ return(1);
+ }
+ return(0);
+}
+
+
+
+
+/*
+ * Dissassociate ourselves from our tty, and close all files
+ */
+int
+mk_daemon(
+ char *logfile)
+{
+ int fd, pid;
+ int i;
+ struct rlimit lim;
+ struct sigaction act;
+
+#ifdef NOTYET
+ if ((pid = fork()) == -1)
+ return (-1);
+ if (pid)
+ exit(0);
+
+ (void) setsid();
+
+ (void) chdir("/");
+
+#endif /* NOTYET */
+ /*
+ * Determine how many open files we've got and close
+ * then all
+ */
+ if (getrlimit(RLIMIT_NOFILE, &lim) < 0 ) {
+ errno_msg("Can't determine max number of open files");
+ return(1);
+ }
+ for (i=0; i<lim.rlim_cur; i++)
+ (void)close(i);
+
+ /*
+ * For error reporting, we re-direct stdout and stderr to a
+ * logfile.
+ */
+ if ((fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0755)) < 0) {
+ errno_msg("Can't open logfile %s", logfile);
+ return(1);
+ }
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ close(fd);
+
+ /*
+ * Set up signals so that we can wait for spawned children
+ */
+ act.sa_handler = migin_exit;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+
+ (void)sigaction(SIGHUP, &act, NULL);
+ (void)sigaction(SIGINT, &act, NULL);
+ (void)sigaction(SIGQUIT, &act, NULL);
+ (void)sigaction(SIGTERM, &act, NULL);
+ (void)sigaction(SIGUSR1, &act, NULL);
+ (void)sigaction(SIGUSR1, &act, NULL);
+ (void)sigaction(SIGUSR2, &act, NULL);
+
+ return(0);
+}
+
+void
+migin_exit(void)
+{
+ dm_sessid_t *sidbuf, *sid;
+ void *infobuf;
+ char *cp;
+ u_int nsessions, nret;
+ int i, found, error;
+ size_t buflen, retlen;
+
+ sidbuf = NULL;
+ infobuf = NULL;
+
+ /*
+ * We could try and kill off all our kids, but we're not
+ * 'Mr. Mean', so we just wait for them to die.
+ */
+ err_msg("%s: waiting for all children to die...", Progname);
+ while (wait3((int *)0, WNOHANG, (struct rusage *)0) > 0)
+ ;
+
+ fprintf(stdout, "\n");
+
+ /*
+ * Now search for our session and try and shut it down. We
+ * could just as easily make the session ID a global, but
+ * this demonstrates how sessions can be queried
+ */
+ nsessions = 4;
+ sidbuf = (dm_sessid_t *)malloc(nsessions * sizeof(dm_sessid_t));
+ if (sidbuf == NULL) {
+ err_msg("Can't alloc mem to shut down session");
+ goto out;
+ }
+ error = dm_getall_sessions(nsessions, sidbuf, &nret);
+ if (error == -1) {
+ if (errno != E2BIG) {
+ errno_msg("Can't get list of active sessions");
+ goto out;
+ }
+ free(sidbuf);
+ nsessions = nret;
+ sidbuf = (dm_sessid_t *)malloc(nsessions * sizeof(dm_sessid_t));
+ if (sidbuf == NULL) {
+ err_msg("Can't alloc mem to shut down session");
+ goto out;
+ }
+ error = dm_getall_sessions(nsessions, sidbuf, &nret);
+ if (error == -1) {
+ errno_msg("Can't get list of active sessions");
+ goto out;
+ }
+ }
+
+ /*
+ * Now we have all the active sessions in our system.
+ * Query each one until we find ourselves.
+ */
+ sid = sidbuf;
+ buflen = DM_SESSION_INFO_LEN;
+ infobuf = malloc(buflen);
+ if (infobuf == NULL) {
+ err_msg("Can't alloc memory for session info buffer");
+ goto out;
+ }
+
+ /*
+ * When we registered our session, we just hammered the last component
+ * of the path name, so that's all we look for here. This prevents
+ * mismatches when running at ./migin or some other such foo
+ */
+ cp = strrchr(Progname, '/');
+ if (cp)
+ cp++;
+ else
+ cp = Progname;
+
+
+ found = 0;
+ for (i=0; i<nret; i++) {
+ error = dm_query_session(*sid, buflen, infobuf, &retlen);
+ if (error == -1)
+ continue; /* We just punt on errors */
+
+ if (strstr(infobuf, cp)) {
+ found = 1;
+ break;
+ }
+ sid++;
+ }
+
+ /*
+ * XXXX FIXME XXX
+ *
+ * Should do a set_disp to 0 and then drain the session
+ * queue as well. On the SGI, we'll need to make the
+ * filesystem handle global so that we can get at it
+ */
+
+ if (!found) {
+ err_msg("Can't find session to shut down");
+ goto out;
+ }
+ error = dm_destroy_session(*sid);
+ if (error == -1) {
+ errno_msg("Can't shut down session");
+ }
+
+
+out:
+ if (infobuf)
+ free(infobuf);
+ if (sidbuf)
+ free(sidbuf);
+
+ exit(0);
+}
+
--- /dev/null
+/*
+ * Simple utility to migrate a group of specified files.
+ * The unsorted input is from migfind, and is of the form:
+ * filehandle length filehandle file size
+ *
+ * The data for each file will be stored in another file located
+ * in a different directory. This 'staging directory' should be on
+ * another filesystem. The staging file will be named the same as
+ * the file handle. This simple-minded scheme suffices, since we're
+ * not interested in showing any media management in this example.
+ *
+ * ASSUMPTIONS:
+ * Persistent managed regions are supported
+ * Persistent DM attributes are supported
+ *
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <lib/hsm.h>
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+char *Progname;
+int Verbose;
+
+int mig_files(dm_sessid_t, char *);
+int mk_nonrez(dm_sessid_t, void *, size_t, dm_token_t, dm_off_t);
+int set_mrgns(dm_sessid_t, void *, size_t, dm_token_t, dm_off_t,
+ dm_off_t *);
+void clear_mrgns(dm_sessid_t, void *, dm_size_t, dm_token_t);
+int lock_file(dm_sessid_t, void *, size_t, dm_right_t, dm_token_t *);
+void unlock_file(dm_sessid_t, dm_token_t);
+int get_dmchange(dm_sessid_t, void *, size_t, dm_token_t, u_int *);
+int create_stgfile(char *, void *, size_t, char *, int *);
+int setup_dmapi(dm_sessid_t *);
+int save_filedata(dm_sessid_t, void *, size_t, int, dm_size_t);
+int extract_fields(char *, char *, size_t *, dm_size_t *);
+int save_dataloc(dm_sessid_t, void *, size_t, dm_token_t, char *);
+
+void usage(char *);
+
+void
+usage(
+ char *prog)
+{
+ fprintf(stderr, "Usage: %s ", prog);
+ fprintf(stderr, " <-v verbose> ");
+ fprintf(stderr, "<staging directory>\n");
+}
+
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+
+ int c;
+ int error;
+ char *stage_dir;
+ dm_sessid_t sid;
+
+
+ error = 0;
+ Progname = argv[0];
+ stage_dir = NULL;
+
+ while ((c = getopt(argc, argv, "v")) != EOF) {
+ switch (c) {
+ case 'v':
+ Verbose++;
+ break;
+
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (optind >= argc) {
+ usage(Progname);
+ exit(1);
+ }
+ stage_dir = argv[optind];
+ if (stage_dir == NULL) {
+ usage(Progname);
+ exit(1);
+ }
+
+ /*
+ * Init the dmapi, and get a session.
+ */
+ error = setup_dmapi(&sid);
+ if (error)
+ exit(1);
+
+ /*
+ * Migrate all the files given to us via stdin
+ */
+ error = mig_files(sid, stage_dir);
+
+
+ if (dm_destroy_session(sid))
+ errno_msg("Can't shut down session, line=%d, errno=%d", __LINE__, errno);
+
+ return(error);
+}
+
+/*
+ * Migrate all the files given in stdin
+ */
+
+int
+mig_files(
+ dm_sessid_t sid,
+ char *stage_dir)
+{
+ void *hanp;
+ size_t hlen;
+ dm_size_t fsize;
+ int error;
+ u_int change_start, change_end;
+ int stg_fd; /* staging file descriptor */
+ dm_off_t off; /* starting offset */
+ dm_token_t token; /* file token */
+ char ibuf[IBUFSIZE];
+ char handle_buf[HANDLE_LEN];
+ char stgpath[MAXPATHLEN];
+
+ /*
+ * Read all the lines in std input and migrate each file.
+ * This simple-minded migout does no batching, sorting, or
+ * anything else that a real HSM might do.
+ */
+ while (fgets(ibuf, IBUFSIZE, stdin) != NULL) {
+ error = extract_fields(ibuf, handle_buf, &hlen, &fsize);
+ if (error) {
+ err_msg("%s/%d: mangled input line, '%s' ", __FILE__, __LINE__, ibuf);
+ continue;
+ }
+ hanp = (void *)handle_buf;
+ if (Verbose) {
+ print_handle(hanp, hlen);
+ }
+
+ /*
+ * Create and open the file in the staging directory.
+ */
+ error = create_stgfile(stage_dir, hanp, hlen, stgpath, &stg_fd);
+ if (error)
+ continue;
+
+ /*
+ * Get the file's DMAPI change indicator so that we
+ * can tell if it changed (either via a data mod, or
+ * a DM attribute update) while we are staging it out
+ */
+ error = get_dmchange(sid, hanp, hlen, DM_NO_TOKEN,
+ &change_start);
+ if (error) {
+ close(stg_fd);
+ continue;
+ }
+
+ /*
+ * Write all the file's data to our file in the
+ * staging directory. In a real HSM, the data would
+ * be copied off to tertiary storage somewhere.
+ *
+ * The staging file descriptor will be closed for us
+ * in all cases.
+ */
+ error = save_filedata(sid, hanp, hlen, stg_fd, fsize);
+ if (error)
+ continue;
+
+
+ /*
+ * Get exclusive access to the file so we can blow
+ * away its data
+ */
+ error = lock_file(sid, hanp, hlen, DM_RIGHT_EXCL, &token);
+ if (error) {
+ err_msg("Can't get exclusive access to file, ignoring");
+ continue;
+ }
+
+ /*
+ * Make sure the file did not change
+ */
+ error = get_dmchange(sid, hanp, hlen, token, &change_end);
+ if (error) {
+ unlock_file(sid, token);
+ continue;
+ }
+ if (change_start != change_end) {
+ unlock_file(sid, token);
+ err_msg("File changed during stageout, ignoring");
+ continue;
+ }
+
+ /*
+ * Save the location of the data (the staging file)
+ * in a private DM attribute so that we can get the
+ * file back in the future
+ */
+ error = save_dataloc(sid, hanp, hlen, token, stgpath);
+ if (error) {
+ err_msg("Can't save location of file data");
+ unlock_file(sid, token);
+ continue;
+ }
+
+
+ /*
+ * Set up the managed regions on the file so that
+ * a foray past the fencepost will cause an event to
+ * be generated.
+ */
+ error = set_mrgns(sid, hanp, hlen, token, fsize, &off);
+ if (error) {
+ unlock_file(sid, token);
+ err_msg("Can't set managed regions");
+ continue;
+ }
+
+ /*
+ * Now we can safely blow away the data.
+ */
+ error = mk_nonrez(sid, hanp, hlen, token, off);
+ if (error) {
+ clear_mrgns(sid, hanp, hlen, token);
+ }
+
+ /*
+ * Unlock the file, which releases the token
+ */
+ unlock_file(sid, token);
+
+ }
+
+ return(0);
+}
+
+
+/*
+ * Remove the data for a file
+ */
+int
+mk_nonrez(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t off)
+{
+ int error;
+
+ error = dm_punch_hole(sid, hanp, hlen, token, off, 0);
+ if (error == -1) {
+ errno_msg("Can't punch hole in file, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * Set up the managed regions on a file. We try to leave some of the
+ * file resident; the actual amount left on-disk is dependent
+ * on the rounding enforced by the DMAPI implementation.
+ */
+int
+set_mrgns(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ dm_off_t fsize,
+ dm_off_t *start_off)
+{
+ dm_off_t rroff;
+ dm_size_t rlenp;
+ dm_region_t rgn;
+ u_int exact_flag;
+ int error;
+
+ if (fsize > FENCEPOST_SIZE) {
+ error = dm_probe_hole(sid, hanp, hlen, token, FENCEPOST_SIZE, 0,
+ &rroff, &rlenp);
+ if (error == -1) {
+ errno_msg("Can't probe hole in file, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ } else {
+ rroff = 0;
+ }
+ *start_off = rroff;
+
+ /*
+ * Now we know what the DMAPI and filesystem will support with
+ * respect to rounding of holes. We try to set our managed region
+ * to begin at this offset and continue to the end of the file.
+ * We set the event mask so that we'll trap on all events that
+ * occur in the managed region.
+ *
+ * Note that some implementations may not be able to support
+ * a managed region that starts someplace other than the beginning
+ * of the file. If we really cared, we could check the exact_flag.
+ */
+ rgn.rg_offset = rroff;
+ rgn.rg_size = 0;
+ rgn.rg_flags = DM_REGION_READ | DM_REGION_WRITE | DM_REGION_TRUNCATE;
+ error = dm_set_region(sid, hanp, hlen, token, 1, &rgn, &exact_flag);
+ if (error == -1) {
+ errno_msg("Can't set managed region, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * Clear a managed region on a file
+ */
+void
+clear_mrgns(
+ dm_sessid_t sid,
+ void *hanp,
+ dm_size_t hlen,
+ dm_token_t token)
+{
+ dm_region_t rgn;
+ u_int exact_flag;
+ int error;
+
+ rgn.rg_offset = 0;
+ rgn.rg_size = 0;
+ rgn.rg_flags = DM_REGION_NOEVENT;
+ error = dm_set_region(sid, hanp, hlen, token, 1, &rgn, &exact_flag);
+ if (error)
+ errno_msg("Can't clear managed regions from file, line=%d, errno=%d", __LINE__, errno);
+
+ return;
+}
+
+
+/*
+ * File rights are accessed via a token. The token must be associated
+ * with a synchronous event message. So, to obtain either shared or
+ * exclusive rights to a file, we first associate a token with a message,
+ * and then request our desired right
+ */
+int
+lock_file(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_right_t right,
+ dm_token_t *token)
+{
+ int error;
+
+ error = dm_create_userevent(sid, (size_t)0, (void *)0, token);
+ if (error == -1) {
+ errno_msg("Can't create user event for token context, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ error = dm_request_right(sid, hanp, hlen, *token, DM_RR_WAIT, right);
+ if (error == -1) {
+ errno_msg("Can't get requested right for token, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * Release the lock on a file
+ */
+void
+unlock_file(
+ dm_sessid_t sid,
+ dm_token_t token)
+{
+ int error;
+
+ error = dm_respond_event(sid, token, DM_RESP_CONTINUE, 0, 0, 0);
+ if (error == -1)
+ errno_msg("Can't respond to event and release token, line=%d, errno=%d", __LINE__, errno);
+
+ return;
+}
+
+
+int
+create_stgfile(
+ char *stage_dir,
+ void *hanp,
+ size_t hlen,
+ char *path,
+ int *stg_fd)
+{
+ char handle_str[HANDLE_STR];
+
+ if (hlen > HANDLE_LEN) {
+ err_msg("Handle length (%d) too long for file", hlen);
+ return(1);
+ }
+
+ strcpy(path, stage_dir);
+ strcat(path, "/");
+ hantoa(hanp, hlen, handle_str);
+
+ /*
+ * Concat the ascii representation of the file handle
+ * (which is two times longer than the binary version)
+ * onto the staging path name
+ */
+ strncat(path, (char *)handle_str, hlen*2);
+
+ if ( (*stg_fd = open(path, O_RDWR | O_CREAT, 0644)) < 0) {
+ errno_msg("Can't open file %s, line=%d, errno=%d\n", path, __LINE__, errno);
+ return(1);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Extract the three fields from the input line. THe input is of
+ * the form
+ * filehandle length filehandle file size
+ *
+ * The length of the file handle is expected to be less than 64 bytes.
+ */
+int
+extract_fields(
+ char *ibuf,
+ char *handle_buf,
+ size_t *hlen,
+ dm_size_t *fsize)
+{
+ char *cp, *start;
+ size_t len;
+ char *hanp;
+
+ /*
+ * Skip any leading white space, and check the length
+ * of the file handle
+ */
+ cp = ibuf;
+ while (!isalnum(*cp))
+ cp++;
+
+if( cp != ibuf )
+printf("%s/%d: found leading whitspace to skip\n", __FILE__, __LINE__);
+
+ start = cp;
+ while (isalnum(*cp))
+ cp++;
+ *cp = '\0';
+
+printf("%s/%d: start=(%s)\n", __FILE__, __LINE__, start);
+
+ len = strtol(start, 0, 0);
+ if (len > HANDLE_LEN) {
+ err_msg("%s/%d: Handle length %d too long in input line", __FILE__, __LINE__, len);
+ return(1);
+ }
+
+printf("%s/%d: len=%ld\n", __FILE__, __LINE__, len);
+
+ *hlen = len;
+
+ /*
+ * Skip over white space, and extract the file handle
+ */
+ while (!isalnum(*cp))
+ cp++;
+ hanp = cp;
+
+ /*
+ * Skip over the ascii length of the file handle, and
+ * then extract the file's length
+ */
+ cp += len*2;
+ *cp = '\0';
+
+printf("%s/%d: handle buf is (%s)\n", __FILE__, __LINE__, hanp );
+
+ atohan( hanp, (void**)&handle_buf, &len );
+
+printf("%s/%d: len now=%ld\n", __FILE__, __LINE__, len);
+
+
+ /* skip over white space */
+ while (!isalnum(*cp))
+ cp++;
+
+ /* read file length */
+ start = cp;
+ while (isalnum(*cp))
+ cp++;
+ *cp = '\0';
+
+printf("%s/%d: file len=%s\n", __FILE__, __LINE__, start);
+
+ *fsize = strtol(start, 0, 0);
+
+printf("%s/%d: fsize=%ld\n", __FILE__, __LINE__, *fsize);
+ return(0);
+
+}
+
+
+/*
+ * Save the location of the file's data so that we can find
+ * it again when we're staging the file back in. Rather than store
+ * the full pathname of the staging file, we just store the handle.
+ * This means the staging dir must be on a filesystem that supports
+ * the DMAPI.
+ */
+int
+save_dataloc(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ char *stgpath)
+{
+ void *stg_hanp;
+ size_t stg_hlen;
+ int error;
+ dm_attrname_t hanp_attrname;
+ dm_attrname_t hlen_attrname;
+
+ if (dm_path_to_handle(stgpath, &stg_hanp, &stg_hlen) == -1) {
+ errno_msg("Can't get handle for path %s, line=%d, errno=%d", stgpath, __LINE__, errno);
+ return(1);
+ }
+
+ /*
+ * Since handles are in two parts, they become two attributes.
+ * This can be useful, since we can extract the length
+ * separately when we stage the file back in
+ */
+ memcpy((void *)&hanp_attrname.an_chars[0], DLOC_HAN, DM_ATTR_NAME_SIZE);
+ error = dm_set_dmattr(sid, hanp, hlen, token, &hanp_attrname,
+ 0, stg_hlen, stg_hanp);
+ if (error == -1) {
+ errno_msg("Can't set DM attr of staging filehandle, line=%d, errno=%d",__LINE__, errno);
+ return(1);
+ }
+
+ memcpy((void *)&hlen_attrname.an_chars[0], DLOC_HANLEN, DM_ATTR_NAME_SIZE);
+ error = dm_set_dmattr(sid, hanp, hlen, token, &hlen_attrname,
+ 0, sizeof(stg_hlen), (void *)&stg_hlen);
+ if (error == -1) {
+ errno_msg("Can't set DM attr of staging filehandle length, line=%d, errno=%d", __LINE__, errno);
+ return(1);
+ }
+ return(0);
+}
--- /dev/null
+/*
+ * Simple util to print out DMAPI info about a file
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <lib/hsm.h>
+
+#define MAX_RGNS 8 /* Arbitrary for this release */
+#define NUM_EXTENTS 4
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+char *Progname;
+
+void usage(char *);
+int mr_info(dm_sessid_t, void *, size_t);
+int alloc_info(dm_sessid_t, void *, size_t);
+int event_info(dm_sessid_t, void *, size_t);
+int handle_info(dm_sessid_t, void *, size_t);
+
+extern int setup_dmapi(dm_sessid_t *);
+extern void errno_msg(char *, ...);
+extern void print_handle(void *, size_t);
+
+
+void
+usage(
+ char *prog)
+{
+ fprintf(stderr, "Usage: %s <options> filename \n ", prog);
+ fprintf(stderr, "\t-m managed region info\n");
+ fprintf(stderr, "\t-a allocation info\n");
+ fprintf(stderr, "\t-e event info\n");
+ fprintf(stderr, "\t-h handle\n");
+}
+
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+ int c;
+ int error;
+ int mr_flag, alloc_flag, handle_flag, event_flag;
+ void *hanp;
+ size_t hlen;
+ char *filename;
+ dm_sessid_t sid;
+
+
+ Progname = argv[0];
+ mr_flag = alloc_flag = handle_flag = event_flag = 0;
+
+ while ((c = getopt(argc, argv, "maeh")) != EOF) {
+ switch (c) {
+ case 'm':
+ mr_flag = 1;
+ break;
+ case 'a':
+ alloc_flag = 1;
+ break;
+ case 'e':
+ event_flag = 1;
+ break;
+ case 'h':
+ handle_flag = 1;
+ break;
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (optind >= argc) {
+ usage(Progname);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (filename == NULL) {
+ usage(Progname);
+ exit(1);
+ }
+
+
+ /*
+ * Set up our link to the DMAPI, and get a handle for
+ * the file we want to query
+ */
+ error = setup_dmapi(&sid);
+ if (error)
+ exit(1);
+
+ if (dm_path_to_handle(filename, &hanp, &hlen) == -1) {
+ printf("Can't get handle for path %s", filename);
+ error = 1;
+ goto out;
+ }
+
+ printf("File %s:\n", filename);
+ if (mr_flag) {
+ error = mr_info(sid, hanp, hlen);
+ if (error) {
+ error = 1;
+ goto out;
+ }
+ }
+ if (alloc_flag) {
+ error = alloc_info(sid, hanp, hlen);
+ if (error) {
+ error = 1;
+ goto out;
+ }
+ }
+ if (event_flag) {
+ error = event_info(sid, hanp, hlen);
+ if (error) {
+ error = 1;
+ goto out;
+ }
+ }
+ if (handle_flag) {
+ error = handle_info(sid, hanp, hlen);
+ if (error) {
+ error = 1;
+ goto out;
+ }
+ }
+
+out:
+ if (dm_destroy_session(sid)) {
+ errno_msg("Can't shut down session");
+ error = 1;
+ }
+
+ return(error);
+}
+
+/*
+ * Get the complete list of all managed regions for a file. For now,
+ * we know that most implementations only support a small number of
+ * regions, so we don't handle the E2BIG error here.
+ */
+int
+mr_info(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen)
+{
+ u_int i;
+ u_int ret;
+ dm_region_t rgn[MAX_RGNS];
+
+ memset((char *)&rgn, 0, (sizeof(dm_region_t) * MAX_RGNS));
+ if (dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, MAX_RGNS, rgn, &ret)) {
+ errno_msg("Can't get list of managed regions");
+ return(1);
+ }
+ printf("\n");
+ for (i=0; i<ret; i++) {
+ printf("\tRegion %d:\n", i);
+#ifdef __sgi
+ printf("\t\toffset %lld, ", rgn[i].rg_offset);
+ printf("size %lld, ", rgn[i].rg_size);
+#else
+ printf("\t\toffset %ld, ", rgn[i].rg_offset);
+ printf("size %ld, ", rgn[i].rg_size);
+#endif
+ printf("flags 0x%x", rgn[i].rg_flags);
+ printf(" ( ");
+ if (rgn[i].rg_flags & DM_REGION_NOEVENT)
+ printf("noevent ");
+ if (rgn[i].rg_flags & DM_REGION_READ)
+ printf("read ");
+ if (rgn[i].rg_flags & DM_REGION_WRITE)
+ printf("write ");
+ if (rgn[i].rg_flags & DM_REGION_TRUNCATE)
+ printf("trunc ");
+ printf(" )\n");
+ }
+ return(0);
+}
+
+/*
+ * Get the complete list of events for a file.
+ */
+int
+event_info(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen)
+{
+ u_int i;
+ u_int ret;
+ dm_eventset_t eventlist;
+
+ DMEV_ZERO(eventlist);
+ if (dm_get_eventlist(sid, hanp, hlen, DM_NO_TOKEN, DM_EVENT_MAX,
+ &eventlist, &ret)) {
+ errno_msg("Can't get list of events");
+ return(1);
+ }
+ printf("\n\tEvent list: \n\t\t");
+ if (DMEV_ISSET(DM_EVENT_MOUNT, eventlist))
+ printf("mount ");
+ if (DMEV_ISSET(DM_EVENT_PREUNMOUNT, eventlist))
+ printf("preunmount ");
+ if (DMEV_ISSET(DM_EVENT_UNMOUNT, eventlist))
+ printf("unmount ");
+ if (DMEV_ISSET(DM_EVENT_DEBUT, eventlist))
+ printf("debut ");
+ if (DMEV_ISSET(DM_EVENT_CREATE, eventlist))
+ printf("create ");
+ if (DMEV_ISSET(DM_EVENT_POSTCREATE, eventlist))
+ printf("postcreate ");
+ if (DMEV_ISSET(DM_EVENT_REMOVE, eventlist))
+ printf("remove ");
+ if (DMEV_ISSET(DM_EVENT_POSTREMOVE, eventlist))
+ printf("postmount ");
+ if (DMEV_ISSET(DM_EVENT_RENAME, eventlist))
+ printf("rename ");
+ if (DMEV_ISSET(DM_EVENT_POSTRENAME, eventlist))
+ printf("postrename ");
+ if (DMEV_ISSET(DM_EVENT_LINK, eventlist))
+ printf("link ");
+ if (DMEV_ISSET(DM_EVENT_POSTLINK, eventlist))
+ printf("postlink ");
+ if (DMEV_ISSET(DM_EVENT_SYMLINK, eventlist))
+ printf("symlink ");
+ if (DMEV_ISSET(DM_EVENT_POSTSYMLINK, eventlist))
+ printf("postsymlink ");
+ if (DMEV_ISSET(DM_EVENT_READ, eventlist))
+ printf("read ");
+ if (DMEV_ISSET(DM_EVENT_WRITE, eventlist))
+ printf("write ");
+ if (DMEV_ISSET(DM_EVENT_TRUNCATE, eventlist))
+ printf("truncate ");
+ if (DMEV_ISSET(DM_EVENT_ATTRIBUTE, eventlist))
+ printf("attribute ");
+ if (DMEV_ISSET(DM_EVENT_DESTROY, eventlist))
+ printf("destroy ");
+ if (DMEV_ISSET(DM_EVENT_NOSPACE, eventlist))
+ printf("nospace ");
+ if (DMEV_ISSET(DM_EVENT_USER, eventlist))
+ printf("user ");
+
+ printf("\n");
+ return(0);
+}
+
+/*
+ * Print out the handle for a file
+ */
+int
+handle_info(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen)
+{
+ printf("\n\tHandle (handle length, value) \n\t\t");
+ print_handle(hanp, hlen);
+ return(0);
+}
+
+/*
+ * Get the allocation info for a file. We pick some small number
+ * of extents to get the residency info on at one time
+ */
+int
+alloc_info(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen)
+{
+ int i, more;
+ dm_off_t offset;
+ u_int nextents, nret;
+ dm_extent_t ext[NUM_EXTENTS];
+
+
+ nextents = NUM_EXTENTS;
+ offset = 0;
+ printf("\n\tAllocation info \n");
+ do {
+ more = dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, &offset,
+ nextents, ext, &nret);
+ if (more == -1) {
+ errno_msg("Can't get alloc info for file");
+ return(1);
+ }
+ for (i=0; i<nret; i++) {
+ printf("\t\tExtent %d ", i);
+ if (ext[i].ex_type == DM_EXTENT_RES)
+ printf("(resident): ");
+ if (ext[i].ex_type == DM_EXTENT_HOLE)
+ printf("(hole): ");
+#ifdef __sgi
+ printf("offset %lld, ", ext[i].ex_offset);
+ printf("len %lld\n", ext[i].ex_length);
+#else
+ printf("offset %ld, ", ext[i].ex_offset);
+ printf("len %ld\n", ext[i].ex_length);
+#endif
+ }
+ } while (more == 1);
+ return(0);
+}
--- /dev/null
+/*
+ * Simple Mr. Mean that can manipulate and torch sessions
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+
+#include <lib/dmport.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+extern int errno;
+
+int Verbose;
+char *Progname;
+
+extern void err_msg(char *, ...);
+extern void errno_msg(char *, ...);
+
+int get_sessions(dm_sessid_t **, u_int *);
+int get_tokens(dm_sessid_t, dm_token_t **, u_int *);
+void print_session(dm_sessid_t);
+void print_tokens(dm_sessid_t);
+void kill_session(dm_sessid_t);
+
+void
+usage(char *s)
+{
+ fprintf(stderr, "Usage: %s <options>\n", s);
+ fprintf(stderr, "\t-t list tokens\n");
+ fprintf(stderr, "\t-l list sessions\n");
+ fprintf(stderr, "\t-k kill sessions\n");
+ fprintf(stderr, "\t-s <specific_sid>\n");
+ fprintf(stderr, "\t-v verbose (for kill)\n");
+}
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+ int c;
+ int error;
+ u_int i, nsids;
+ int list_flag, kill_flag, token_flag, sid_flag;
+ dm_sessid_t *sidbuf, *sidp, onesid;
+ char *cp;
+
+
+ Progname = argv[0];
+ list_flag = sid_flag = kill_flag = token_flag = 0;
+
+ while ((c = getopt(argc, argv, "vlkts:")) != EOF) {
+ switch (c) {
+ case 'l':
+ list_flag = 1;
+ break;
+ case 'k':
+ kill_flag = 1;
+ break;
+ case 't':
+ token_flag = 1;
+ break;
+ case 's':
+ if (sscanf(optarg, "%d", &onesid) <=0 ) {
+ err_msg("Can't convert sid %s", optarg);
+ exit(2);
+ }
+ sid_flag = 1;
+ break;
+ case 'v':
+ Verbose = 1;
+ break;
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (!list_flag && !sid_flag && !kill_flag && !token_flag) {
+ usage(Progname);
+ exit(1);
+ }
+
+ if (dm_init_service(&cp) == -1) {
+ err_msg("Can't init dmapi");
+ return(1);
+ }
+ if (strcmp(cp, DM_VER_STR_CONTENTS)) {
+ err_msg("Compiled for a different version");
+ return(1);
+ }
+
+
+ /*
+ * Get the list of all sessions in the system
+ */
+ error = get_sessions(&sidbuf, &nsids);
+ if (error)
+ exit(1);
+
+ /*
+ * Walk through the list of sessions do what is right
+ */
+ sidp = sidbuf;
+ for (i=0; i<nsids; i++, sidp++) {
+ if (sid_flag) {
+ /*
+ * If we're only looking for one sid, then
+ * we can skip this one if there's no match
+ */
+ if (onesid != *sidp)
+ continue;
+ }
+ if (list_flag)
+ print_session(*sidp);
+ if (token_flag)
+ print_tokens(*sidp);
+ if (kill_flag)
+ kill_session(*sidp);
+ }
+ return(0);
+}
+
+/*
+ * Print out info about a sessions
+ */
+void
+print_session(dm_sessid_t sid)
+{
+ char buf[DM_SESSION_INFO_LEN];
+ size_t ret;
+
+ if (dm_query_session(sid,DM_SESSION_INFO_LEN,(void *)buf, &ret) == -1) {
+ errno_msg("Can't get session info");
+ return;
+ }
+
+ printf("Session (%d) name: %s\n", sid, buf);
+ return;
+}
+
+/*
+ * Get all the tokens for a session
+ */
+void
+print_tokens(dm_sessid_t sid)
+{
+ dm_token_t *tbuf;
+ int error;
+ u_int i, ntokens;
+
+ error = get_tokens(sid, &tbuf, &ntokens);
+ if (error)
+ return;
+
+ printf("\tTokens (%d): ", ntokens);
+ for (i=0; i<ntokens; i++)
+ printf("%d ", *tbuf++);
+
+ printf("\n");
+
+ free(tbuf);
+ return;
+}
+
+/*
+ * Try and kill a session
+ */
+void
+kill_session(dm_sessid_t sid)
+{
+ dm_token_t *tbuf;
+ int error;
+ u_int i, ntokens;
+
+ /*
+ * Get all the tokens in the system so we can respond to them
+ */
+ error = get_tokens(sid, &tbuf, &ntokens);
+ if (error)
+ return;
+
+ if (ntokens && Verbose)
+ printf("\tResponding to events for sid %d, tokens: \n", sid);
+
+ for (i=0; i<ntokens; i++) {
+ if (Verbose)
+ printf("\t\t%d ", *tbuf);
+
+ if (dm_respond_event(sid, *tbuf, DM_RESP_ABORT, EIO, 0, NULL) == -1)
+ errno_msg("Can't respond to event, sid %d token %d",
+ sid, *tbuf);
+ tbuf++;
+ }
+
+ if (Verbose)
+ printf("\tDestroying session %d\n", sid);
+ if (dm_destroy_session(sid) == -1)
+ errno_msg("Can't shut down session %d", sid);
+ return;
+}
+
+int
+get_sessions(
+ dm_sessid_t **sidpp,
+ u_int *nsidp)
+{
+ dm_sessid_t *sidbuf;
+ int more, error;
+ u_int nsids, nret;
+
+ /*
+ * Pick an arbitrary number of sessions to get info for.
+ * If it's not enough, then we can always resize our buffer
+ */
+ error = 0;
+ nsids = 32;
+ sidbuf = malloc(nsids * sizeof(dm_sessid_t));
+ if (sidbuf == NULL) {
+ err_msg("Can't malloc memory");
+ error = 1;
+ goto out;
+ }
+
+ if (dm_getall_sessions(nsids, sidbuf, &nret) == -1) {
+ if (errno != E2BIG) {
+ errno_msg("Can't get list of sessions");
+ error = 1;
+ goto out;
+ }
+ free(sidbuf);
+ nsids = nret;
+ sidbuf = malloc(nsids * sizeof(dm_sessid_t));
+ if (sidbuf == NULL) {
+ err_msg("Can't malloc memory");
+ error = 1;
+ goto out;
+ }
+ if (dm_getall_sessions(nsids, sidbuf, &nret) == -1) {
+ if (error == -1) {
+ errno_msg("Can't get sessions with new buf");
+ error = 1;
+ goto out;
+ }
+ }
+ }
+out:
+ if (error && (sidbuf != NULL) )
+ free(sidbuf);
+ else {
+ *sidpp = sidbuf;
+ *nsidp = nret;
+ }
+
+ return(error);
+}
+
+
+/*
+ * Get all tokens in the session
+ */
+int
+get_tokens(
+ dm_sessid_t sid,
+ dm_token_t **bufpp,
+ u_int *nretp)
+{
+ dm_token_t *tbuf;
+ u_int ntokens, nret;
+ int error;
+
+ error = 0;
+ ntokens = 1024;
+ tbuf = (dm_token_t *)malloc(ntokens * sizeof(dm_token_t));
+ if (tbuf == NULL)
+ goto out;
+
+ if (dm_getall_tokens(sid, ntokens, tbuf, &nret) == -1) {
+ if (errno != E2BIG) {
+ errno_msg("Can't get all tokens");
+ goto out;
+ }
+ free(tbuf);
+ ntokens = nret;
+ tbuf = (dm_token_t *)malloc(ntokens * sizeof(dm_token_t));
+ if (tbuf == NULL)
+ goto out;
+
+ if (dm_getall_tokens(sid, ntokens, tbuf, &nret) == -1) {
+ errno_msg("Can't get all tokens");
+ goto out;
+ }
+ }
+out:
+ if (error && (tbuf != NULL))
+ free(tbuf);
+ else {
+ *bufpp = tbuf;
+ *nretp = nret;
+ }
+
+ return(error);
+}
--- /dev/null
+/*
+ * Worker bees.
+ *
+ * The bees perform the grunt work of handling a file event
+ *
+ * This code was written by Peter Lawthers, and placed in the public
+ * domain for use by DMAPI implementors and app writers.
+ *
+ * Standard disclaimer:
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <lib/hsm.h>
+
+extern char *optarg;
+extern int optind, optopt, opterr;
+extern int errno;
+char *Progname;
+int Verbose;
+
+extern int restore_filedata(dm_sessid_t, void *, size_t, dm_token_t,
+ void *, size_t, dm_off_t);
+extern int get_dmchange(dm_sessid_t, void *, size_t, dm_token_t, u_int *);
+extern int setup_dmapi(dm_sessid_t *);
+extern void err_msg(char *, ...);
+extern void errno_msg(char *, ...);
+
+int stagein_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *);
+int inval_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *);
+int check_lockstate(dm_sessid_t, void *, size_t, dm_token_t);
+int clear_mrgns(dm_sessid_t, void *, size_t, dm_token_t);
+int find_msg(dm_sessid_t, dm_token_t, dm_eventmsg_t **);
+int get_stghandle(dm_sessid_t, void *, size_t, dm_token_t, void **,
+ size_t *);
+void usage(char *);
+
+
+
+void
+usage(
+ char *prog)
+{
+ fprintf(stderr, "Usage: %s ", prog);
+ fprintf(stderr, " <-i invalidate file> ");
+ fprintf(stderr, " <-r restore file> ");
+ fprintf(stderr, "[-s sid] [-t token] \n");
+}
+
+
+int
+main(
+ int argc,
+ char *argv[])
+{
+
+ dm_eventmsg_t *msgheader;
+ char *sid_str, *token_str;
+ dm_sessid_t sid;
+ dm_token_t token;
+ int c;
+ int error;
+ int restore_flag, inval_flag;
+ char *cp;
+
+ Progname = argv[0];
+ sid_str = NULL;
+ token_str = NULL;
+ restore_flag = 0;
+ inval_flag = 0;
+
+ while ((c = getopt(argc, argv, "s:t:ri")) != EOF) {
+ switch (c) {
+ case 'r':
+ restore_flag++;
+ break;
+
+ case 'i':
+ inval_flag++;
+ break;
+
+ case 's':
+ sid_str = optarg;
+ break;
+
+ case 't':
+ token_str = optarg;
+ break;
+
+ case '?':
+ default:
+ usage(Progname);
+ exit(1);
+ }
+ }
+ if (optind < argc) {
+ usage(Progname);
+ exit(1);
+ }
+ if (sid_str == NULL || token_str == NULL) {
+ usage(Progname);
+ exit(1);
+ }
+ if ((restore_flag > 0) && (inval_flag > 0)) {
+ usage(Progname);
+ exit(1);
+ }
+
+ if (sscanf(sid_str, "%d", &sid) <= 0) {
+ err_msg("Can't convert sid");
+ exit(1);
+ }
+ if (sscanf(token_str, "%d", &token) <= 0) {
+ err_msg("Can't convert token");
+ exit(1);
+ }
+
+ /*
+ * Now we have our session and token. We just need to
+ * let the DMAPI know we exist so we can use the interface.
+ * We don't need to create a session since we'll be using
+ * the session of our parent.
+ */
+ error = dm_init_service(&cp);
+ if (error == -1) {
+ errno_msg("Can't init DMAPI");
+ exit(1);
+ }
+ if (strcmp(cp, DM_VER_STR_CONTENTS)) {
+ err_msg("Compiled for a different version");
+ exit(1);
+ }
+
+ /*
+ * Find the message our caller wants us to handle
+ */
+ error = find_msg(sid, token, &msgheader);
+ if (error)
+ exit(1);
+
+ /*
+ * Now service the particular event type
+ */
+ if (restore_flag)
+ error = stagein_file(sid, token, msgheader);
+ else
+ error = inval_file(sid, token, msgheader);
+
+ return(error);
+}
+
+
+/*
+ * Find the data event message that correponds to the token.
+ *
+ * RETURNS:
+ * A pointer to malloc'd memory that contains the message
+ * we're supposed to handle in the 'msgheader' param.
+ */
+int
+find_msg(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_eventmsg_t **msgheader)
+{
+ void *buf;
+ size_t buflen, rlen;
+ int error;
+
+ /*
+ * Malloc a buffer that we think is large enough for
+ * the common message header and the event specific part.
+ * If it's not large enough, we can always resize it.
+ */
+ buflen = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN;
+ buf = (void *)malloc(buflen);
+ if (buf == NULL) {
+ err_msg("Can't alloc memory for event buffer");
+ return(1);
+ }
+
+ error = dm_find_eventmsg(sid, token, buflen, buf, &rlen);
+ if (error == -1) {
+ if (errno != E2BIG) {
+ free(buf);
+ errno_msg("Can't obtain message from token");
+ return(1);
+ }
+ free(buf);
+ buflen = rlen;
+ buf = (void *)malloc(buflen);
+ if (buf == NULL) {
+ err_msg("Can't resize event buffer");
+ return(1);
+ }
+ error = dm_find_eventmsg(sid, token, buflen, buf, &rlen);
+ if (error == -1) {
+ errno_msg("Can't get message with resized buffer");
+ return(1);
+ }
+ }
+
+ *msgheader = (dm_eventmsg_t *)buf;
+ return(0);
+}
+
+
+/*
+ * Check the lock state associated with the file. If the token
+ * does not reference exclusive access, try to upgrade our lock.
+ * If we can't upgrade, drop the lock and start over
+ */
+int
+check_lockstate(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token)
+{
+ int error;
+ dm_right_t right;
+ u_int change_start, change_end;
+
+ error = dm_query_right(sid, hanp, hlen, token, &right);
+ if (error == -1) {
+ errno_msg("Can't query file access rights");
+ return(1);
+ }
+#ifdef __sgi
+ /*
+ * There are no access rights on the SGI. 1 means it's
+ * there.
+ */
+ if (right == DM_RIGHT_SHARED)
+ return 0;
+#endif
+
+ if (right != DM_RIGHT_EXCL) {
+ error = dm_request_right(sid, hanp, hlen, token, 0,
+ DM_RIGHT_EXCL);
+ if (error == -1) {
+ if (errno != EAGAIN) {
+ errno_msg("Can't upgrade lock");
+ return(1);
+ }
+ error = get_dmchange(sid, hanp, hlen, token,
+ &change_start);
+ if (error)
+ return(1);
+
+
+ error = dm_release_right(sid, hanp, hlen, token);
+ if (error == -1) {
+ errno_msg("Can't release file access rights");
+ return(1);
+ }
+ error = dm_request_right(sid, hanp, hlen, token,
+ DM_RR_WAIT, DM_RIGHT_EXCL);
+ if (error == -1) {
+ errno_msg("Can't get exclusive right to file");
+ return(1);
+ }
+
+ /*
+ * If the file changed while we slept, then someone
+ * must have modified the file
+ */
+ error = get_dmchange(sid, hanp, hlen, token,
+ &change_end);
+ if (error == -1)
+ return(1);
+
+ if (change_start != change_end) {
+ err_msg("File changed while waiting for lock");
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+
+
+/*
+ * Stage in the data for a file
+ */
+int
+stagein_file(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_eventmsg_t *msgheader)
+{
+
+ void *stg_hanp, *hanp;
+ size_t stg_hlen, hlen;
+ int error, ret_errno;
+ dm_response_t reply;
+ dm_data_event_t *msg;
+
+ /*
+ * Extract the event-specific info from the message header,
+ * then get the file handle.
+ */
+ msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *);
+ hanp = DM_GET_VALUE(msg, de_handle, void *);
+ hlen = DM_GET_LEN(msg, de_handle);
+
+ /*
+ * Check our permissions. We need exclusive access to the
+ * file to stage it back in.
+ */
+ error = check_lockstate(sid, hanp, hlen, token);
+ if (error)
+ goto out;
+
+ /*
+ * get the staging file handle from it's DM attributes
+ */
+ stg_hanp = NULL;
+ error = get_stghandle(sid, hanp, hlen, token, &stg_hanp, &stg_hlen);
+ if (error)
+ goto out;
+
+ /*
+ * We keep the exclusive lock held for the *entire* duration
+ * of the stagein. This is not required, but just quick and
+ * [sl]easy. For a large file, it is typically better to release
+ * the lock, and have a sliding window of managed regions to allow
+ * people to consume the data as it is being read in.
+ */
+ error = restore_filedata(sid, hanp, hlen, token, stg_hanp, stg_hlen,
+ msg->de_offset);
+ if (error)
+ goto out;
+
+ /*
+ * Now that the data is restored, and while we still have exclusive
+ * access to the file, clear the managed regions.
+ */
+ error = clear_mrgns(sid, hanp, hlen, token);
+ if (error)
+ goto out;
+
+out:
+ if (stg_hanp)
+ free((char *)stg_hanp);
+
+ /*
+ * Figure out what our response to the event will be. Once
+ * we've responded to the event, the token is no longer valid.
+ * On error, we pick the (less than helpful) errno EIO to signal
+ * to the user that something went wrong.
+ */
+ if (error) {
+ reply = DM_RESP_ABORT;
+ ret_errno = EIO;
+ } else {
+ reply = DM_RESP_CONTINUE;
+ ret_errno = 0;
+ }
+ (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0);
+
+ return(ret_errno);
+
+}
+
+/*
+ * Turn off event monitoring for a file. In a real HSM, we would
+ * probably want to either invalidate the file's data on
+ * tertiary storage, or start some aging process so that it will
+ * eventually go away.
+ *
+ * The assumption is that for write and truncate events, the file
+ * data is about to be invalidated.
+ */
+int
+inval_file(
+ dm_sessid_t sid,
+ dm_token_t token,
+ dm_eventmsg_t *msgheader)
+{
+ dm_data_event_t *msg;
+ void *hanp;
+ size_t hlen;
+ int error, ret_errno;
+ dm_response_t reply;
+
+ /*
+ * Extract the event-specific info from the message header,
+ * then get the file handle.
+ */
+ msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *);
+ hanp = DM_GET_VALUE(msg, de_handle, void *);
+ hlen = DM_GET_LEN(msg, de_handle);
+
+ /*
+ * Check our permissions. We need exclusive access to the
+ * file to clear our managed regions.
+ */
+ error = check_lockstate(sid, hanp, hlen, token);
+ if (error)
+ goto out;
+
+ /*
+ * Clear all the managed regions for the file.
+ */
+ error = clear_mrgns(sid, hanp, hlen, token);
+
+out:
+ /*
+ * Figure out what our response to the event will be. Once
+ * we've responded to the event, the token is no longer valid.
+ * On error, we pick the (less than helpful) errno EIO to signal
+ * to the user that something went wrong.
+ */
+ if (error) {
+ reply = DM_RESP_ABORT;
+ ret_errno = EIO;
+ } else {
+ reply = DM_RESP_CONTINUE;
+ ret_errno = 0;
+ }
+ (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0);
+
+ return(ret_errno);
+}
+
+/*
+ * Clear all of the managed regions for a file.
+ */
+int
+clear_mrgns(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token)
+{
+ dm_region_t *rgn;
+ u_int nregions, nret;
+ u_int exact_flag;
+ int i;
+ int error, retval;
+
+ /*
+ * We take a guess first and assume there is only one managed
+ * region per file. There should'nt be more than this, but
+ * it never hurts to check, since we want to make sure that
+ * all regions are turned off.
+ *
+ * The main purpose of this is to demonstrate the use of the
+ * E2BIG paradigm.
+ */
+ retval = 1;
+ nregions = 1;
+ rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t));
+ if (rgn == NULL) {
+ err_msg("Can't allocate memory for region buffers");
+ goto out;
+ }
+
+ error = dm_get_region(sid, hanp, hlen, token, nregions, rgn, &nret);
+ if (error == -1) {
+ if (errno != E2BIG) {
+ errno_msg("Can't get list of managed regions for file");
+ goto out;
+ }
+
+ /*
+ * Now we know how many managed regions there are, so we can
+ * resize our buffer
+ */
+ nregions = nret;
+ free(rgn);
+ rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t));
+ if (rgn == NULL) {
+ err_msg("Can't resize region buffers");
+ goto out;
+ }
+ error = dm_get_region(sid, hanp, hlen, token, nregions, rgn,
+ &nret);
+ if (error == -1) {
+ errno_msg("Can't get list of managed regions for file");
+ goto out;
+ }
+ }
+
+ /*
+ * Clear all the managed regions
+ */
+ for (i=0; i<nregions; i++) {
+ rgn->rg_offset = 0;
+ rgn->rg_size = 0;
+ rgn->rg_flags = DM_REGION_NOEVENT;
+ rgn++;
+ }
+ error = dm_set_region(sid, hanp, hlen, token, nregions, rgn,
+ &exact_flag);
+ if (error == -1) {
+ errno_msg("Can't clear list of managed regions for file");
+ }
+ retval = 0;
+
+out:
+ if (rgn != NULL)
+ free(rgn);
+
+ return(retval);
+}
+
+
+/*
+ * Extract the staging file handle from a file's DM attributes
+ */
+int
+get_stghandle(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ dm_token_t token,
+ void **stg_hanp,
+ size_t *stg_hlen)
+{
+ void *han_buf;
+ size_t han_len;
+ int error;
+ size_t rlen;
+ dm_attrname_t hanp_attrname;
+ dm_attrname_t hlen_attrname;
+
+ /*
+ * First get the length of the file handle, so we
+ * can size our buffer correctly
+ */
+ memcpy((void *)&hlen_attrname.an_chars[0], DLOC_HANLEN, DM_ATTR_NAME_SIZE);
+ error = dm_get_dmattr(sid, hanp, hlen, token, &hlen_attrname,
+ sizeof(size_t), &han_len, &rlen);
+ if (error == -1) {
+ /*
+ * On any error, even E2BIG, we bail since the size of
+ * the file handle should be a constant
+ */
+ errno_msg("Can't get size of staging file handle");
+ return(1);
+ }
+ if (rlen != sizeof(size_t)) {
+ err_msg("File handle length component incorrect");
+ return(1);
+ }
+
+ /*
+ * Malloc space for our staging file handle, and
+ * extract it from our DM attributes
+ */
+ han_buf = (void *)malloc(han_len);
+ if (han_buf == NULL) {
+ err_msg("Can't alloc memory for file handle");
+ return(1);
+ }
+
+ memcpy((void *)&hanp_attrname.an_chars[0], DLOC_HAN, DM_ATTR_NAME_SIZE);
+ error = dm_get_dmattr(sid, hanp, hlen, token, &hanp_attrname,
+ han_len, han_buf, &rlen);
+ if (error == -1) {
+ errno_msg("Can't get staging file handle");
+ free(han_buf);
+ return(1);
+ }
+ if (rlen != han_len) {
+ err_msg("File handle is incorrect length");
+ free(han_buf);
+ return(1);
+ }
+ *stg_hanp = han_buf;
+ *stg_hlen = han_len;
+ return(0);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ dm_sessid_t oldsid = DM_NO_SESSION;
+ dm_sessid_t newsid = 0;
+ char *sessinfo = "test1";
+ char *versionstr;
+
+ while( (c = getopt(argc, argv, "hs:i:")) != -1 ) {
+ switch(c){
+ case 's':
+ oldsid = atoi( optarg );
+ break;
+ case 'i':
+ sessinfo = optarg;
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s [-s oldsid] [-i sessinfo_txt]\n", argv[0]);
+ exit(2);
+ }
+ }
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_create_session( oldsid, sessinfo, &newsid);
+ printf( "ret=%d\n", ret );
+ printf( "newsid=%d\n", newsid );
+
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ dm_sessid_t sid = 0;
+ char *versionstr;
+
+ while( (c = getopt(argc, argv, "hs:")) != -1 ) {
+ switch(c){
+ case 's':
+ sid = atoi( optarg );
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s <-s sid>\n", argv[0] );
+ exit(2);
+ }
+ }
+
+ if( sid == 0 ){
+ fprintf(stderr, "%s: must specify -s\n", argv[0] );
+ exit(1);
+ }
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_destroy_session( sid );
+ printf( "ret=%d\n", ret );
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ dm_sessid_t sid = 0;
+ dm_token_t token = 0;
+ dm_eventmsg_t msg;
+ size_t rlen;
+ int buflen = sizeof(dm_eventmsg_t) + 100;
+ char *versionstr;
+
+ while( (c = getopt(argc, argv, "hs:t:l:q")) != -1 ) {
+ switch(c){
+ case 's':
+ sid = atoi( optarg );
+ break;
+ case 't':
+ token = atoi( optarg );
+ break;
+ case 'l':
+ buflen = atoi( optarg );
+ break;
+ case 'q':
+ printf("dm_eventmsg_t=%d\n", sizeof(dm_eventmsg_t) );
+ exit(0);
+ case 'h':
+ fprintf(stderr, "Usage: %s <-s sid> <-t token> [-l buflen]\n", argv[0]);
+ fprintf(stderr, " %s -q\n", argv[0]);
+ exit(2);
+ }
+ }
+
+ if( sid == 0 ){
+ fprintf(stderr, "%s: must specify -s\n", argv[0] );
+ exit(1);
+ }
+
+ if( token == 0 ){
+ fprintf(stderr, "%s: must specify -t\n", argv[0] );
+ exit(1);
+ }
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_find_eventmsg( sid, token, buflen, &msg, &rlen );
+ printf( "ret=%d\n", ret );
+ printf( "rlen=%d\n", rlen );
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <malloc.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ dm_sessid_t *sidbuf;
+ u_int nelem = 100;
+ u_int rnelem = 0;
+ int i;
+ char *versionstr;
+ int anyway = 0; /* attempt to show this many elements anyway,
+ * even if it looks like nothing was returned.
+ */
+
+ while( (c = getopt(argc, argv, "hn:x:")) != -1 ) {
+ switch(c){
+ case 'n':
+ nelem = atoi( optarg );
+ break;
+ case 'x':
+ anyway = atoi( optarg );
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s [-n nelem]\n", argv[0]);
+ exit(2);
+ }
+ }
+
+ if( (sidbuf = malloc( sizeof(*sidbuf) * nelem )) == NULL ){
+ fprintf(stderr, "%s: malloc failed\n", argv[0] );
+ exit(1);
+ }
+
+ memset( sidbuf, 0, sizeof(*sidbuf) * nelem );
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_getall_sessions( nelem, sidbuf, &rnelem );
+ printf( "ret=%d\n", ret );
+ printf( "rnelem=%d\n", rnelem );
+
+ /* user wants us to try to show a specific number of elements */
+ if( anyway > 0 )
+ rnelem = anyway;
+
+ printf("sids=\"");
+ for( i = 0; i < rnelem; i++ ){
+ printf("%d ", sidbuf[i]);
+ }
+ printf("\"\n");
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <malloc.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ dm_token_t *tokenbuf;
+ u_int nelem = 100;
+ u_int rnelem = 0;
+ dm_sessid_t sid = 0;
+ int i;
+ char *versionstr;
+
+ while( (c = getopt(argc, argv, "hs:n:")) != -1 ) {
+ switch(c){
+ case 's':
+ sid = atoi( optarg );
+ break;
+ case 'n':
+ nelem = atoi( optarg );
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s <-s sid> [-n nelem]\n", argv[0]);
+ exit(2);
+ }
+ }
+
+ if( sid == 0 ){
+ fprintf(stderr, "%s: must specify -s\n", argv[0] );
+ exit(1);
+ }
+
+ if( (tokenbuf = malloc( sizeof(dm_token_t) * nelem )) == NULL ){
+ fprintf(stderr, "%s: malloc failed\n", argv[0] );
+ exit(1);
+ }
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_getall_tokens( sid, nelem, tokenbuf, &rnelem );
+ printf( "ret=%d\n", ret );
+ printf( "rnelem=%d\n", rnelem );
+
+ printf("tokens=\"");
+ for( i = 0; i < rnelem; i++ ){
+ printf("%d ", tokenbuf+i);
+ }
+ printf("\"\n");
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/errno.h>
+#include <linux/dmapi_kern.h>
+
+main( int argc, char **argv )
+{
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int ret;
+ char *sessinfo;
+ size_t rlen = 0;
+ dm_sessid_t sid = 0;
+ int buflen = 100;
+ char *versionstr;
+
+ while( (c = getopt(argc, argv, "hs:l:")) != -1 ) {
+ switch(c){
+ case 's':
+ sid = atoi( optarg );
+ break;
+ case 'l':
+ buflen = atoi( optarg );
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s <-s sid> [-l buflen]\n", argv[0]);
+ exit(2);
+ }
+ }
+
+ if( sid == 0 ){
+ fprintf(stderr, "%s: must specify -s\n", argv[0] );
+ exit(1);
+ }
+
+ if( (sessinfo = malloc( sizeof(char*) * buflen )) == NULL ){
+ fprintf(stderr, "%s: malloc failed\n", argv[0] );
+ exit(1);
+ }
+
+ if( dm_init_service( &versionstr ) < 0 )
+ exit(1);
+
+ ret = dm_query_session( sid, buflen, sessinfo, &rlen );
+ printf( "ret=%d\n", ret );
+ printf( "rlen=%d\n", rlen );
+ if( ret != -1 )
+ printf( "sessinfo=%s\n", sessinfo );
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function create_userevent(). The
+command line is:
+
+ create_userevent [-s sid] string
+
+where string is the msgdata to be stored in the event.
+sid is the session ID to use for the event.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+static void
+usage(void)
+{
+ int i;
+
+ fprintf(stderr, "usage:\t%s [-s sid] string\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ char *string;
+ dm_token_t token;
+ char *name;
+ int opt;
+ int i;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "s:")) != EOF) {
+ switch (opt) {
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 1 != argc)
+ usage();
+ string = argv[optind++];
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ if (dm_create_userevent(sid, strlen(string)+ 1, string, &token)) {
+ fprintf(stderr, "dm_create_userevent failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ fprintf(stdout, "New token %d\n", token);
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test all the DMAPI functions in dm_handle.c. The
+command line is:
+
+ dm_handle pathname
+
+where pathname is the name of a file. If any function fails, an error message
+containing the work ERROR will be written to stderr.
+
+Tested DMAPI functions are:
+ dm_fd_to_handle
+ dm_handle_cmp
+ dm_handle_free
+ dm_handle_hash
+ dm_handle_is_valid
+ dm_handle_to_fshandle
+ dm_handle_to_fsid
+ dm_handle_to_ino
+ dm_handle_to_igen
+ dm_make_handle
+ dm_make_fshandle
+ dm_path_to_handle
+ dm_path_to_fshandle
+
+----------------------------------------------------------------------------*/
+
+
+char *Progname;
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage:\t%s pathname\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ char *pathname;
+ char *name;
+ void *hanp1, *hanp2, *hanp3, *fshanp1, *fshanp2, *fshanp3;
+ size_t hlen1, hlen2, hlen3, fshlen1, fshlen2, fshlen3;
+ u_int hash1, hash2, hash3, fshash1, fshash2, fshash3;
+ dm_fsid_t fsid;
+ dm_ino_t ino;
+ dm_igen_t igen;
+ char buffer[100];
+ char buffer1[100];
+ char fsbuffer1[100];
+ char buffer2[100];
+ char fsbuffer2[100];
+ char buffer3[100];
+ char fsbuffer3[100];
+ int fd;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s path\n", argv[0]);
+ exit(1);
+ }
+ pathname = argv[1];
+
+ (void)dm_init_service(&name);
+
+ if (dm_path_to_handle(pathname, &hanp1, &hlen1) != 0) {
+ fprintf(stderr, "dm_path_to_handle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hash1 = dm_handle_hash(hanp1, hlen1);
+ hantoa(hanp1, hlen1, buffer1);
+ fprintf(stdout, " han1: hash %u value %s (dm_path_to_handle)\n",
+ hash1, buffer1);
+ if (dm_handle_is_valid(hanp1, hlen1) == DM_FALSE) {
+ fprintf(stderr, "ERROR: han1 is not valid\n");
+ }
+
+ if (dm_path_to_fshandle(pathname, &fshanp1, &fshlen1) != 0) {
+ fprintf(stderr, "dm_path_to_fshandle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ fshash1 = dm_handle_hash(fshanp1, fshlen1);
+ hantoa(fshanp1, fshlen1, fsbuffer1);
+ fprintf(stdout, "fshan1: hash %u value %s (dm_path_to_fshandle\n",
+ fshash1, fsbuffer1);
+ if (dm_handle_is_valid(fshanp1, fshlen1) == DM_FALSE) {
+ fprintf(stderr, "ERROR: fshan1 is not valid\n");
+ }
+
+ if ((fd = open(pathname, O_RDONLY)) < 0) {
+ fprintf(stderr, "open of %s failed, %s\n", pathname,
+ strerror(errno));
+ exit(1);
+ }
+ if (dm_fd_to_handle(fd, &hanp2, &hlen2) != 0) {
+ fprintf(stderr, "dm_fd_to_handle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ (void)close(fd);
+ hash2 = dm_handle_hash(hanp2, hlen2);
+ hantoa(hanp2, hlen2, buffer2);
+ fprintf(stdout, " han2: hash %u value %s (dm_fd_to_handle)\n",
+ hash2, buffer2);
+ if (dm_handle_is_valid(hanp2, hlen2) == DM_FALSE) {
+ fprintf(stderr, "ERROR: han2 is not valid\n");
+ }
+
+ if (dm_handle_to_fshandle(hanp2, hlen2, &fshanp2, &fshlen2) != 0) {
+ fprintf(stderr, "dm_handle_to_fshandle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ fshash2 = dm_handle_hash(fshanp2, fshlen2);
+ hantoa(fshanp2, fshlen2, fsbuffer2);
+ fprintf(stdout, "fshan2: hash %u value %s (dm_handle_to_fshandle)\n",
+ fshash2, fsbuffer2);
+ if (dm_handle_is_valid(fshanp2, fshlen2) == DM_FALSE) {
+ fprintf(stderr, "ERROR: fshan2 is not valid\n");
+ }
+
+ if (dm_handle_cmp(hanp1, hlen1, hanp2, hlen2)) {
+ fprintf(stderr, "ERROR: han1 and han2 differ in dm_handle_cmp\n");
+ }
+ if (strcmp(buffer1, buffer2)) {
+ fprintf(stderr, "ERROR: han1 and han2 differ in strcmp\n");
+ }
+ if (hash1 != hash2) {
+ fprintf(stderr, "ERROR: hash1 and hash2 differ\n");
+ }
+
+ if (dm_handle_cmp(fshanp1, fshlen1, fshanp2, fshlen2)) {
+ fprintf(stderr, "ERROR: fshan1 and fshan2 differ in dm_handle_cmp\n");
+ }
+ if (strcmp(fsbuffer1, fsbuffer2)) {
+ fprintf(stderr, "ERROR: fshan1 and fshan2 differ in strcmp\n");
+ }
+ if (fshash1 != fshash2) {
+ fprintf(stderr, "ERROR: fshash1 and fshash2 differ\n");
+ }
+
+ /* Break the handle into its component parts and display them. Use
+ hantoa() instead of printing the parts directly because some are
+ 32 bits on Veritas and 64 bits on SGI.
+ */
+
+ if (dm_handle_to_fsid(hanp1, hlen1, &fsid) != 0) {
+ fprintf(stderr, "dm_handle_to_fsid failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hantoa(&fsid, sizeof(fsid), buffer);
+ fprintf(stdout, "fsid %s (dm_handle_to_fsid)\n", buffer);
+
+ if (dm_handle_to_ino(hanp1, hlen1, &ino) != 0) {
+ fprintf(stderr, "dm_handle_to_ino failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hantoa(&ino, sizeof(ino), buffer);
+ fprintf(stdout, "ino %s (dm_handle_to_ino)\n", buffer);
+
+ if (dm_handle_to_igen(hanp1, hlen1, &igen) != 0) {
+ fprintf(stderr, "dm_handle_to_igen failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hantoa(&igen, sizeof(igen), buffer);
+ fprintf(stdout, "igen %s (dm_handle_to_igen)\n", buffer);
+
+ /* Now use the parts to remake the handle and verify we get the same
+ answer.
+ */
+
+ if (dm_make_handle(&fsid, &ino, &igen, &hanp3, &hlen3) != 0) {
+ fprintf(stderr, "dm_make_handle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hash3 = dm_handle_hash(hanp3, hlen3);
+ hantoa(hanp3, hlen3, buffer3);
+ fprintf(stdout, " han3: hash %u value %s (dm_make_handle)\n",
+ hash3, buffer3);
+ if (dm_handle_is_valid(hanp3, hlen3) == DM_FALSE) {
+ fprintf(stderr, "ERROR: han3 is not valid\n");
+ }
+
+ if (dm_handle_cmp(hanp1, hlen1, hanp3, hlen3)) {
+ fprintf(stderr, "ERROR: hanp1 and hanp3 differ in dm_handle_cmp\n");
+ }
+ if (strcmp(buffer1, buffer3)) {
+ fprintf(stderr, "ERROR: hanp1 and hanp3 differ in strcmp\n");
+ }
+ if (hash1 != hash3) {
+ fprintf(stderr, "ERROR: hash1 and hash3 differ\n");
+ }
+
+ if (dm_make_fshandle(&fsid, &fshanp3, &fshlen3) != 0) {
+ fprintf(stderr, "dm_make_fshandle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ fshash3 = dm_handle_hash(fshanp3, fshlen3);
+ hantoa(fshanp3, fshlen3, fsbuffer3);
+ fprintf(stdout, "fshan3: hash %u value %s (dm_make_fshandle)\n",
+ fshash3, fsbuffer3);
+ if (dm_handle_is_valid(fshanp3, fshlen3) == DM_FALSE) {
+ fprintf(stderr, "ERROR: fshan3 is not valid\n");
+ }
+
+ if (dm_handle_cmp(fshanp1, fshlen1, fshanp3, fshlen3)) {
+ fprintf(stderr, "ERROR: fshan1 and fshan3 differ in dm_handle_cmp\n");
+ }
+ if (strcmp(fsbuffer1, fsbuffer3)) {
+ fprintf(stderr, "ERROR: fshan1 and fshan3 differ in strcmp\n");
+ }
+ if (fshash1 != fshash3) {
+ fprintf(stderr, "ERROR: fshash1 and fshash3 differ\n");
+ }
+
+ dm_handle_free(hanp1, hlen1);
+ dm_handle_free(hanp2, hlen2);
+ dm_handle_free(hanp3, hlen3);
+ dm_handle_free(fshanp1, fshlen1);
+ dm_handle_free(fshanp2, fshlen2);
+ dm_handle_free(fshanp3, fshlen3);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_downgrade_right(). The
+command line is:
+
+ downgrade_right {-F} [-s sid] token {pathname|handle}
+
+where:
+-F
+ when a pathname is specified, -F indicates that its filesystem handle
+ should be used rather than its file object handle.
+sid
+ is the dm_sessid_t to use rather than the default test session.
+token
+ is the dm_token_t to use.
+{pathname|handle}
+ is either a handle, or is the pathname of a file whose handle is
+ to be used.
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+
+char *Progname;
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n",
+ Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ dm_token_t token;
+ char *object;
+ void *hanp;
+ size_t hlen;
+ int Fflag = 0;
+ char *name;
+ int opt;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "Fs:")) != EOF) {
+ switch (opt) {
+ case 'F':
+ Fflag++;
+ break;
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 2 != argc)
+ usage();
+ token = atol(argv[optind++]);
+ object = argv[optind];
+
+ if (dm_init_service(&name) == -1) {
+ fprintf(stderr, "Can't inititalize the DMAPI\n");
+ exit(1);
+ }
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file or filesystem's handle. */
+
+ if (opaque_to_handle(object, &hanp, &hlen)) {
+ fprintf(stderr, "can't get handle from %s\n", object);
+ exit(1);
+ }
+ if (Fflag) {
+ void *fshanp;
+ size_t fshlen;
+
+ if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) {
+ fprintf(stderr, "can't get filesystem handle from %s\n",
+ object);
+ exit(1);
+ }
+ dm_handle_free(hanp, hlen);
+ hanp = fshanp;
+ hlen = fshlen;
+ }
+
+ if (dm_downgrade_right(sid, hanp, hlen, token)) {
+ fprintf(stderr, "dm_downgrade_right failed, %s\n",
+ strerror(errno));
+ return(1);
+ }
+
+ dm_handle_free(hanp, hlen);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+/* Given a file object's pathname, print the object's handle. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <lib/dmport.h>
+
+
+static void
+hantoa(
+ void *hanp,
+ size_t hlen,
+ char *handle_str)
+{
+ u_char *cp= (u_char *)hanp;
+ int i;
+
+ for (i = 0;i < hlen; i++, handle_str += 2)
+ sprintf(handle_str, "%.2x", *cp++);
+ *handle_str = '\0';
+}
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ char *name;
+ void *hanp;
+ size_t hlen;
+ char buffer[100];
+ int fd;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s path\n", argv[0]);
+ exit(1);
+ }
+
+ (void)dm_init_service(&name);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "open of %s failed, %s\n", argv[1],
+ strerror(errno));
+ exit(1);
+ }
+ if (dm_fd_to_handle(fd, &hanp, &hlen) != 0) {
+ fprintf(stderr, "dm_fd_to_handle failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ hantoa(hanp, hlen, buffer);
+
+ fprintf(stdout, "handle %s, path %s\n", buffer, argv[1]);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <lib/hsm.h>
+
+#ifdef linux
+#include <string.h>
+#endif
+
+/*---------------------------------------------------------------------------
+
+Test program used to test the DMAPI function dm_get_allocinfo(). The
+command line is:
+
+ get_allocinfo [-D] [-n nelem] [-o offp] [-s sid] pathname
+
+where pathname is the name of a file, 'offp' is a byte offset from the
+beginning of the file where you want to start dumping, and 'nelem' allows
+you to specify how many extent structures to use in each dm_get_allocinfo
+call.
+
+The code checks the returned extents as much as possible for errors.
+It detects bad ex_type values, verifies that there is always a trailing
+hole at the end of the file, that the ex_offset of each extent matches the
+ex_offset+ex_length of the previous extent, and that ex_offset+ex_length
+is always an even multiple of 512. It verifies that all ex_offset values
+after the first fall on a 512-byte boundary. It verifies that the '*offp'
+value returned by dm_get_allocinfo() is 0 at the end of the file, and
+equals ex_offset+ex_length of the last extent if not at the end of the file.
+Any error is reported to stderr, and the program then terminates with a
+non-zero exit status.
+
+The program produces output similar to xfs_bmap in order to make comparison
+easier. Here is some sample output.
+
+f1: offset 1
+ rc 0, nelemp 17
+ 0: [0..127]: resv [1..511]
+
+Line 1 gives the name of the file and the byte offset within the file where
+the dump started. Line 2 appears once for each dm_get_allocinfo() call,
+giving the return value (rc) and the number of extents which were returned.
+Line 3 is repeated once for each extent. The first field "0:" is the extent
+number. The second field "[0..127]:" give the starting and ending block for
+the extent in 512-byte units. The third field is either "resv" to indicate
+allocated space or "hole" if the extent is a hole. The fourth field
+"[1..511]" only appears if the dump did not start with byte zero of the
+first block. In that case, the first number shows the actual byte offset
+within the block (1 in this case). The second number should always be
+511 since we always dump to the end of a block.
+
+Possible tests
+--------------
+
+Dump some holey files and compare the output of this program with xfs_bmap.
+
+Produce a file with holes, and perform the following tests using just one
+extent (-e 1).
+ Dump extents from beginning of the file.
+ Dump from byte 1 of the file.
+ Dump from the last byte of the first extent.
+ Dump from the first byte of the second extent.
+ Dump from the middle of the second extent.
+ Dump the first byte of the last extent.
+ Dump the last byte of the last extent.
+ Dump the first byte after the last extent.
+ Dump starting at an offset way past the end of the file.
+
+Produce a fragmented file with many adjacent DM_EXTENT_RES extents.
+ Repeat the above tests.
+
+Produce a GRIO file with holes.
+ Repeat the above tests.
+
+Run the following shell script.
+
+#!/bin/ksh
+
+# Dump the same holey file $max times, each time using one less extent
+# structure than the previous time. The grep and diff code
+# checks to make sure that you get the same answer each time, no matter
+# how many extents you use. If all is okay, The only messages you will
+# see are the "trial $num" messages.
+
+max=20 # should be bigger than the number extents in the file
+
+num=$max
+while [ $num -gt 0 ]
+do
+ echo "trial $num"
+ ./test_alloc -e $num f1 | grep '\[' > x.$num
+ if [ $num -lt $max ]
+ then
+ diff x.$num x.$max
+ fi
+ num=`expr $num - 1`
+done
+
+----------------------------------------------------------------------------*/
+
+#ifndef linux
+extern char *sys_errlist[];
+#endif
+extern int optind;
+extern char *optarg;
+
+static int print_alloc(dm_sessid_t sid, void* hanp, size_t hlen,
+ char *pathname, dm_off_t startoff, u_int nelem);
+
+char *Progname;
+int Dflag = 0;
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage:\t%s [-D] [-n nelem] [-o off] [-s sid] "
+ "pathname\n", Progname);
+ exit(1);
+}
+
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ dm_sessid_t sid = DM_NO_SESSION;
+ dm_off_t startoff = 0; /* starting offset */
+ u_int nelem = 100;
+ char *pathname;
+ void *hanp;
+ size_t hlen;
+ dm_stat_t sbuf;
+ char *name;
+ int opt;
+
+ if (Progname = strrchr(argv[0], '/')) {
+ Progname++;
+ } else {
+ Progname = argv[0];
+ }
+
+ /* Crack and validate the command line options. */
+
+ while ((opt = getopt(argc, argv, "Dn:o:s:")) != EOF) {
+ switch(opt) {
+ case 'D':
+ Dflag++;
+ break;
+ case 'n':
+ nelem = atol(optarg);
+ break;
+ case 'o':
+ startoff = atoll(optarg);
+ break;
+ case 's':
+ sid = atol(optarg);
+ break;
+ case '?':
+ usage();
+ }
+ }
+ if (optind + 1 != argc)
+ usage();
+ pathname = argv[optind];
+
+ if (dm_init_service(&name)) {
+ fprintf(stderr, "dm_init_service failed, %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ if (sid == DM_NO_SESSION)
+ find_test_session(&sid);
+
+ /* Get the file's handle and verify that it is a regular file. */
+
+ if (dm_path_to_handle(pathname, &hanp, &hlen)) {
+ fprintf(stderr, "can't get handle for %s\n", pathname);
+ exit(1);
+ }
+ if (dm_get_fileattr(sid, hanp, hlen, DM_NO_TOKEN, DM_AT_STAT, &sbuf)) {
+ fprintf(stderr, "dm_get_fileattr failed\n");
+ exit(1);
+ }
+ if (!S_ISREG(sbuf.dt_mode)) {
+ fprintf(stderr, "%s is not a regular file\n", pathname);
+ exit(1);
+ }
+
+ /* Print the allocation. */
+
+ if (print_alloc(sid, hanp, hlen, pathname, startoff, nelem))
+ exit(1);
+
+ dm_handle_free(hanp, hlen);
+ exit(0);
+}
+
+
+static int
+print_alloc(
+ dm_sessid_t sid,
+ void *hanp,
+ size_t hlen,
+ char *pathname,
+ dm_off_t startoff,
+ u_int nelem)
+{
+ dm_off_t endoff;
+ dm_extent_t *extent;
+ u_int nelemp;
+ u_int num = 0;
+ u_int i;
+ char *type = NULL;
+ int rc;
+
+#ifdef __sgi
+ fprintf(stdout, "%s: starting offset %lld\n", pathname, startoff);
+#else
+ fprintf(stdout, "%s: starting offset %d\n", pathname, startoff);
+#endif
+
+ /* Allocate space for the number of extents requested by the user. */
+
+ if ((extent = malloc(nelem * sizeof(*extent))) == NULL) {
+ fprintf(stderr, "can't malloc extent structures\n");
+ return(1);
+ }
+
+ rc = 1;
+ endoff = startoff;
+
+ while (rc != 0) {
+ rc = dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, &startoff,
+ nelem, extent, &nelemp);
+
+ if (rc < 0) {
+ fprintf(stderr, "dm_get_allocinfo failed, %s\n",
+ strerror(errno));
+ return(1);
+ }
+
+ fprintf(stdout, "\treturned %d, nelemp %d\n", rc, nelemp);
+ if (Dflag && nelemp)
+ fprintf(stdout, " ex_type ex_offset ex_length\n");
+
+ /* Note: it is possible for nelemp to be zero! */
+
+ for (i = 0; i < nelemp; i++) {
+ /* The extent must either be reserved space or a hole.
+ */
+
+ switch (extent[i].ex_type) {
+ case DM_EXTENT_RES:
+ type = "resv";
+ break;
+ case DM_EXTENT_HOLE:
+ type = "hole";
+ break;
+ default:
+ fprintf(stderr, "invalid extent type %d\n",
+ extent[i].ex_type);
+ return(1);
+ }
+
+ if (!Dflag) {
+#if __sgi
+ fprintf(stdout, "\t%d: [%lld..%lld]: %s", num,
+#else
+ fprintf(stdout, "\t%d: [%d..%d]: %s", num,
+#endif
+ extent[i].ex_offset / 512,
+ (extent[i].ex_offset +
+ extent[i].ex_length - 1) / 512, type);
+ if ((extent[i].ex_offset % 512 != 0) ||
+ (endoff % 512 != 0)) {
+#if __sgi
+ fprintf(stdout, "\t[%lld..%lld]\n",
+#else
+ fprintf(stdout, "\t[%d..%d]\n",
+#endif
+ extent[i].ex_offset % 512,
+ (endoff-1) % 512);
+ } else {
+ fprintf(stdout, "\n");
+ }
+ } else {
+#ifdef __sgi
+ fprintf(stdout, "%5s %13lld %13lld\n",
+#else
+ fprintf(stdout, "%5s %13d %13d\n",
+#endif
+ type, extent[i].ex_offset,
+ extent[i].ex_length);
+ }
+
+ /* The ex_offset of the first extent should match the
+ 'startoff' specified by the caller. The ex_offset
+ in subsequent extents should always match
+ (ex_offset + ex_length) of the previous extent,
+ and should always start on a 512 byte boundary.
+ */
+
+ if (extent[i].ex_offset != endoff) {
+#ifdef __sgi
+ fprintf(stderr, "new extent (%lld)is not "
+ "adjacent to previous one (%lld)\n",
+#else
+ fprintf(stderr, "new extent (%d)is not "
+ "adjacent to previous one (%d)\n",
+#endif
+ extent[i].ex_offset, endoff);
+ return(1);
+ }
+ if (num && (extent[i].ex_offset % 512) != 0) {
+#ifdef __sgi
+ fprintf(stderr, "non-initial ex_offset (%lld) "
+#else
+ fprintf(stderr, "non-initial ex_offset (%d) "
+#endif
+ "is not a 512-byte multiple\n",
+ extent[i].ex_offset);
+ return(1);
+ }
+
+ /* Non-initial extents should have ex_length values
+ that are an even multiple of 512. The initial
+ extent should be a multiple of 512 less the offset
+ into the starting 512-byte block.
+ */
+
+ if (((extent[i].ex_offset % 512) + extent[i].ex_length) % 512 != 0) {
+ fprintf(stderr, "ex_length is incorrect based "
+ "upon the ex_offset\n");
+ return(1);
+ }
+
+ endoff = extent[i].ex_offset + extent[i].ex_length;
+ num++; /* count of extents printed */
+ }
+
+ /* If not yet at end of file, the startoff parameter should
+ match the ex_offset plus ex_length of the last extent
+ retrieved.
+ */
+
+ if (rc && startoff != endoff) {
+#ifdef __sgi
+ fprintf(stderr, "startoff is %lld, should be %lld\n",
+#else
+ fprintf(stderr, "startoff is %d, should be %d\n",
+#endif
+ startoff, endoff);
+ &nbs