Imported Upstream version 3.1.0
[debian/amanda] / ndmp-src / ndmos_common.c
diff --git a/ndmp-src/ndmos_common.c b/ndmp-src/ndmos_common.c
new file mode 100644 (file)
index 0000000..dfa6523
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1998,2001
+ *     Traakan, Inc., Los Altos, CA
+ *     All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+/*
+ * Project:  NDMJOB
+ * Ident:    $Id: $
+ *
+ * Description:
+ *     This contains code fragments common between the
+ *     O/S (Operating System) portions of NDMJOBLIB.
+ *
+ *     This file is #include'd by the O/S specific ndmos_*.c
+ *     file, and fragments are selected by #ifdef's.
+ *
+ *     There are four major portions:
+ *     1) Misc support routines: password check, local info, etc
+ *     2) Non-blocking I/O support routines
+ *     3) Tape interfacs ndmos_tape_xxx()
+ *     4) OS Specific NDMP request dispatcher which intercepts
+ *        requests implemented here, such as SCSI operations
+ *        and system configuration queries.
+ */
+
+
+
+
+/*
+ * CONFIG SUPPORT
+ ****************************************************************
+ */
+
+#ifdef NDMOS_COMMON_SYNC_CONFIG_INFO
+/*
+ * Get local info. Supports NDMPx_CONFIG_GET_HOST_INFO,
+ * NDMP3_CONFIG_GET_SERVER_INFO, and NDMPx_CONFIG_GET_SCSI_INFO.
+ */
+void
+ndmos_sync_config_info (struct ndm_session *sess)
+{
+       static struct utsname   unam;
+       static char             osbuf[100];
+       static char             idbuf[30];
+       static char             revbuf[50];
+       char                    obuf[5];
+
+       if (sess->config_info.hostname) {
+               /* already set */
+               return;
+       }
+
+       obuf[0] = (char)(NDMOS_ID >> 24);
+       obuf[1] = (char)(NDMOS_ID >> 16);
+       obuf[2] = (char)(NDMOS_ID >> 8);
+       obuf[3] = (char)(NDMOS_ID >> 0);
+       obuf[4] = 0;
+
+       uname (&unam);
+       sprintf (idbuf, "%lu", gethostid());
+       /*
+        * give CONTROL via NDMPv2 a chance to recognize this
+        * implementation (no ndmp2_config_get_server).
+        */
+       sprintf (osbuf, "%s (running %s from %s)",
+                       unam.sysname,
+                       NDMOS_CONST_PRODUCT_NAME,
+                       NDMOS_CONST_VENDOR_NAME);
+
+       sess->config_info.hostname = unam.nodename;
+       sess->config_info.os_type = osbuf;
+       sess->config_info.os_vers = unam.release;
+       sess->config_info.hostid = idbuf;
+
+       sess->config_info.vendor_name = NDMOS_CONST_VENDOR_NAME;
+       sess->config_info.product_name = NDMOS_CONST_PRODUCT_NAME;
+
+       sprintf (revbuf, "%s LIB:%d.%d/%s OS:%s (%s)",
+               NDMOS_CONST_PRODUCT_REVISION,
+               NDMJOBLIB_VERSION, NDMJOBLIB_RELEASE,
+               NDMOS_CONST_NDMJOBLIB_REVISION,
+               NDMOS_CONST_NDMOS_REVISION,
+               obuf);
+
+       sess->config_info.revision_number = revbuf;
+
+       /* best effort; note that this loads scsi and tape config */
+       ndmcfg_load (sess->param.config_file_name, &sess->config_info);
+}
+#endif /* NDMOS_COMMON_SYNC_CONFIG_INFO */
+
+
+
+
+/*
+ * AUTHENTICATION SUPPORT
+ ****************************************************************
+ */
+
+#ifdef NDMOS_COMMON_OK_NAME_PASSWORD
+/*
+ * Determine whether the clear-text account name and password
+ * are valid. Supports NDMPx_CONNECT_CLIENT_AUTH requests.
+ */
+int
+ndmos_ok_name_password (struct ndm_session *sess, char *name, char *pass)
+{
+       if (strcmp (name, "ndmp") != 0)
+               return 0;
+
+       if (strcmp (pass, "ndmp") != 0)
+               return 0;
+
+       return 1;       /* OK */
+}
+#endif /* NDMOS_COMMON_OK_NAME_PASSWORD */
+
+
+
+
+#ifdef NDMOS_COMMON_MD5
+/*
+ * MD5 authentication support
+ *
+ * See ndml_md5.c
+ */
+
+int
+ndmos_get_md5_challenge (struct ndm_session *sess)
+{
+       ndmmd5_generate_challenge (sess->md5_challenge);
+       sess->md5_challenge_valid = 1;
+       return 0;
+}
+
+int
+ndmos_ok_name_md5_digest (struct ndm_session *sess,
+  char *name, char digest[16])
+{
+       if (strcmp (name, "ndmp") != 0)
+               return 0;
+
+       if (!ndmmd5_ok_digest (sess->md5_challenge, "ndmp", digest))
+               return 0;
+
+       return 1;       /* OK */
+}
+#endif /* NDMOS_COMMON_MD5 */
+
+
+
+#ifdef NDMOS_COMMON_NONBLOCKING_IO_SUPPORT
+/*
+ * NON-BLOCKING I/O SUPPORT
+ ****************************************************************
+ * As support non-blocking I/O for NDMCHAN, condition different
+ * types of file descriptors to not block.
+ */
+
+void
+ndmos_condition_listen_socket (struct ndm_session *sess, int sock)
+{
+       int             flag;
+
+       flag = 1;
+       setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void*)&flag, sizeof flag);
+}
+
+void
+ndmos_condition_control_socket (struct ndm_session *sess, int sock)
+{
+       /* nothing */
+}
+
+void
+ndmos_condition_image_stream_socket (struct ndm_session *sess, int sock)
+{
+       fcntl (sock, F_SETFL, O_NONBLOCK);
+       signal (SIGPIPE, SIG_IGN);
+}
+
+void
+ndmos_condition_pipe_fd (struct ndm_session *sess, int fd)
+{
+       fcntl (fd, F_SETFL, O_NONBLOCK);
+       signal (SIGPIPE, SIG_IGN);
+}
+#endif /* NDMOS_COMMON_NONBLOCKING_IO_SUPPORT */
+
+
+
+
+#ifdef NDMOS_COMMON_TAPE_INTERFACE
+#ifndef NDMOS_OPTION_NO_TAPE_AGENT
+#ifndef NDMOS_OPTION_TAPE_SIMULATOR
+/*
+ * TAPE INTERFACE
+ ****************************************************************
+ * These interface to the O/S specific tape drivers and subsystem.
+ * They must result in functionality equivalent to the reference
+ * tape simulator. The NDMP TAPE model is demanding, and it is
+ * often necessary to workaround the native device driver(s)
+ * to achieve NDMP TAPE model conformance.
+ *
+ * It's easy to test this ndmos_tape_xxx() implementation
+ * using the ndmjob(1) command in test-tape conformance mode.
+ * The tape simulator passes this test. To test this implementation,
+ * rebuild ndmjob, then use this command:
+ *
+ *     ndmjob -o test-tape -T. -f /dev/whatever
+ *
+ * These ndmos_tape_xxx() interfaces must maintain the tape state
+ * (sess->tape_agent.tape_state). In particular, the position
+ * information (file_num and blockno) must be accurate at all
+ * times. A typical workaround is to maintain these here rather
+ * than relying on the native device drivers. Another workaround
+ * is to implement NDMP MTIO operations using repeated native MTIO
+ * operations with count=1, then interpret the results and errors
+ * to maintain accurate position and residual information.
+ *
+ * Workarounds in this implementation (please keep this updated):
+ *
+ */
+
+int
+ndmos_tape_initialize (struct ndm_session *sess)
+{
+       return -1;
+}
+
+void
+ndmos_tape_sync_state (struct ndm_session *sess)
+{
+       the_tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
+}
+
+ndmp9_error
+ndmos_tape_open (struct ndm_session *sess, char *name, int will_write)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_tape_close (struct ndm_session *sess)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_tape_write (struct ndm_session *sess, char *data,
+  unsigned long count, unsigned long * done_count)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_tape_read (struct ndm_session *sess, char *data,
+  unsigned long count, unsigned long * done_count)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_tape_mtio (struct ndm_session *sess, ndmp9_tape_mtio_op op,
+  unsigned long count, unsigned long * done_count)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_tape_execute_cdb (struct ndm_session *sess,
+  ndmp9_execute_cdb_request *request,
+  ndmp9_execute_cdb_reply *reply)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+#endif /* !NDMOS_OPTION_TAPE_SIMULATOR */
+#else /* !NDMOS_OPTION_NO_TAPE_AGENT */
+/* tape interfaces implemented in ndma_tape_simulator.c */
+#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
+#endif /* NDMOS_COMMON_TAPE_INTERFACE */
+
+
+#ifdef NDMOS_COMMON_ROBOT_INTERFACE
+#ifndef NDMOS_OPTION_NO_ROBOT_AGENT
+#ifndef NDMOS_OPTION_ROBOT_SIMULATOR
+
+/* ndmos_robot_* functions here */
+
+#endif /* !NDMOS_OPTION_ROBOT_SIMULATOR */
+#else /* !NDMOS_OPTION_NO_ROBOT_AGENT */
+/* robot interfaces implemented in ndma_robot_simulator.c */
+#endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
+#endif /* NDMOS_COMMON_ROBOT_INTERFACE */
+
+
+#ifdef NDMOS_COMMON_SCSI_INTERFACE
+#ifndef NDMOS_OPTION_NO_ROBOT_AGENT    /* Surrounds all SCSI intfs */
+#ifndef NDMOS_OPTION_ROBOT_SIMULATOR
+/*
+ * SCSI INTERFACE
+ ****************************************************************
+ */
+
+int
+ndmos_scsi_initialize (struct ndm_session *sess)
+{
+       return -1;
+}
+
+void
+ndmos_scsi_sync_state (struct ndm_session *sess)
+{
+       sess->robot_acb.scsi_state.error = NDMP9_DEV_NOT_OPEN_ERR;
+}
+
+ndmp9_error
+ndmos_scsi_open (struct ndm_session *sess, char *name)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_scsi_close (struct ndm_session *sess)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+/* deprecated */
+ndmp9_error
+ndmos_scsi_set_target (struct ndm_session *sess)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+
+ndmp9_error
+ndmos_scsi_reset_device (struct ndm_session *sess)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+/* deprecated */
+ndmp9_error
+ndmos_scsi_reset_bus (struct ndm_session *sess)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+ndmp9_error
+ndmos_scsi_execute_cdb (struct ndm_session *sess,
+  ndmp9_execute_cdb_request *request,
+  ndmp9_execute_cdb_reply *reply)
+{
+       return NDMP9_NOT_SUPPORTED_ERR;
+}
+
+#endif /* NDMOS_OPTION_ROBOT_SIMULATOR */
+#endif /* NDMOS_OPTION_NO_ROBOT_AGENT  Surrounds all SCSI intfs */
+#endif /* NDMOS_COMMON_SCSI_INTERFACE */
+
+
+
+
+#ifdef NDMOS_COMMON_DISPATCH_REQUEST
+/*
+ * ndmos_dispatch_request() -- O/S Specific Agent Dispatch Request (ADR)
+ ****************************************************************
+ * Some NDMP requests can only be handled as O/S specific portions,
+ * and are implemented here.
+ *
+ * The more generic NDMP requests may be re-implemented here rather
+ * than modifying the main body of code. Extensions to the NDMP protocol
+ * may also be implemented here. Neither is ever a good idea beyond
+ * experimentation. The structures in ndmagents.h provide for O/S
+ * specific extensions. Such extensions are #define'd in the ndmos_xxx.h.
+ *
+ * The return value from ndmos_dispatch_request() tells the main
+ * dispatcher, ndma_dispatch_request(), whether or not the request
+ * was intercepted. ndmos_dispatch_request() is called after basic
+ * reply setup is done (message headers and buffers), but before
+ * the request is interpretted.
+ */
+
+#ifndef I_HAVE_DISPATCH_REQUEST
+
+/*
+ * If we're not intercepting, keep it simple
+ */
+int
+ndmos_dispatch_request (struct ndm_session *sess,
+  struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
+{
+       return -1;      /* not intercepted */
+}
+
+#else /* !I_HAVE_DISPATCH_REQUEST */
+
+/*
+ * The following fragment is here for reference.
+ * If the O/S module intercepts requests, copy
+ * all this into the module source file and
+ * #undef NDMOS_COMMON_DISPATCH_REQUEST.
+ */
+
+extern struct ndm_dispatch_version_table ndmos_dispatch_version_table[];
+
+int
+ndmos_dispatch_request (struct ndm_session *sess,
+  struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
+{
+       struct ndm_dispatch_request_table *drt;
+       unsigned        protocol_version = ref_conn->protocol_version;
+       unsigned        msg = xa->request.header.message;
+       int             rc;
+
+       drt = ndma_drt_lookup (ndmos_dispatch_version_table,
+                                       protocol_version, msg);
+
+       if (!drt) {
+               return -1;      /* not intercepted */
+       }
+
+       /*
+        * Replicate the ndma_dispatch_request() permission checks
+        */
+       if (!sess->conn_open
+        && !(drt->flags & NDM_DRT_FLAG_OK_NOT_CONNECTED)) {
+               xa->reply.header.error = NDMP0_PERMISSION_ERR;
+               return 0;
+       }
+
+       if (!sess->conn_authorized
+        && !(drt->flags & NDM_DRT_FLAG_OK_NOT_AUTHORIZED)) {
+               xa->reply.header.error = NDMP9_NOT_AUTHORIZED_ERR;
+               return 0;
+       }
+
+       rc = (*drt->dispatch_request)(sess, xa, ref_conn);
+
+       if (rc < 0) {
+               xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
+       }
+
+       return 0;
+}
+
+
+
+
+/*
+ * Dispatch Version Table and Dispatch Request Tables (DVT/DRT)
+ ****************************************************************
+ */
+
+struct ndm_dispatch_request_table ndmos_dispatch_request_table_v0[] = {
+   {0}
+};
+
+#ifndef NDMOS_OPTION_NO_NDMP2
+struct ndm_dispatch_request_table ndmos_dispatch_request_table_v2[] = {
+   {0}
+};
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+
+#ifndef NDMOS_OPTION_NO_NDMP3
+struct ndm_dispatch_request_table ndmos_dispatch_request_table_v3[] = {
+   {0}
+};
+#endif /* !NDMOS_OPTION_NO_NDMP3 */
+
+#ifndef NDMOS_OPTION_NO_NDMP4
+struct ndm_dispatch_request_table ndmos_dispatch_request_table_v4[] = {
+   {0}
+};
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+
+
+struct ndm_dispatch_version_table ndmos_dispatch_version_table[] = {
+       { 0,            ndmos_dispatch_request_table_v0 },
+#ifndef NDMOS_OPTION_NO_NDMP2
+       { NDMP2VER,     ndmos_dispatch_request_table_v2 },
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+#ifndef NDMOS_OPTION_NO_NDMP3
+       { NDMP3VER,     ndmos_dispatch_request_table_v3 },
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+#ifndef NDMOS_OPTION_NO_NDMP4
+       { NDMP4VER,     ndmos_dispatch_request_table_v4 },
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+       { -1 }
+};
+#endif /* !I_HAVE_DISPATCH_REQUEST */
+#endif /* NDMOS_COMMON_DISPATCH_REQUEST */