--- /dev/null
+/*
+ * Copyright (c) 1998,1999,2000
+ * 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:
+ *
+ */
+
+
+#include "ndmagents.h"
+#include "wraplib.h"
+
+#ifndef NDMOS_OPTION_NO_DATA_AGENT
+
+
+
+/*
+ * Initialization and Cleanup
+ ****************************************************************
+ */
+
+/* Initialize -- Set data structure to know value, ignore current value */
+int
+ndmda_initialize (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ NDMOS_MACRO_ZEROFILL (da);
+ da->data_state.state = NDMP9_DATA_STATE_IDLE;
+ ndmchan_initialize (&da->formatter_error, "dfp-error");
+ ndmchan_initialize (&da->formatter_wrap, "dfp-wrap");
+ ndmchan_initialize (&da->formatter_image, "dfp-image");
+ ndmda_fh_initialize (sess);
+
+ return 0;
+}
+
+/* Commission -- Get agent ready. Entire session has been initialize()d */
+int
+ndmda_commission (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ da->data_state.state = NDMP9_DATA_STATE_IDLE;
+ ndmda_fh_commission (sess);
+
+ return 0;
+}
+
+/* Decommission -- Discard agent */
+int
+ndmda_decommission (struct ndm_session *sess)
+{
+ ndmis_data_close (sess);
+ ndmda_purge_environment (sess);
+ ndmda_purge_nlist (sess);
+ ndmda_fh_decommission (sess);
+ NDMOS_API_BZERO (sess->data_acb.bu_type,sizeof sess->data_acb.bu_type);
+
+ ndmda_commission (sess);
+
+ return 0;
+}
+
+/* Belay -- Cancel partially issued activation/start */
+int
+ndmda_belay (struct ndm_session *sess)
+{
+ ndmda_fh_belay (sess);
+ return ndmda_decommission (sess);
+}
+
+
+
+
+/*
+ * Semantic actions -- called from ndma_dispatch()
+ ****************************************************************
+ */
+
+static int
+add_env (struct ndm_env_table *envtab, char *cmd)
+{
+ char buf[1024];
+ int i;
+
+ for (i = 0; i < envtab->n_env; i++) {
+ strcpy (buf, envtab->env[i].name);
+ strcat (buf, "=");
+ strcat (buf, envtab->env[i].value);
+ ndmda_add_to_cmd (cmd, "-E");
+ ndmda_add_to_cmd (cmd, buf);
+ }
+
+ return 0;
+}
+
+static int
+add_nlist (struct ndm_nlist_table *nlisttab, char *cmd)
+{
+ char buf[32];
+ int i;
+
+ for (i = 0; i < nlisttab->n_nlist; i++) {
+ ndmp9_name * nl = &nlisttab->nlist[i];
+
+ ndmda_add_to_cmd (cmd, nl->original_path);
+ if (nl->fh_info.valid == NDMP9_VALIDITY_VALID) {
+ sprintf (buf, "@%llu", nl->fh_info.value);
+ ndmda_add_to_cmd (cmd, buf);
+ } else {
+ ndmda_add_to_cmd (cmd, "@-");
+ }
+ ndmda_add_to_cmd (cmd, nl->destination_path);
+ }
+
+ return 0;
+}
+
+
+ndmp9_error
+ndmda_data_start_backup (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ ndmp9_error error = NDMP9_NO_ERR;
+ char cmd[NDMDA_MAX_CMD];
+
+ strcpy (cmd, "wrap_");
+ strcat (cmd, da->bu_type);
+
+ if (sess->param.log_level > 0) {
+ char tmpbuf[40];
+ sprintf(tmpbuf, "-d%d", sess->param.log_level);
+ ndmda_add_to_cmd (cmd, tmpbuf);
+ }
+
+ ndmda_add_to_cmd (cmd, "-c");
+ ndmda_add_to_cmd (cmd, "-I#3");
+ add_env (&da->env_tab, cmd);
+
+ ndma_send_logmsg (sess, NDMP9_LOG_DEBUG, sess->plumb.data,
+ "CMD: %s", cmd);
+
+ if (ndmda_pipe_fork_exec (sess, cmd, 1) < 0) {
+ return NDMP9_UNDEFINED_ERR;
+ }
+
+ ndmis_data_start (sess, NDMCHAN_MODE_WRITE);
+
+ da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
+ da->data_state.operation = NDMP9_DATA_OP_BACKUP;
+
+ return error;
+}
+
+ndmp9_error
+ndmda_data_start_recover (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ ndmp9_error error = NDMP9_NO_ERR;
+ char cmd[NDMDA_MAX_CMD];
+
+ strcpy (cmd, "wrap_");
+ strcat (cmd, da->bu_type);
+
+ if (sess->param.log_level > 0) {
+ char tmpbuf[40];
+ sprintf(tmpbuf, "-d%d", sess->param.log_level);
+ ndmda_add_to_cmd (cmd, tmpbuf);
+ }
+
+ ndmda_add_to_cmd (cmd, "-x");
+ ndmda_add_to_cmd (cmd, "-I#3");
+ add_env (&da->env_tab, cmd);
+ add_nlist (&da->nlist_tab, cmd);
+
+ ndma_send_logmsg (sess, NDMP9_LOG_DEBUG, sess->plumb.data,
+ "CMD: %s", cmd);
+
+ if (ndmda_pipe_fork_exec (sess, cmd, 0) < 0) {
+ return NDMP9_UNDEFINED_ERR;
+ }
+
+ ndmis_data_start (sess, NDMCHAN_MODE_READ);
+
+ da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
+ da->data_state.operation = NDMP9_DATA_OP_RECOVER;
+
+ return error;
+}
+
+ndmp9_error
+ndmda_data_start_recover_fh (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ ndmp9_error error = NDMP9_NO_ERR;
+ char cmd[NDMDA_MAX_CMD];
+
+ strcpy (cmd, "wrap_");
+ strcat (cmd, da->bu_type);
+ ndmda_add_to_cmd (cmd, "-t");
+ ndmda_add_to_cmd (cmd, "-I#3");
+ add_env (&da->env_tab, cmd);
+ add_nlist (&da->nlist_tab, cmd);
+
+ ndma_send_logmsg (sess, NDMP9_LOG_DEBUG, sess->plumb.data,
+ "CMD: %s", cmd);
+
+ if (ndmda_pipe_fork_exec (sess, cmd, 0) < 0) {
+ return NDMP9_UNDEFINED_ERR;
+ }
+
+ ndmis_data_start (sess, NDMCHAN_MODE_READ);
+
+ da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
+ da->data_state.operation = NDMP9_DATA_OP_RECOVER_FILEHIST;
+
+ return error;
+}
+
+void
+ndmda_sync_state (struct ndm_session *sess)
+{
+ /* no-op, always accurate */
+}
+
+void
+ndmda_data_abort (struct ndm_session *sess)
+{
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_ABORTED);
+}
+
+void
+ndmda_sync_environment (struct ndm_session *sess)
+{
+ /* no-op, always accurate */
+}
+
+ndmp9_error
+ndmda_data_listen (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ da->data_state.state = NDMP9_DATA_STATE_LISTEN;
+ da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
+
+ return NDMP9_NO_ERR;
+}
+
+ndmp9_error
+ndmda_data_connect (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
+ da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
+
+ return NDMP9_NO_ERR;
+}
+
+void
+ndmda_data_halt (struct ndm_session *sess, ndmp9_data_halt_reason reason)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ da->data_state.state = NDMP9_DATA_STATE_HALTED;
+ da->data_state.halt_reason = reason;
+ da->data_notify_pending = 1;
+
+ ndmda_fh_flush (sess);
+
+ ndmis_data_close (sess);
+
+ ndmchan_cleanup (&da->formatter_image);
+ ndmchan_cleanup (&da->formatter_error);
+ ndmchan_cleanup (&da->formatter_wrap);
+
+ /* this needs to be better */
+ if (da->formatter_pid) {
+ sleep (1); /* give gtar a chance to stop by itself */
+ kill (da->formatter_pid, SIGTERM);
+ }
+}
+
+void
+ndmda_data_stop (struct ndm_session *sess)
+{
+ ndmda_decommission (sess);
+}
+
+
+
+
+/*
+ * Quantum -- get a bit of work done
+ ****************************************************************
+ */
+
+int
+ndmda_quantum (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int did_something = 0; /* did nothing */
+
+
+ switch (da->data_state.state) {
+ default:
+ ndmalogf (sess, 0, 0, "BOTCH data state");
+ return -1;
+
+ case NDMP9_DATA_STATE_IDLE:
+ case NDMP9_DATA_STATE_HALTED:
+ case NDMP9_DATA_STATE_CONNECTED:
+ break;
+
+ case NDMP9_DATA_STATE_LISTEN:
+ switch (sess->plumb.image_stream.data_ep.connect_status) {
+ case NDMIS_CONN_LISTEN: /* no connection yet */
+ break;
+
+ case NDMIS_CONN_ACCEPTED: /* we're in business */
+ /* drum roll please... */
+ da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
+ /* tah-dah */
+ did_something++; /* did something */
+ break;
+
+ case NDMIS_CONN_BOTCHED: /* accept() went south */
+ default: /* ain't suppose to happen */
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_CONNECT_ERROR);
+ did_something++; /* did something */
+ break;
+ }
+ break;
+
+ case NDMP9_DATA_STATE_ACTIVE:
+ did_something |= ndmda_quantum_stderr (sess);
+ did_something |= ndmda_quantum_wrap (sess);
+ did_something |= ndmda_quantum_image (sess);
+ break;
+ }
+
+ ndmda_send_notice (sess);
+
+ return did_something;
+}
+
+int
+ndmda_quantum_stderr (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ struct ndmchan * ch = &da->formatter_error;
+ int did_something = 0;
+ char * p;
+ char * data;
+ char * pend;
+ unsigned n_ready;
+
+ again:
+ n_ready = ndmchan_n_ready (ch);
+ if (n_ready == 0)
+ return did_something;
+
+ data = p = &ch->data[ch->beg_ix];
+ pend = p + n_ready;
+
+ while (p < pend && *p != '\n') p++;
+
+
+ if (p < pend && *p == '\n') {
+ *p++ = 0;
+ ndma_send_logmsg (sess, NDMP9_LOG_NORMAL, sess->plumb.data,
+ "%s", data);
+ ch->beg_ix += p - data;
+ did_something++;
+ goto again;
+ }
+
+ if (!ch->eof)
+ return did_something;
+
+ /* content w/o newline, and EOF */
+ /* p == pend */
+ if (ch->end_ix >= ch->data_size) {
+ if (data != ch->data) {
+ ndmchan_compress (ch);
+ goto again;
+ }
+ /* that's one huge message */
+ p--; /* lose last byte */
+ }
+
+ ch->data[ch->end_ix++] = '\n';
+ did_something++;
+ goto again;
+}
+
+int
+ndmda_quantum_wrap (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ struct ndmchan * ch = &da->formatter_wrap;
+ int did_something = 0;
+ char * p;
+ char * data;
+ char * pend;
+ unsigned n_ready;
+ int is_recover = 0;
+
+ switch (da->data_state.operation) {
+ default:
+ assert (0);
+ break;
+
+ case NDMP9_DATA_OP_BACKUP:
+ break;
+
+ case NDMP9_DATA_OP_RECOVER:
+ case NDMP9_DATA_OP_RECOVER_FILEHIST:
+ is_recover = 1;
+ break;
+ }
+
+ again:
+ n_ready = ndmchan_n_ready (ch);
+ if (n_ready == 0) {
+ if (ch->eof && is_recover) {
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_SUCCESSFUL);
+ }
+ return did_something;
+ }
+ data = p = &ch->data[ch->beg_ix];
+ pend = p + n_ready;
+
+ while (p < pend && *p != '\n') p++;
+
+
+ if (p < pend && *p == '\n') {
+ *p++ = 0;
+ ndmda_wrap_in (sess, data);
+ ch->beg_ix += p - data;
+ did_something++;
+ goto again;
+ }
+
+ if (!ch->eof)
+ return did_something;
+
+ /* content w/o newline, and EOF */
+ /* p == pend */
+ if (ch->end_ix >= ch->data_size) {
+ if (data != ch->data) {
+ ndmchan_compress (ch);
+ goto again;
+ }
+ /* that's one huge message */
+ p--; /* lose last byte */
+ }
+
+ ch->data[ch->end_ix++] = '\n';
+ did_something++;
+ goto again;
+}
+
+
+
+int
+ndmda_quantum_image (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ struct ndmchan * from_chan;
+ struct ndmchan * to_chan;
+ unsigned n_ready, n_avail, n_copy;
+ int is_backup = 0;
+
+ switch (da->data_state.operation) {
+ default:
+ assert (0);
+ from_chan = 0;
+ to_chan = 0;
+ break;
+
+ case NDMP9_DATA_OP_BACKUP:
+ from_chan = &da->formatter_image;
+ to_chan = &sess->plumb.image_stream.chan;
+ is_backup = 1;
+ break;
+
+ case NDMP9_DATA_OP_RECOVER:
+ case NDMP9_DATA_OP_RECOVER_FILEHIST:
+ from_chan = &sess->plumb.image_stream.chan;
+ to_chan = &da->formatter_image;
+ break;
+ }
+
+ again:
+ n_copy = n_ready = ndmchan_n_ready (from_chan);
+ if (n_ready == 0) {
+ if (from_chan->eof) {
+ to_chan->eof = 1;
+ if (ndmchan_n_ready (to_chan) == 0) {
+ if (is_backup) {
+ ndmda_data_halt (sess,
+ NDMP9_DATA_HALT_SUCCESSFUL);
+ }
+ }
+ }
+ return 0; /* data blocked */
+ }
+
+ n_avail = ndmchan_n_avail (to_chan);
+ if (n_copy > n_avail)
+ n_copy = n_avail;
+
+ if (da->enable_hist) {
+ if (n_copy > da->pass_resid)
+ n_copy = da->pass_resid;
+ }
+
+ if (n_copy > 0) {
+ bcopy (&from_chan->data[from_chan->beg_ix],
+ &to_chan->data[to_chan->end_ix],
+ n_copy);
+ from_chan->beg_ix += n_copy;
+ to_chan->end_ix += n_copy;
+ da->data_state.bytes_processed += n_copy;
+ da->pass_resid -= n_copy;
+ goto again; /* do as much as possible */
+ }
+
+ return 0;
+
+}
+
+
+
+
+/*
+ * Process WRAP messages from the formatter. Called from
+ * ndmda_quantum_wrap(). The formatter sends one line text
+ * messages via the WRAP pipe (fd=3 on formatter).
+ * The WRAP message contain log messages, file history,
+ * status updates, etc, etc, etc.
+ *
+ * Here the messages are parsed and directed to the
+ * right NDMP interface toward the Control Agent.
+ */
+
+void ndmp9_fstat_from_wrap_fstat (ndmp9_file_stat *fstat9,
+ struct wrap_fstat *fstatw);
+
+int
+ndmda_wrap_in (struct ndm_session *sess, char *wrap_line)
+{
+ struct wrap_msg_buf _wmsg, *wmsg = &_wmsg;
+ int rc;
+ ndmp9_file_stat fstat9;
+
+ NDMOS_MACRO_ZEROFILL (wmsg);
+
+ rc = wrap_parse_msg (wrap_line, wmsg);
+ if (rc != 0) {
+ ndmalogf (sess, 0, 2, "Malformed wrap: %s", wrap_line);
+ return -1;
+ }
+
+ switch (wmsg->msg_type) {
+ case WRAP_MSGTYPE_LOG_MESSAGE:
+ ndmalogf (sess, "WRAP", 2, "%s",
+ wmsg->body.log_message.message);
+ ndma_send_logmsg (sess, NDMP9_LOG_NORMAL, sess->plumb.data,
+ "WRAP: %s", wmsg->body.log_message.message);
+ break;
+
+ case WRAP_MSGTYPE_ADD_FILE:
+ ndmp9_fstat_from_wrap_fstat (&fstat9,
+ &wmsg->body.add_file.fstat);
+ fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
+ fstat9.fh_info.value = wmsg->body.add_file.fhinfo;
+ ndmda_fh_add_file (sess, &fstat9, wmsg->body.add_file.path);
+ break;
+
+ case WRAP_MSGTYPE_ADD_DIRENT:
+ ndmda_fh_add_dir (sess,
+ wmsg->body.add_dirent.dir_fileno,
+ wmsg->body.add_dirent.name,
+ wmsg->body.add_dirent.fileno);
+ break;
+
+ case WRAP_MSGTYPE_ADD_NODE:
+ ndmp9_fstat_from_wrap_fstat (&fstat9,
+ &wmsg->body.add_node.fstat);
+ fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
+ fstat9.fh_info.value = wmsg->body.add_node.fhinfo;
+ ndmda_fh_add_node (sess, &fstat9);
+ break;
+
+ case WRAP_MSGTYPE_DATA_READ:
+ ndmda_send_data_read (sess,
+ wmsg->body.data_read.offset,
+ wmsg->body.data_read.length);
+ break;
+
+ case WRAP_MSGTYPE_ADD_ENV:
+ case WRAP_MSGTYPE_DATA_STATS:
+ case WRAP_MSGTYPE_RECOVERY_RESULT:
+ ndmalogf (sess, 0, 2, "Unimplemented wrap: %s", wrap_line);
+ break;
+ }
+
+ return 0;
+}
+
+void
+ndmp9_fstat_from_wrap_fstat (ndmp9_file_stat *fstat9,
+ struct wrap_fstat *fstatw)
+{
+ NDMOS_MACRO_ZEROFILL (fstat9);
+
+ switch (fstatw->ftype) {
+ default:
+ case WRAP_FTYPE_INVALID:fstat9->ftype = NDMP9_FILE_OTHER; break;
+ case WRAP_FTYPE_DIR: fstat9->ftype = NDMP9_FILE_DIR; break;
+ case WRAP_FTYPE_FIFO: fstat9->ftype = NDMP9_FILE_FIFO; break;
+ case WRAP_FTYPE_CSPEC: fstat9->ftype = NDMP9_FILE_CSPEC; break;
+ case WRAP_FTYPE_BSPEC: fstat9->ftype = NDMP9_FILE_BSPEC; break;
+ case WRAP_FTYPE_REG: fstat9->ftype = NDMP9_FILE_REG; break;
+ case WRAP_FTYPE_SLINK: fstat9->ftype = NDMP9_FILE_SLINK; break;
+ case WRAP_FTYPE_SOCK: fstat9->ftype = NDMP9_FILE_SOCK; break;
+ case WRAP_FTYPE_REGISTRY:fstat9->ftype = NDMP9_FILE_REGISTRY; break;
+ case WRAP_FTYPE_OTHER: fstat9->ftype = NDMP9_FILE_OTHER; break;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_FTYPE) {
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_MODE) {
+ fstat9->mode.valid = NDMP9_VALIDITY_VALID;
+ fstat9->mode.value = fstatw->mode;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_SIZE) {
+ fstat9->size.valid = NDMP9_VALIDITY_VALID;
+ fstat9->size.value = fstatw->size;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_LINKS) {
+ fstat9->links.valid = NDMP9_VALIDITY_VALID;
+ fstat9->links.value = fstatw->size;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_UID) {
+ fstat9->uid.valid = NDMP9_VALIDITY_VALID;
+ fstat9->uid.value = fstatw->uid;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_GID) {
+ fstat9->gid.valid = NDMP9_VALIDITY_VALID;
+ fstat9->gid.value = fstatw->gid;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_ATIME) {
+ fstat9->atime.valid = NDMP9_VALIDITY_VALID;
+ fstat9->atime.value = fstatw->atime;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_MTIME) {
+ fstat9->mtime.valid = NDMP9_VALIDITY_VALID;
+ fstat9->mtime.value = fstatw->mtime;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_CTIME) {
+ fstat9->ctime.valid = NDMP9_VALIDITY_VALID;
+ fstat9->ctime.value = fstatw->ctime;
+ }
+
+ if (fstatw->valid & WRAP_FSTAT_VALID_FILENO) {
+ fstat9->node.valid = NDMP9_VALIDITY_VALID;
+ fstat9->node.value = fstatw->fileno;
+ }
+
+
+
+
+}
+
+
+
+
+/*
+ * Send LOG and NOTIFY messages
+ ****************************************************************
+ */
+
+#if 0
+void
+ndmda_send_logmsg (struct ndm_session *sess, char *fmt, ...)
+{
+ struct ndmconn * conn = sess->plumb.control;
+ char buf[4096];
+ va_list ap;
+
+ va_start (ap, fmt);
+ vsnprintf (buf, sizeof(buf), fmt, ap);
+ va_end (ap);
+
+ // we don't handle our own messages so don't send them....
+ if (conn->conn_type == NDMCONN_TYPE_RESIDENT) {
+ ndmalogf(sess, 0, 2, "RESIDENT AGENT LOGMSG: %s", buf);
+ return;
+ }
+
+ ndma_send_logmsg (sess, buf, conn);
+}
+#endif
+
+void
+ndmda_send_notice (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+
+ if (!da->data_notify_pending)
+ return;
+
+ da->data_notify_pending = 0;
+
+ switch (da->data_state.state) {
+ case NDMP9_DATA_STATE_HALTED:
+ ndma_notify_data_halted (sess);
+ break;
+
+ default:
+ /* Hmm. Why are we here. Race? */
+ break;
+ }
+}
+
+void
+ndmda_send_data_read (struct ndm_session *sess,
+ unsigned long long offset, unsigned long long length)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ ndmp9_addr_type addr_type;
+
+ addr_type = da->data_state.data_connection_addr.addr_type;
+#if 0
+ da->reco_read_offset = offset;
+ da->reco_read_length = length;
+#endif
+
+ if (NDMP9_ADDR_LOCAL == addr_type) {
+#ifndef NDMOS_OPTION_NO_TAPE_AGENT
+ if (ndmta_local_mover_read (sess, offset, length) != 0) {
+ ndma_send_logmsg (sess, NDMP9_LOG_ERROR,
+ sess->plumb.data,
+ "local_mover_read failed");
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
+ }
+#else /* !NDMOS_OPTION_NO_TAPE_AGENT */
+ ndma_send_logmsg (sess, NDMP9_LOG_ERROR,
+ sess->plumb.data,
+ "local_mover_read not configured");
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
+#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
+ return;
+ }
+
+ switch (addr_type) {
+ case NDMP9_ADDR_TCP:
+ ndma_notify_data_read (sess, offset, length);
+ break;
+
+ default:
+ ndma_send_logmsg (sess, NDMP9_LOG_ERROR, sess->plumb.data,
+ "bogus mover.addr_type");
+ ndmda_data_halt (sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
+ break;
+ }
+}
+
+
+
+
+/*
+ * Misc -- env[] and nlist[] subroutines, etc
+ ****************************************************************
+ */
+
+int
+ndmda_copy_environment (struct ndm_session *sess,
+ ndmp9_pval *env, unsigned n_env)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i;
+ unsigned int j;
+ ndmp9_pval * src_pv;
+ ndmp9_pval * dst_pv;
+
+ for (j = 0; j < n_env; j++) {
+ src_pv = &env[j];
+ dst_pv = &da->env_tab.env[da->env_tab.n_env];
+
+ dst_pv->name = NDMOS_API_STRDUP (src_pv->name);
+ dst_pv->value = NDMOS_API_STRDUP (src_pv->value);
+
+ if (!dst_pv->name || !dst_pv->value)
+ goto fail;
+
+ da->env_tab.n_env++;
+ }
+
+ return 0;
+
+ fail:
+ for (i = 0; i < da->env_tab.n_env; i++) {
+ char * p;
+
+ dst_pv = &da->env_tab.env[da->env_tab.n_env];
+
+ if ((p = dst_pv->name) != 0)
+ NDMOS_API_FREE (p);
+
+ if ((p = dst_pv->value) != 0)
+ NDMOS_API_FREE (p);
+ }
+ da->env_tab.n_env = 0;
+
+ return -1;
+}
+
+struct ndmp9_pval *
+ndmda_find_env (struct ndm_session *sess, char *name)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i;
+ struct ndmp9_pval * pv;
+
+ for (i = 0; i < da->env_tab.n_env; i++) {
+ pv = &da->env_tab.env[i];
+ if (strcmp (pv->name, name) == 0)
+ return pv;
+ }
+
+ return 0;
+}
+
+
+int
+ndmda_interpret_boolean_value (char *value_str, int default_value)
+{
+ if (strcasecmp (value_str, "y") == 0
+ || strcasecmp (value_str, "yes") == 0
+ || strcasecmp (value_str, "t") == 0
+ || strcasecmp (value_str, "true") == 0
+ || strcasecmp (value_str, "1") == 0)
+ return 1;
+
+ if (strcasecmp (value_str, "n") == 0
+ || strcasecmp (value_str, "no") == 0
+ || strcasecmp (value_str, "f") == 0
+ || strcasecmp (value_str, "false") == 0
+ || strcasecmp (value_str, "0") == 0)
+ return 0;
+
+ return default_value;
+}
+
+void
+ndmda_purge_environment (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i;
+ struct ndmp9_pval * pv;
+
+ for (i = 0; i < da->env_tab.n_env; i++) {
+ pv = &da->env_tab.env[i];
+
+ if (pv->name) NDMOS_API_FREE (pv->name);
+ if (pv->value) NDMOS_API_FREE (pv->value);
+ pv->name = 0;
+ pv->value = 0;
+ }
+ da->env_tab.n_env = 0;
+}
+
+
+int
+ndmda_copy_nlist (struct ndm_session *sess,
+ ndmp9_name *nlist, unsigned n_nlist)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ unsigned int i;
+ int j;
+ ndmp9_name * src_nl;
+ ndmp9_name * dst_nl;
+
+ for (i = 0; i < n_nlist; i++) {
+ j = da->nlist_tab.n_nlist;
+ src_nl = &nlist[i];
+ dst_nl = &da->nlist_tab.nlist[j];
+
+ dst_nl->original_path =
+ NDMOS_API_STRDUP (src_nl->original_path);
+ dst_nl->destination_path =
+ NDMOS_API_STRDUP (src_nl->destination_path);
+ dst_nl->fh_info = src_nl->fh_info;
+ da->nlist_tab.result_err[j] = NDMP9_UNDEFINED_ERR;
+ da->nlist_tab.result_count[j] = 0;
+
+ if (!dst_nl->original_path || !dst_nl->destination_path)
+ return -1; /* no mem */
+
+ da->nlist_tab.n_nlist++;
+ }
+
+ /* TODO: sort */
+
+ return 0;
+}
+
+void
+ndmda_purge_nlist (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i;
+ struct ndmp9_name * nl;
+
+ for (i = 0; i < da->nlist_tab.n_nlist; i++) {
+ nl = &da->nlist_tab.nlist[i];
+
+ if (nl->original_path) {
+ NDMOS_API_FREE (nl->original_path);
+ }
+ if (nl->destination_path) {
+ NDMOS_API_FREE (nl->destination_path);
+ }
+
+ nl->original_path = 0;
+ nl->destination_path = 0;
+ }
+ da->nlist_tab.n_nlist = 0;
+}
+
+int
+ndmda_count_invalid_fh_info (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i, count;
+ struct ndmp9_name * nl;
+
+ count = 0;
+ for (i = 0; i < da->nlist_tab.n_nlist; i++) {
+ nl = &da->nlist_tab.nlist[i];
+
+ if (nl->fh_info.valid != NDMP9_VALIDITY_VALID)
+ count++;
+ }
+
+ return count;
+}
+
+int
+ndmda_count_invalid_fh_info_pending (struct ndm_session *sess)
+{
+ struct ndm_data_agent * da = &sess->data_acb;
+ int i, count;
+ struct ndmp9_name * nl;
+
+ count = 0;
+ for (i = 0; i < da->nlist_tab.n_nlist; i++) {
+ nl = &da->nlist_tab.nlist[i];
+
+ if (da->nlist_tab.result_err[i] == NDMP9_UNDEFINED_ERR
+ && nl->fh_info.valid != NDMP9_VALIDITY_VALID) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+#endif /* !NDMOS_OPTION_NO_DATA_AGENT */