2N/A/*
2N/A * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * BSD 3 Clause License
2N/A *
2N/A * Copyright (c) 2007, The Storage Networking Industry Association.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A * - Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * - Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * - Neither the name of The Storage Networking Industry Association (SNIA)
2N/A * nor the names of its contributors may be used to endorse or promote
2N/A * products derived from this software without specific prior written
2N/A * permission.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2N/A * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2N/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2N/A * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2N/A * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2N/A * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2N/A * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2N/A * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2N/A * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2N/A * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2N/A * POSSIBILITY OF SUCH DAMAGE.
2N/A */
2N/A#include <locale.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <unistd.h>
2N/A#include <fcntl.h>
2N/A#include <door.h>
2N/A#include <thread.h>
2N/A#include <ndmpd_door.h>
2N/A#include <libndmp.h>
2N/A
2N/Astatic int ndmp_num_conn; /* number of connections */
2N/A
2N/Astatic int ndmp_door_fildes = -1;
2N/Astatic char *door_buf = NULL;
2N/Astatic int door_buf_size = 0;
2N/Astatic ndmp_door_ctx_t *dec_ctx;
2N/Astatic ndmp_door_ctx_t *enc_ctx;
2N/Astatic door_arg_t arg;
2N/Astatic mutex_t ndmp_lock = DEFAULTMUTEX;
2N/A
2N/Astatic int ndmp_door_setup(int opcode);
2N/Astatic int ndmp_door_call(ndmp_door_err_t *);
2N/Astatic int ndmp_door_fini(void);
2N/A
2N/Astatic int ndmp_num_dev = 0; /* number of devices */
2N/A
2N/A/* ndmp library APIs */
2N/Aint
2N/Andmp_get_devinfo(ndmp_devinfo_t **dipp, size_t *sizep)
2N/A{
2N/A ndmp_devinfo_t *dip;
2N/A int i;
2N/A ndmp_door_err_t derr;
2N/A
2N/A (void) mutex_lock(&ndmp_lock);
2N/A
2N/A /*
2N/A * the first door call is to get the device count
2N/A * which will be used to calculate the door buffer size
2N/A */
2N/A if (ndmp_door_setup(NDMP_GET_DEV_CNT) ||
2N/A ndmp_door_call(&derr)) {
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A }
2N/A
2N/A /* number of devices */
2N/A ndmp_num_dev = ndmp_door_get_int32(dec_ctx);
2N/A
2N/A if (ndmp_door_fini() ||
2N/A ndmp_door_setup(NDMP_DEVICES_GET_INFO) ||
2N/A ndmp_door_call(&derr)) {
2N/A ndmp_num_dev = 0;
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A }
2N/A
2N/A /* get the number of devices available */
2N/A *sizep = ndmp_door_get_uint32(dec_ctx);
2N/A
2N/A /* calloc to ensure NULL pointers in allocated struct */
2N/A *dipp = calloc(*sizep, sizeof (ndmp_devinfo_t));
2N/A if (*dipp == NULL) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A }
2N/A dip = *dipp;
2N/A for (i = 0; i < *sizep; i++, dip++) {
2N/A dip->nd_dev_type = ndmp_door_get_int32(dec_ctx);
2N/A dip->nd_name = ndmp_door_get_string(dec_ctx);
2N/A dip->nd_lun = ndmp_door_get_int32(dec_ctx);
2N/A dip->nd_sid = ndmp_door_get_int32(dec_ctx);
2N/A dip->nd_vendor = ndmp_door_get_string(dec_ctx);
2N/A dip->nd_product = ndmp_door_get_string(dec_ctx);
2N/A dip->nd_revision = ndmp_door_get_string(dec_ctx);
2N/A dip->nd_serial = ndmp_door_get_string(dec_ctx);
2N/A dip->nd_wwn = ndmp_door_get_string(dec_ctx);
2N/A
2N/A if (dip->nd_name == NULL ||
2N/A dip->nd_vendor == NULL ||
2N/A dip->nd_product == NULL ||
2N/A dip->nd_revision == NULL ||
2N/A dip->nd_serial == NULL ||
2N/A dip->nd_wwn == NULL) {
2N/A /* Free all allocations if any failed */
2N/A ndmp_get_devinfo_free(dipp, sizep);
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A }
2N/A }
2N/A if (ndmp_door_fini()) {
2N/A /* Free all allocations if anything failed */
2N/A ndmp_get_devinfo_free(dipp, sizep);
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A }
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Andmp_get_devinfo_free(ndmp_devinfo_t **dipp, size_t *sizep)
2N/A{
2N/A ndmp_devinfo_t *dip;
2N/A int i;
2N/A
2N/A if (*dipp != NULL) {
2N/A dip = *dipp;
2N/A for (i = 0; i < *sizep; i++, dip++) {
2N/A free(dip->nd_name);
2N/A free(dip->nd_vendor);
2N/A free(dip->nd_product);
2N/A free(dip->nd_revision);
2N/A free(dip->nd_serial);
2N/A free(dip->nd_wwn);
2N/A }
2N/A free(*dipp);
2N/A *dipp = NULL;
2N/A }
2N/A}
2N/A
2N/Aint
2N/Andmp_terminate_session(int session)
2N/A{
2N/A int ret;
2N/A int opcode = NDMP_TERMINATE_SESSION_ID;
2N/A ndmp_door_err_t derr;
2N/A
2N/A (void) mutex_lock(&ndmp_lock);
2N/A if (ndmp_door_setup(opcode))
2N/A goto err;
2N/A
2N/A ndmp_door_put_uint32(enc_ctx, session);
2N/A if (ndmp_door_call(&derr))
2N/A goto err;
2N/A
2N/A ret = ndmp_door_get_uint32(dec_ctx);
2N/A if (ndmp_door_fini())
2N/A goto err;
2N/A
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (ret);
2N/Aerr:
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Andmp_get_session_info(ndmp_session_info_t **sinfopp, size_t *sizep)
2N/A{
2N/A int status;
2N/A int i, j;
2N/A int prev_num_conn = 0;
2N/A int attempts = 0;
2N/A ndmp_session_info_t *sp;
2N/A ndmp_dt_pval_t *ep;
2N/A ndmp_dt_name_t *np;
2N/A ndmp_dt_name_v3_t *npv3;
2N/A ndmp_door_err_t derr;
2N/A
2N/A
2N/A (void) mutex_lock(&ndmp_lock);
2N/A
2N/A for (attempts = 0; attempts < MAX_ALLOWED_DOOR_RETRY; attempts++) {
2N/A
2N/A if (ndmp_door_setup(NDMP_GET_NUM_CONN))
2N/A goto err;
2N/A
2N/A if (ndmp_door_call(&derr))
2N/A goto err;
2N/A
2N/A /* number of sessions */
2N/A prev_num_conn = ndmp_num_conn;
2N/A ndmp_num_conn = ndmp_door_get_int32(dec_ctx);
2N/A
2N/A if (ndmp_door_fini())
2N/A goto err;
2N/A
2N/A /*
2N/A * Now setup the door again, this time
2N/A * with the intention of getting the session
2N/A * specific info.
2N/A */
2N/A if (ndmp_door_setup(NDMP_SHOW))
2N/A goto err;
2N/A
2N/A if (ndmp_door_call(&derr)) {
2N/A /*
2N/A * If we failed because of space constraints
2N/A * then reevaluate and give it another try,
2N/A * but only if the number of sessions actually changed
2N/A * between our previous call and now. If they are
2N/A * equal, then retrying is fruitless.
2N/A */
2N/A if ((derr.door_extended_err == ENOSPC) &&
2N/A (prev_num_conn < ndmp_num_conn)) {
2N/A continue;
2N/A } else {
2N/A goto err;
2N/A }
2N/A } else {
2N/A /*
2N/A * If the door call was successful then
2N/A * no need to continue to retry. Break out
2N/A * of the loop now.
2N/A */
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* number of sessions */
2N/A *sizep = ndmp_door_get_int32(dec_ctx);
2N/A
2N/A /* calloc to ensure NULL pointers in allocated struct */
2N/A *sinfopp = calloc(*sizep, sizeof (ndmp_session_info_t));
2N/A if (*sinfopp == NULL) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A goto err;
2N/A }
2N/A sp = *sinfopp;
2N/A for (i = 0; i < *sizep; i++, sp++) {
2N/A status = ndmp_door_get_int32(dec_ctx);
2N/A if (status == NDMP_SESSION_NODATA)
2N/A continue;
2N/A
2N/A /* connection common info */
2N/A sp->nsi_sid = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_pver = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_auth = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_eof = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_cl_addr = ndmp_door_get_string(dec_ctx);
2N/A /*
2N/A * scsi and tape data are same for all version,
2N/A * so keep reading
2N/A */
2N/A /* connection common scsi info. */
2N/A sp->nsi_scsi.ns_scsi_open = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_scsi.ns_adapter_name = ndmp_door_get_string(dec_ctx);
2N/A sp->nsi_scsi.ns_valid_target_set = ndmp_door_get_int32(dec_ctx);
2N/A if (sp->nsi_scsi.ns_valid_target_set) {
2N/A sp->nsi_scsi.ns_scsi_id = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_scsi.ns_lun = ndmp_door_get_int32(dec_ctx);
2N/A }
2N/A
2N/A /* connection common tape info. */
2N/A sp->nsi_tape.nt_fd = ndmp_door_get_int32(dec_ctx);
2N/A if (sp->nsi_tape.nt_fd != -1) {
2N/A sp->nsi_tape.nt_rec_count =
2N/A ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_tape.nt_mode = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_tape.nt_dev_name =
2N/A ndmp_door_get_string(dec_ctx);
2N/A sp->nsi_tape.nt_sid = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_tape.nt_lun = ndmp_door_get_int32(dec_ctx);
2N/A }
2N/A /* all the V2 mover data are same as V3/V4 */
2N/A sp->nsi_mover.nm_state = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_mode = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_pause_reason = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_halt_reason = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_rec_size = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_mover.nm_rec_num = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_mover.nm_mov_pos = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_mover.nm_window_offset = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_mover.nm_window_length = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_mover.nm_sock = ndmp_door_get_int32(dec_ctx);
2N/A
2N/A /* Read V3/V4 mover info */
2N/A if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) {
2N/A sp->nsi_mover.nm_listen_sock =
2N/A ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_addr_type =
2N/A ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_mover.nm_tcp_addr =
2N/A ndmp_door_get_string(dec_ctx);
2N/A }
2N/A
2N/A /* connection common data info */
2N/A sp->nsi_data.nd_oper = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_state = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_halt_reason = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_sock = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_addr_type = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_abort = ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_read_offset = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_data.nd_read_length = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_data.nd_total_size = ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_data.nd_env_len = ndmp_door_get_uint64(dec_ctx);
2N/A /* calloc to ensure NULL pointers in allocated struct */
2N/A sp->nsi_data.nd_env =
2N/A calloc(sp->nsi_data.nd_env_len, sizeof (ndmp_dt_pval_t));
2N/A if (!sp->nsi_data.nd_env) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A ndmp_get_session_info_free(sinfopp, sizep);
2N/A goto err;
2N/A }
2N/A ep = sp->nsi_data.nd_env;
2N/A for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) {
2N/A ep->np_name = ndmp_door_get_string(dec_ctx);
2N/A ep->np_value = ndmp_door_get_string(dec_ctx);
2N/A }
2N/A sp->nsi_data.nd_tcp_addr = ndmp_door_get_string(dec_ctx);
2N/A
2N/A /* Read V2 data info */
2N/A if (sp->nsi_pver == NDMP_V2) {
2N/A sp->nsi_data.nld_nlist_len =
2N/A ndmp_door_get_int64(dec_ctx);
2N/A /* calloc to ensure NULL pointers in allocated struct */
2N/A sp->nsi_data.nd_nlist.nld_nlist =
2N/A calloc(sp->nsi_data.nld_nlist_len,
2N/A sizeof (ndmp_dt_name_t));
2N/A if (!sp->nsi_data.nd_nlist.nld_nlist) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A ndmp_get_session_info_free(sinfopp, sizep);
2N/A goto err;
2N/A }
2N/A np = sp->nsi_data.nd_nlist.nld_nlist;
2N/A
2N/A for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) {
2N/A np->nn_name = ndmp_door_get_string(dec_ctx);
2N/A np->nn_dest = ndmp_door_get_string(dec_ctx);
2N/A }
2N/A } else if ((sp->nsi_pver == NDMP_V3) ||
2N/A (sp->nsi_pver == NDMP_V4)) {
2N/A /* Read V3/V4 data info */
2N/A sp->nsi_data.nd_nlist.nld_dt_v3.dv3_listen_sock =
2N/A ndmp_door_get_int32(dec_ctx);
2N/A sp->nsi_data.nd_nlist.nld_dt_v3.dv3_bytes_processed =
2N/A ndmp_door_get_uint64(dec_ctx);
2N/A sp->nsi_data.nld_nlist_len =
2N/A ndmp_door_get_uint64(dec_ctx);
2N/A /* calloc to ensure NULL pointers in allocated struct */
2N/A sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist =
2N/A calloc(sp->nsi_data.nld_nlist_len,
2N/A sizeof (ndmp_dt_name_v3_t));
2N/A if (!sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A ndmp_get_session_info_free(sinfopp, sizep);
2N/A goto err;
2N/A }
2N/A npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist;
2N/A for (j = 0; j < sp->nsi_data.nld_nlist_len;
2N/A j++, npv3++) {
2N/A npv3->nn3_opath = ndmp_door_get_string(dec_ctx);
2N/A npv3->nn3_dpath = ndmp_door_get_string(dec_ctx);
2N/A npv3->nn3_node = ndmp_door_get_uint64(dec_ctx);
2N/A npv3->nn3_fh_info =
2N/A ndmp_door_get_uint64(dec_ctx);
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (ndmp_door_fini()) {
2N/A ndmp_get_session_info_free(sinfopp, sizep);
2N/A goto err;
2N/A }
2N/A
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (0);
2N/Aerr:
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A}
2N/A
2N/Avoid
2N/Andmp_get_session_info_free(ndmp_session_info_t **sinfopp, size_t *sizep)
2N/A{
2N/A ndmp_session_info_t *sp;
2N/A ndmp_dt_pval_t *ep;
2N/A ndmp_dt_name_t *np;
2N/A ndmp_dt_name_v3_t *npv3;
2N/A int i, j;
2N/A
2N/A/*
2N/A * Protect against dereferencing a null pointer in any of the following code.
2N/A * If *sinfopp == NULL, assume that everything was already freed previously.
2N/A */
2N/A if (*sinfopp == NULL) {
2N/A return;
2N/A }
2N/A
2N/A sp = *sinfopp;
2N/A for (i = 0; i < *sizep; i++, sp++) {
2N/A free(sp->nsi_cl_addr);
2N/A free(sp->nsi_scsi.ns_adapter_name);
2N/A if (sp->nsi_tape.nt_fd != -1) {
2N/A free(sp->nsi_tape.nt_dev_name);
2N/A }
2N/A if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4))
2N/A free(sp->nsi_mover.nm_tcp_addr);
2N/A
2N/A ep = sp->nsi_data.nd_env;
2N/A for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) {
2N/A free(ep->np_name);
2N/A free(ep->np_value);
2N/A }
2N/A free(sp->nsi_data.nd_env);
2N/A free(sp->nsi_data.nd_tcp_addr);
2N/A
2N/A if (sp->nsi_pver == NDMP_V2) {
2N/A np = sp->nsi_data.nd_nlist.nld_nlist;
2N/A for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) {
2N/A free(np->nn_name);
2N/A free(np->nn_dest);
2N/A }
2N/A free(sp->nsi_data.nd_nlist.nld_nlist);
2N/A } else if ((sp->nsi_pver == NDMP_V3) ||
2N/A (sp->nsi_pver == NDMP_V4)) {
2N/A npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist;
2N/A for (j = 0; j < sp->nsi_data.nld_nlist_len;
2N/A j++, npv3++) {
2N/A free(npv3->nn3_opath);
2N/A free(npv3->nn3_dpath);
2N/A }
2N/A free(sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist);
2N/A }
2N/A }
2N/A free(*sinfopp);
2N/A *sinfopp = NULL;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Andmp_get_stats(ndmp_stat_t *statp)
2N/A{
2N/A int opcode = NDMP_GET_STAT;
2N/A ndmp_door_err_t derr;
2N/A
2N/A (void) mutex_lock(&ndmp_lock);
2N/A if (!statp) {
2N/A ndmp_errno = ENDMP_INVALID_ARG;
2N/A goto err;
2N/A }
2N/A
2N/A if (ndmp_door_setup(opcode))
2N/A goto err;
2N/A
2N/A if (ndmp_door_call(&derr))
2N/A goto err;
2N/A
2N/A statp->ns_trun = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_twait = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_nbk = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_nrs = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_rfile = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_wfile = ndmp_door_get_uint32(dec_ctx);
2N/A statp->ns_rdisk = ndmp_door_get_uint64(dec_ctx);
2N/A statp->ns_wdisk = ndmp_door_get_uint64(dec_ctx);
2N/A statp->ns_rtape = ndmp_door_get_uint64(dec_ctx);
2N/A statp->ns_wtape = ndmp_door_get_uint64(dec_ctx);
2N/A
2N/A if (ndmp_door_fini())
2N/A goto err;
2N/A
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (0);
2N/Aerr:
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Andmp_door_status(void)
2N/A{
2N/A int opcode = NDMP_GET_DOOR_STATUS;
2N/A ndmp_door_err_t derr;
2N/A
2N/A (void) mutex_lock(&ndmp_lock);
2N/A if (ndmp_door_setup(opcode))
2N/A goto err;
2N/A
2N/A if (ndmp_door_call(&derr))
2N/A goto err;
2N/A
2N/A if (ndmp_door_fini())
2N/A goto err;
2N/A
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (0);
2N/Aerr:
2N/A (void) mutex_unlock(&ndmp_lock);
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Andmp_door_setup(int opcode)
2N/A{
2N/A /* Open channel to NDMP service */
2N/A if ((ndmp_door_fildes == -1) &&
2N/A (ndmp_door_fildes = open(NDMP_DOOR_SVC, O_RDONLY)) < 0) {
2N/A ndmp_errno = ENDMP_DOOR_OPEN;
2N/A return (-1);
2N/A }
2N/A
2N/A switch (opcode) {
2N/A case NDMP_SHOW:
2N/A door_buf_size = (NDMP_DOOR_SESSION_INFO * ndmp_num_conn);
2N/A break;
2N/A case NDMP_DEVICES_GET_INFO:
2N/A door_buf_size = (NDMP_DOOR_DEVICE_INFO * ndmp_num_dev);
2N/A break;
2N/A default:
2N/A door_buf_size = NDMP_DOOR_SIZE;
2N/A }
2N/A
2N/A /*
2N/A * No matter what, we don't allow our
2N/A * door size to be less than NDMP_DOOR_SIZE
2N/A */
2N/A if (door_buf_size < NDMP_DOOR_SIZE)
2N/A door_buf_size = NDMP_DOOR_SIZE;
2N/A
2N/A door_buf = malloc(door_buf_size);
2N/A if (door_buf == NULL) {
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A return (-1);
2N/A }
2N/A
2N/A enc_ctx = ndmp_door_encode_start(door_buf, door_buf_size);
2N/A if (enc_ctx == 0) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_DOOR_ENCODE_START;
2N/A return (-1);
2N/A }
2N/A ndmp_door_put_uint32(enc_ctx, opcode);
2N/A
2N/A /*
2N/A * If it is an opcode that can elicit a variant
2N/A * response in size, tell the door callee
2N/A * how much memory to alloc when forming the
2N/A * response.
2N/A */
2N/A switch (opcode) {
2N/A case NDMP_SHOW:
2N/A case NDMP_DEVICES_GET_INFO:
2N/A ndmp_door_put_uint32(enc_ctx, door_buf_size);
2N/A break;
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Andmp_door_call(ndmp_door_err_t *derr)
2N/A{
2N/A uint32_t used;
2N/A int rc;
2N/A
2N/A (void) memset((void *)derr, 0, sizeof (ndmp_door_err_t));
2N/A
2N/A if ((ndmp_door_encode_finish(enc_ctx, &used)) != 0) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_DOOR_ENCODE_FINISH;
2N/A return (-1);
2N/A }
2N/A
2N/A arg.data_ptr = door_buf;
2N/A arg.data_size = used;
2N/A arg.desc_ptr = NULL;
2N/A arg.desc_num = 0;
2N/A arg.rbuf = door_buf;
2N/A arg.rsize = door_buf_size;
2N/A
2N/A if (door_call(ndmp_door_fildes, &arg) < 0) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_DOOR_SRV_TIMEOUT;
2N/A (void) close(ndmp_door_fildes);
2N/A ndmp_door_fildes = -1;
2N/A return (-1);
2N/A }
2N/A
2N/A dec_ctx = ndmp_door_decode_start(arg.data_ptr, arg.data_size);
2N/A rc = ndmp_door_get_uint32(dec_ctx);
2N/A if (rc != NDMP_DOOR_SRV_SUCCESS) {
2N/A derr->door_err = rc;
2N/A derr->door_extended_err = ndmp_door_get_uint32(dec_ctx);
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_DOOR_SRV_OPERATION;
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Andmp_door_fini(void)
2N/A{
2N/A if ((ndmp_door_decode_finish(dec_ctx)) != 0) {
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A ndmp_errno = ENDMP_DOOR_DECODE_FINISH;
2N/A return (-1);
2N/A }
2N/A free(door_buf);
2N/A door_buf = NULL;
2N/A return (0);
2N/A}