+/*
+ * 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 */