1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * BSD 3 Clause License 8 * 9 * Copyright (c) 2007, The Storage Networking Industry Association. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * - Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * - Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * - Neither the name of The Storage Networking Industry Association (SNIA) 23 * nor the names of its contributors may be used to endorse or promote 24 * products derived from this software without specific prior written 25 * permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 #include <locale.h> 40 #include <stdlib.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <door.h> 45 #include <thread.h> 46 #include <ndmpd_door.h> 47 #include <libndmp.h> 48 49 static int ndmp_door_fildes = -1; 50 static char *buf; 51 static ndmp_door_ctx_t *dec_ctx; 52 static ndmp_door_ctx_t *enc_ctx; 53 static door_arg_t arg; 54 static mutex_t ndmp_lock = DEFAULTMUTEX; 55 56 static int ndmp_door_setup(int opcode); 57 static int ndmp_door_call(void); 58 static int ndmp_door_fini(void); 59 60 /* ndmp library APIs */ 61 int 62 ndmp_get_devinfo(ndmp_devinfo_t **dip, size_t *size) 63 { 64 ndmp_devinfo_t *dipptr; 65 int i; 66 int opcode = NDMP_DEVICES_GET_INFO; 67 68 (void) mutex_lock(&ndmp_lock); 69 if (ndmp_door_setup(opcode)) 70 goto err; 71 72 if (ndmp_door_call()) 73 goto err; 74 75 /* get the number of devices available */ 76 *size = ndmp_door_get_uint32(dec_ctx); 77 78 *dip = malloc(sizeof (ndmp_devinfo_t) * *size); 79 if (!*dip) { 80 free(buf); 81 ndmp_errno = ENDMP_MEM_ALLOC; 82 goto err; 83 } 84 dipptr = *dip; 85 for (i = 0; i < *size; i++, dipptr++) { 86 dipptr->nd_dev_type = ndmp_door_get_int32(dec_ctx); 87 dipptr->nd_name = ndmp_door_get_string(dec_ctx); 88 dipptr->nd_lun = ndmp_door_get_int32(dec_ctx); 89 dipptr->nd_sid = ndmp_door_get_int32(dec_ctx); 90 dipptr->nd_vendor = ndmp_door_get_string(dec_ctx); 91 dipptr->nd_product = ndmp_door_get_string(dec_ctx); 92 dipptr->nd_revision = ndmp_door_get_string(dec_ctx); 93 dipptr->nd_serial = ndmp_door_get_string(dec_ctx); 94 dipptr->nd_wwn = ndmp_door_get_string(dec_ctx); 95 } 96 if (ndmp_door_fini()) { 97 free(*dip); 98 goto err; 99 } 100 (void) mutex_unlock(&ndmp_lock); 101 return (0); 102 err: 103 (void) mutex_unlock(&ndmp_lock); 104 return (-1); 105 } 106 107 void 108 ndmp_get_devinfo_free(ndmp_devinfo_t *dip, size_t size) 109 { 110 ndmp_devinfo_t *dipptr; 111 int i; 112 113 dipptr = dip; 114 for (i = 0; i < size; i++, dipptr++) { 115 free(dipptr->nd_name); 116 free(dipptr->nd_vendor); 117 free(dipptr->nd_product); 118 free(dipptr->nd_revision); 119 } 120 free(dip); 121 } 122 123 int 124 ndmp_terminate_session(int session) 125 { 126 int ret; 127 int opcode = NDMP_TERMINATE_SESSION_ID; 128 129 (void) mutex_lock(&ndmp_lock); 130 if (ndmp_door_setup(opcode)) 131 goto err; 132 133 ndmp_door_put_uint32(enc_ctx, session); 134 if (ndmp_door_call()) 135 goto err; 136 137 ret = ndmp_door_get_uint32(dec_ctx); 138 if (ndmp_door_fini()) 139 goto err; 140 141 (void) mutex_unlock(&ndmp_lock); 142 return (ret); 143 err: 144 (void) mutex_unlock(&ndmp_lock); 145 return (-1); 146 } 147 148 int 149 ndmp_get_session_info(ndmp_session_info_t **sinfo, size_t *size) 150 { 151 int status; 152 int i, j; 153 ndmp_session_info_t *sp; 154 ndmp_dt_pval_t *ep; 155 ndmp_dt_name_t *np; 156 ndmp_dt_name_v3_t *npv3; 157 int opcode = NDMP_SHOW; 158 159 (void) mutex_lock(&ndmp_lock); 160 if (ndmp_door_setup(opcode)) 161 goto err; 162 163 if (ndmp_door_call()) 164 goto err; 165 166 /* number of sessions */ 167 *size = ndmp_door_get_int32(dec_ctx); 168 169 *sinfo = malloc((sizeof (ndmp_session_info_t)) * *size); 170 if (!*sinfo) { 171 free(buf); 172 ndmp_errno = ENDMP_MEM_ALLOC; 173 goto err; 174 } 175 sp = *sinfo; 176 for (i = 0; i < *size; i++, sp++) { 177 status = ndmp_door_get_int32(dec_ctx); 178 if (status == NDMP_SESSION_NODATA) 179 continue; 180 181 /* connection common info */ 182 sp->nsi_sid = ndmp_door_get_int32(dec_ctx); 183 sp->nsi_pver = ndmp_door_get_int32(dec_ctx); 184 sp->nsi_auth = ndmp_door_get_int32(dec_ctx); 185 sp->nsi_eof = ndmp_door_get_int32(dec_ctx); 186 sp->nsi_cl_addr = ndmp_door_get_string(dec_ctx); 187 /* 188 * scsi and tape data are same for all version, 189 * so keep reading 190 */ 191 /* connection common scsi info. */ 192 sp->nsi_scsi.ns_scsi_open = ndmp_door_get_int32(dec_ctx); 193 sp->nsi_scsi.ns_adapter_name = ndmp_door_get_string(dec_ctx); 194 sp->nsi_scsi.ns_valid_target_set = ndmp_door_get_int32(dec_ctx); 195 if (sp->nsi_scsi.ns_valid_target_set) { 196 sp->nsi_scsi.ns_scsi_id = ndmp_door_get_int32(dec_ctx); 197 sp->nsi_scsi.ns_lun = ndmp_door_get_int32(dec_ctx); 198 } 199 200 /* connection common tape info. */ 201 sp->nsi_tape.nt_fd = ndmp_door_get_int32(dec_ctx); 202 if (sp->nsi_tape.nt_fd != -1) { 203 sp->nsi_tape.nt_rec_count = 204 ndmp_door_get_uint64(dec_ctx); 205 sp->nsi_tape.nt_mode = ndmp_door_get_int32(dec_ctx); 206 sp->nsi_tape.nt_dev_name = 207 ndmp_door_get_string(dec_ctx); 208 sp->nsi_tape.nt_adapter_name = 209 ndmp_door_get_string(dec_ctx); 210 sp->nsi_tape.nt_sid = ndmp_door_get_int32(dec_ctx); 211 sp->nsi_tape.nt_lun = ndmp_door_get_int32(dec_ctx); 212 } 213 /* all the V2 mover data are same as V3/V4 */ 214 sp->nsi_mover.nm_state = ndmp_door_get_int32(dec_ctx); 215 sp->nsi_mover.nm_mode = ndmp_door_get_int32(dec_ctx); 216 sp->nsi_mover.nm_pause_reason = ndmp_door_get_int32(dec_ctx); 217 sp->nsi_mover.nm_halt_reason = ndmp_door_get_int32(dec_ctx); 218 sp->nsi_mover.nm_rec_size = ndmp_door_get_uint64(dec_ctx); 219 sp->nsi_mover.nm_rec_num = ndmp_door_get_uint64(dec_ctx); 220 sp->nsi_mover.nm_mov_pos = ndmp_door_get_uint64(dec_ctx); 221 sp->nsi_mover.nm_window_offset = ndmp_door_get_uint64(dec_ctx); 222 sp->nsi_mover.nm_window_length = ndmp_door_get_uint64(dec_ctx); 223 sp->nsi_mover.nm_sock = ndmp_door_get_int32(dec_ctx); 224 225 /* Read V3/V4 mover info */ 226 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) { 227 sp->nsi_mover.nm_listen_sock = 228 ndmp_door_get_int32(dec_ctx); 229 sp->nsi_mover.nm_addr_type = 230 ndmp_door_get_int32(dec_ctx); 231 sp->nsi_mover.nm_tcp_addr = 232 ndmp_door_get_string(dec_ctx); 233 } 234 235 /* connection common data info */ 236 sp->nsi_data.nd_oper = ndmp_door_get_int32(dec_ctx); 237 sp->nsi_data.nd_state = ndmp_door_get_int32(dec_ctx); 238 sp->nsi_data.nd_halt_reason = ndmp_door_get_int32(dec_ctx); 239 sp->nsi_data.nd_sock = ndmp_door_get_int32(dec_ctx); 240 sp->nsi_data.nd_addr_type = ndmp_door_get_int32(dec_ctx); 241 sp->nsi_data.nd_abort = ndmp_door_get_int32(dec_ctx); 242 sp->nsi_data.nd_read_offset = ndmp_door_get_uint64(dec_ctx); 243 sp->nsi_data.nd_read_length = ndmp_door_get_uint64(dec_ctx); 244 sp->nsi_data.nd_total_size = ndmp_door_get_uint64(dec_ctx); 245 sp->nsi_data.nd_env_len = ndmp_door_get_uint64(dec_ctx); 246 sp->nsi_data.nd_env = 247 malloc(sizeof (ndmp_dt_pval_t) * sp->nsi_data.nd_env_len); 248 if (!sp->nsi_data.nd_env) { 249 free(buf); 250 ndmp_errno = ENDMP_MEM_ALLOC; 251 goto err; 252 } 253 ep = sp->nsi_data.nd_env; 254 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) { 255 ep->np_name = ndmp_door_get_string(dec_ctx); 256 ep->np_value = ndmp_door_get_string(dec_ctx); 257 } 258 sp->nsi_data.nd_tcp_addr = ndmp_door_get_string(dec_ctx); 259 260 /* Read V2 data info */ 261 if (sp->nsi_pver == NDMP_V2) { 262 sp->nsi_data.nld_nlist_len = 263 ndmp_door_get_int64(dec_ctx); 264 sp->nsi_data.nd_nlist.nld_nlist = 265 malloc(sizeof (ndmp_dt_name_t) * 266 sp->nsi_data.nld_nlist_len); 267 if (!sp->nsi_data.nd_nlist.nld_nlist) { 268 free(buf); 269 ndmp_errno = ENDMP_MEM_ALLOC; 270 goto err; 271 } 272 np = sp->nsi_data.nd_nlist.nld_nlist; 273 274 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) { 275 np->nn_name = ndmp_door_get_string(dec_ctx); 276 np->nn_dest = ndmp_door_get_string(dec_ctx); 277 } 278 } else if ((sp->nsi_pver == NDMP_V3) || 279 (sp->nsi_pver == NDMP_V4)) { 280 /* Read V3/V4 data info */ 281 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_listen_sock = 282 ndmp_door_get_int32(dec_ctx); 283 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_bytes_processed = 284 ndmp_door_get_uint64(dec_ctx); 285 sp->nsi_data.nld_nlist_len = 286 ndmp_door_get_uint64(dec_ctx); 287 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist = 288 malloc(sizeof (ndmp_dt_name_v3_t) * 289 sp->nsi_data.nld_nlist_len); 290 if (!sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist) { 291 free(buf); 292 ndmp_errno = ENDMP_MEM_ALLOC; 293 goto err; 294 } 295 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist; 296 for (j = 0; j < sp->nsi_data.nld_nlist_len; 297 j++, npv3++) { 298 npv3->nn3_opath = ndmp_door_get_string(dec_ctx); 299 npv3->nn3_dpath = ndmp_door_get_string(dec_ctx); 300 npv3->nn3_node = ndmp_door_get_uint64(dec_ctx); 301 npv3->nn3_fh_info = 302 ndmp_door_get_uint64(dec_ctx); 303 } 304 } 305 } 306 307 if (ndmp_door_fini()) 308 goto err; 309 310 (void) mutex_unlock(&ndmp_lock); 311 return (0); 312 err: 313 (void) mutex_unlock(&ndmp_lock); 314 return (-1); 315 } 316 317 void 318 ndmp_get_session_info_free(ndmp_session_info_t *sinfo, size_t size) 319 { 320 ndmp_session_info_t *sp; 321 ndmp_dt_pval_t *ep; 322 ndmp_dt_name_t *np; 323 ndmp_dt_name_v3_t *npv3; 324 int i, j; 325 326 sp = sinfo; 327 for (i = 0; i < size; i++, sp++) { 328 free(sp->nsi_cl_addr); 329 free(sp->nsi_scsi.ns_adapter_name); 330 if (sp->nsi_tape.nt_fd != -1) { 331 free(sp->nsi_tape.nt_dev_name); 332 free(sp->nsi_tape.nt_adapter_name); 333 } 334 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) 335 free(sp->nsi_mover.nm_tcp_addr); 336 337 ep = sp->nsi_data.nd_env; 338 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) { 339 free(ep->np_name); 340 free(ep->np_value); 341 } 342 free(sp->nsi_data.nd_env); 343 free(sp->nsi_data.nd_tcp_addr); 344 345 if (sp->nsi_pver == NDMP_V2) { 346 np = sp->nsi_data.nd_nlist.nld_nlist; 347 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) { 348 free(np->nn_name); 349 free(np->nn_dest); 350 } 351 free(sp->nsi_data.nd_nlist.nld_nlist); 352 } else if ((sp->nsi_pver == NDMP_V3) || 353 (sp->nsi_pver == NDMP_V4)) { 354 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist; 355 for (j = 0; j < sp->nsi_data.nld_nlist_len; 356 j++, npv3++) { 357 free(npv3->nn3_opath); 358 free(npv3->nn3_dpath); 359 } 360 free(sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist); 361 } 362 } 363 free(sinfo); 364 } 365 366 /* ARGSUSED */ 367 int 368 ndmp_get_stats(ndmp_stat_t *statp) 369 { 370 int opcode = NDMP_GET_STAT; 371 372 (void) mutex_lock(&ndmp_lock); 373 if (!statp) { 374 ndmp_errno = ENDMP_INVALID_ARG; 375 goto err; 376 } 377 378 if (ndmp_door_setup(opcode)) 379 goto err; 380 381 if (ndmp_door_call()) 382 goto err; 383 384 statp->ns_trun = ndmp_door_get_uint32(dec_ctx); 385 statp->ns_twait = ndmp_door_get_uint32(dec_ctx); 386 statp->ns_nbk = ndmp_door_get_uint32(dec_ctx); 387 statp->ns_nrs = ndmp_door_get_uint32(dec_ctx); 388 statp->ns_rfile = ndmp_door_get_uint32(dec_ctx); 389 statp->ns_wfile = ndmp_door_get_uint32(dec_ctx); 390 statp->ns_rdisk = ndmp_door_get_uint64(dec_ctx); 391 statp->ns_wdisk = ndmp_door_get_uint64(dec_ctx); 392 statp->ns_rtape = ndmp_door_get_uint64(dec_ctx); 393 statp->ns_wtape = ndmp_door_get_uint64(dec_ctx); 394 395 if (ndmp_door_fini()) 396 goto err; 397 398 (void) mutex_unlock(&ndmp_lock); 399 return (0); 400 err: 401 (void) mutex_unlock(&ndmp_lock); 402 return (-1); 403 } 404 405 int 406 ndmp_door_status(void) 407 { 408 int opcode = NDMP_GET_DOOR_STATUS; 409 410 (void) mutex_lock(&ndmp_lock); 411 if (ndmp_door_setup(opcode)) 412 goto err; 413 414 if (ndmp_door_call()) 415 goto err; 416 417 if (ndmp_door_fini()) 418 goto err; 419 420 (void) mutex_unlock(&ndmp_lock); 421 return (0); 422 err: 423 (void) mutex_unlock(&ndmp_lock); 424 return (-1); 425 } 426 427 static int 428 ndmp_door_setup(int opcode) 429 { 430 /* Open channel to NDMP service */ 431 if ((ndmp_door_fildes == -1) && 432 (ndmp_door_fildes = open(NDMP_DOOR_SVC, O_RDONLY)) < 0) { 433 ndmp_errno = ENDMP_DOOR_OPEN; 434 return (-1); 435 } 436 437 buf = malloc(NDMP_DOOR_SIZE); 438 if (!buf) { 439 ndmp_errno = ENDMP_MEM_ALLOC; 440 return (-1); 441 } 442 443 enc_ctx = ndmp_door_encode_start(buf, NDMP_DOOR_SIZE); 444 if (enc_ctx == 0) { 445 free(buf); 446 ndmp_errno = ENDMP_DOOR_ENCODE_START; 447 return (-1); 448 } 449 ndmp_door_put_uint32(enc_ctx, opcode); 450 return (0); 451 } 452 453 static int 454 ndmp_door_call(void) 455 { 456 uint32_t used; 457 int rc; 458 459 if ((ndmp_door_encode_finish(enc_ctx, &used)) != 0) { 460 free(buf); 461 ndmp_errno = ENDMP_DOOR_ENCODE_FINISH; 462 return (-1); 463 } 464 465 arg.data_ptr = buf; 466 arg.data_size = used; 467 arg.desc_ptr = NULL; 468 arg.desc_num = 0; 469 arg.rbuf = buf; 470 arg.rsize = NDMP_DOOR_SIZE; 471 472 if (door_call(ndmp_door_fildes, &arg) < 0) { 473 free(buf); 474 ndmp_errno = ENDMP_DOOR_SRV_TIMEOUT; 475 (void) close(ndmp_door_fildes); 476 ndmp_door_fildes = -1; 477 return (-1); 478 } 479 480 dec_ctx = ndmp_door_decode_start(arg.data_ptr, arg.data_size); 481 rc = ndmp_door_get_uint32(dec_ctx); 482 if (rc != NDMP_DOOR_SRV_SUCCESS) { 483 free(buf); 484 ndmp_errno = ENDMP_DOOR_SRV_OPERATION; 485 return (-1); 486 } 487 return (0); 488 } 489 490 static int 491 ndmp_door_fini(void) 492 { 493 if ((ndmp_door_decode_finish(dec_ctx)) != 0) { 494 free(buf); 495 ndmp_errno = ENDMP_DOOR_DECODE_FINISH; 496 return (-1); 497 } 498 free(buf); 499 return (0); 500 } 501