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 } 94 if (ndmp_door_fini()) { 95 free(*dip); 96 goto err; 97 } 98 (void) mutex_unlock(&ndmp_lock); 99 return (0); 100 err: 101 (void) mutex_unlock(&ndmp_lock); 102 return (-1); 103 } 104 105 void 106 ndmp_get_devinfo_free(ndmp_devinfo_t *dip, size_t size) 107 { 108 ndmp_devinfo_t *dipptr; 109 int i; 110 111 dipptr = dip; 112 for (i = 0; i < size; i++, dipptr++) { 113 free(dipptr->nd_name); 114 free(dipptr->nd_vendor); 115 free(dipptr->nd_product); 116 free(dipptr->nd_revision); 117 } 118 free(dip); 119 } 120 121 int 122 ndmp_terminate_session(int session) 123 { 124 int ret; 125 int opcode = NDMP_TERMINATE_SESSION_ID; 126 127 (void) mutex_lock(&ndmp_lock); 128 if (ndmp_door_setup(opcode)) 129 goto err; 130 131 ndmp_door_put_uint32(enc_ctx, session); 132 if (ndmp_door_call()) 133 goto err; 134 135 ret = ndmp_door_get_uint32(dec_ctx); 136 if (ndmp_door_fini()) 137 goto err; 138 139 (void) mutex_unlock(&ndmp_lock); 140 return (ret); 141 err: 142 (void) mutex_unlock(&ndmp_lock); 143 return (-1); 144 } 145 146 int 147 ndmp_get_session_info(ndmp_session_info_t **sinfo, size_t *size) 148 { 149 int status; 150 int i, j; 151 ndmp_session_info_t *sp; 152 ndmp_dt_pval_t *ep; 153 ndmp_dt_name_t *np; 154 ndmp_dt_name_v3_t *npv3; 155 int opcode = NDMP_SHOW; 156 157 (void) mutex_lock(&ndmp_lock); 158 if (ndmp_door_setup(opcode)) 159 goto err; 160 161 if (ndmp_door_call()) 162 goto err; 163 164 /* number of sessions */ 165 *size = ndmp_door_get_int32(dec_ctx); 166 167 *sinfo = malloc((sizeof (ndmp_session_info_t)) * *size); 168 if (!*sinfo) { 169 free(buf); 170 ndmp_errno = ENDMP_MEM_ALLOC; 171 goto err; 172 } 173 sp = *sinfo; 174 for (i = 0; i < *size; i++, sp++) { 175 status = ndmp_door_get_int32(dec_ctx); 176 if (status == NDMP_SESSION_NODATA) 177 continue; 178 179 /* connection common info */ 180 sp->nsi_sid = ndmp_door_get_int32(dec_ctx); 181 sp->nsi_pver = ndmp_door_get_int32(dec_ctx); 182 sp->nsi_auth = ndmp_door_get_int32(dec_ctx); 183 sp->nsi_eof = ndmp_door_get_int32(dec_ctx); 184 sp->nsi_cl_addr = ndmp_door_get_string(dec_ctx); 185 /* 186 * scsi and tape data are same for all version, 187 * so keep reading 188 */ 189 /* connection common scsi info. */ 190 sp->nsi_scsi.ns_scsi_open = ndmp_door_get_int32(dec_ctx); 191 sp->nsi_scsi.ns_adapter_name = ndmp_door_get_string(dec_ctx); 192 sp->nsi_scsi.ns_valid_target_set = ndmp_door_get_int32(dec_ctx); 193 if (sp->nsi_scsi.ns_valid_target_set) { 194 sp->nsi_scsi.ns_scsi_id = ndmp_door_get_int32(dec_ctx); 195 sp->nsi_scsi.ns_lun = ndmp_door_get_int32(dec_ctx); 196 } 197 198 /* connection common tape info. */ 199 sp->nsi_tape.nt_fd = ndmp_door_get_int32(dec_ctx); 200 if (sp->nsi_tape.nt_fd != -1) { 201 sp->nsi_tape.nt_rec_count = 202 ndmp_door_get_uint64(dec_ctx); 203 sp->nsi_tape.nt_mode = ndmp_door_get_int32(dec_ctx); 204 sp->nsi_tape.nt_dev_name = 205 ndmp_door_get_string(dec_ctx); 206 sp->nsi_tape.nt_adapter_name = 207 ndmp_door_get_string(dec_ctx); 208 sp->nsi_tape.nt_sid = ndmp_door_get_int32(dec_ctx); 209 sp->nsi_tape.nt_lun = ndmp_door_get_int32(dec_ctx); 210 } 211 /* all the V2 mover data are same as V3/V4 */ 212 sp->nsi_mover.nm_state = ndmp_door_get_int32(dec_ctx); 213 sp->nsi_mover.nm_mode = ndmp_door_get_int32(dec_ctx); 214 sp->nsi_mover.nm_pause_reason = ndmp_door_get_int32(dec_ctx); 215 sp->nsi_mover.nm_halt_reason = ndmp_door_get_int32(dec_ctx); 216 sp->nsi_mover.nm_rec_size = ndmp_door_get_uint64(dec_ctx); 217 sp->nsi_mover.nm_rec_num = ndmp_door_get_uint64(dec_ctx); 218 sp->nsi_mover.nm_mov_pos = ndmp_door_get_uint64(dec_ctx); 219 sp->nsi_mover.nm_window_offset = ndmp_door_get_uint64(dec_ctx); 220 sp->nsi_mover.nm_window_length = ndmp_door_get_uint64(dec_ctx); 221 sp->nsi_mover.nm_sock = ndmp_door_get_int32(dec_ctx); 222 223 /* Read V3/V4 mover info */ 224 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) { 225 sp->nsi_mover.nm_listen_sock = 226 ndmp_door_get_int32(dec_ctx); 227 sp->nsi_mover.nm_addr_type = 228 ndmp_door_get_int32(dec_ctx); 229 sp->nsi_mover.nm_tcp_addr = 230 ndmp_door_get_string(dec_ctx); 231 } 232 233 /* connection common data info */ 234 sp->nsi_data.nd_oper = ndmp_door_get_int32(dec_ctx); 235 sp->nsi_data.nd_state = ndmp_door_get_int32(dec_ctx); 236 sp->nsi_data.nd_halt_reason = ndmp_door_get_int32(dec_ctx); 237 sp->nsi_data.nd_sock = ndmp_door_get_int32(dec_ctx); 238 sp->nsi_data.nd_addr_type = ndmp_door_get_int32(dec_ctx); 239 sp->nsi_data.nd_abort = ndmp_door_get_int32(dec_ctx); 240 sp->nsi_data.nd_read_offset = ndmp_door_get_uint64(dec_ctx); 241 sp->nsi_data.nd_read_length = ndmp_door_get_uint64(dec_ctx); 242 sp->nsi_data.nd_total_size = ndmp_door_get_uint64(dec_ctx); 243 sp->nsi_data.nd_env_len = ndmp_door_get_uint64(dec_ctx); 244 sp->nsi_data.nd_env = 245 malloc(sizeof (ndmp_dt_pval_t) * sp->nsi_data.nd_env_len); 246 if (!sp->nsi_data.nd_env) { 247 free(buf); 248 ndmp_errno = ENDMP_MEM_ALLOC; 249 goto err; 250 } 251 ep = sp->nsi_data.nd_env; 252 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) { 253 ep->np_name = ndmp_door_get_string(dec_ctx); 254 ep->np_value = ndmp_door_get_string(dec_ctx); 255 } 256 sp->nsi_data.nd_tcp_addr = ndmp_door_get_string(dec_ctx); 257 258 /* Read V2 data info */ 259 if (sp->nsi_pver == NDMP_V2) { 260 sp->nsi_data.nld_nlist_len = 261 ndmp_door_get_int64(dec_ctx); 262 sp->nsi_data.nd_nlist.nld_nlist = 263 malloc(sizeof (ndmp_dt_name_t) * 264 sp->nsi_data.nld_nlist_len); 265 if (!sp->nsi_data.nd_nlist.nld_nlist) { 266 free(buf); 267 ndmp_errno = ENDMP_MEM_ALLOC; 268 goto err; 269 } 270 np = sp->nsi_data.nd_nlist.nld_nlist; 271 272 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) { 273 np->nn_name = ndmp_door_get_string(dec_ctx); 274 np->nn_dest = ndmp_door_get_string(dec_ctx); 275 } 276 } else if ((sp->nsi_pver == NDMP_V3) || 277 (sp->nsi_pver == NDMP_V4)) { 278 /* Read V3/V4 data info */ 279 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_listen_sock = 280 ndmp_door_get_int32(dec_ctx); 281 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_bytes_processed = 282 ndmp_door_get_uint64(dec_ctx); 283 sp->nsi_data.nld_nlist_len = 284 ndmp_door_get_uint64(dec_ctx); 285 sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist = 286 malloc(sizeof (ndmp_dt_name_v3_t) * 287 sp->nsi_data.nld_nlist_len); 288 if (!sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist) { 289 free(buf); 290 ndmp_errno = ENDMP_MEM_ALLOC; 291 goto err; 292 } 293 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist; 294 for (j = 0; j < sp->nsi_data.nld_nlist_len; 295 j++, npv3++) { 296 npv3->nn3_opath = ndmp_door_get_string(dec_ctx); 297 npv3->nn3_dpath = ndmp_door_get_string(dec_ctx); 298 npv3->nn3_node = ndmp_door_get_uint64(dec_ctx); 299 npv3->nn3_fh_info = 300 ndmp_door_get_uint64(dec_ctx); 301 } 302 } 303 } 304 305 if (ndmp_door_fini()) 306 goto err; 307 308 (void) mutex_unlock(&ndmp_lock); 309 return (0); 310 err: 311 (void) mutex_unlock(&ndmp_lock); 312 return (-1); 313 } 314 315 void 316 ndmp_get_session_info_free(ndmp_session_info_t *sinfo, size_t size) 317 { 318 ndmp_session_info_t *sp; 319 ndmp_dt_pval_t *ep; 320 ndmp_dt_name_t *np; 321 ndmp_dt_name_v3_t *npv3; 322 int i, j; 323 324 sp = sinfo; 325 for (i = 0; i < size; i++, sp++) { 326 free(sp->nsi_cl_addr); 327 free(sp->nsi_scsi.ns_adapter_name); 328 if (sp->nsi_tape.nt_fd != -1) { 329 free(sp->nsi_tape.nt_dev_name); 330 free(sp->nsi_tape.nt_adapter_name); 331 } 332 if ((sp->nsi_pver == NDMP_V3) || (sp->nsi_pver == NDMP_V4)) 333 free(sp->nsi_mover.nm_tcp_addr); 334 335 ep = sp->nsi_data.nd_env; 336 for (j = 0; j < sp->nsi_data.nd_env_len; j++, ep++) { 337 free(ep->np_name); 338 free(ep->np_value); 339 } 340 free(sp->nsi_data.nd_env); 341 free(sp->nsi_data.nd_tcp_addr); 342 343 if (sp->nsi_pver == NDMP_V2) { 344 np = sp->nsi_data.nd_nlist.nld_nlist; 345 for (j = 0; j < sp->nsi_data.nld_nlist_len; j++, np++) { 346 free(np->nn_name); 347 free(np->nn_dest); 348 } 349 free(sp->nsi_data.nd_nlist.nld_nlist); 350 } else if ((sp->nsi_pver == NDMP_V3) || 351 (sp->nsi_pver == NDMP_V4)) { 352 npv3 = sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist; 353 for (j = 0; j < sp->nsi_data.nld_nlist_len; 354 j++, npv3++) { 355 free(npv3->nn3_opath); 356 free(npv3->nn3_dpath); 357 } 358 free(sp->nsi_data.nd_nlist.nld_dt_v3.dv3_nlist); 359 } 360 } 361 free(sinfo); 362 } 363 364 /* ARGSUSED */ 365 int 366 ndmp_get_stats(ndmp_stat_t *statp) 367 { 368 int opcode = NDMP_GET_STAT; 369 370 (void) mutex_lock(&ndmp_lock); 371 if (!statp) { 372 ndmp_errno = ENDMP_INVALID_ARG; 373 goto err; 374 } 375 376 if (ndmp_door_setup(opcode)) 377 goto err; 378 379 if (ndmp_door_call()) 380 goto err; 381 382 statp->ns_trun = ndmp_door_get_uint32(dec_ctx); 383 statp->ns_twait = ndmp_door_get_uint32(dec_ctx); 384 statp->ns_nbk = ndmp_door_get_uint32(dec_ctx); 385 statp->ns_nrs = ndmp_door_get_uint32(dec_ctx); 386 statp->ns_rfile = ndmp_door_get_uint32(dec_ctx); 387 statp->ns_wfile = ndmp_door_get_uint32(dec_ctx); 388 statp->ns_rdisk = ndmp_door_get_uint64(dec_ctx); 389 statp->ns_wdisk = ndmp_door_get_uint64(dec_ctx); 390 statp->ns_rtape = ndmp_door_get_uint64(dec_ctx); 391 statp->ns_wtape = ndmp_door_get_uint64(dec_ctx); 392 393 if (ndmp_door_fini()) 394 goto err; 395 396 (void) mutex_unlock(&ndmp_lock); 397 return (0); 398 err: 399 (void) mutex_unlock(&ndmp_lock); 400 return (-1); 401 } 402 403 int 404 ndmp_door_status(void) 405 { 406 int opcode = NDMP_GET_DOOR_STATUS; 407 408 (void) mutex_lock(&ndmp_lock); 409 if (ndmp_door_setup(opcode)) 410 goto err; 411 412 if (ndmp_door_call()) 413 goto err; 414 415 if (ndmp_door_fini()) 416 goto err; 417 418 (void) mutex_unlock(&ndmp_lock); 419 return (0); 420 err: 421 (void) mutex_unlock(&ndmp_lock); 422 return (-1); 423 } 424 425 static int 426 ndmp_door_setup(int opcode) 427 { 428 /* Open channel to NDMP service */ 429 if ((ndmp_door_fildes == -1) && 430 (ndmp_door_fildes = open(NDMP_DOOR_SVC, O_RDONLY)) < 0) { 431 ndmp_errno = ENDMP_DOOR_OPEN; 432 return (-1); 433 } 434 435 buf = malloc(NDMP_DOOR_SIZE); 436 if (!buf) { 437 ndmp_errno = ENDMP_MEM_ALLOC; 438 return (-1); 439 } 440 441 enc_ctx = ndmp_door_encode_start(buf, NDMP_DOOR_SIZE); 442 if (enc_ctx == 0) { 443 free(buf); 444 ndmp_errno = ENDMP_DOOR_ENCODE_START; 445 return (-1); 446 } 447 ndmp_door_put_uint32(enc_ctx, opcode); 448 return (0); 449 } 450 451 static int 452 ndmp_door_call(void) 453 { 454 uint32_t used; 455 int rc; 456 457 if ((ndmp_door_encode_finish(enc_ctx, &used)) != 0) { 458 free(buf); 459 ndmp_errno = ENDMP_DOOR_ENCODE_FINISH; 460 return (-1); 461 } 462 463 arg.data_ptr = buf; 464 arg.data_size = used; 465 arg.desc_ptr = NULL; 466 arg.desc_num = 0; 467 arg.rbuf = buf; 468 arg.rsize = NDMP_DOOR_SIZE; 469 470 if (door_call(ndmp_door_fildes, &arg) < 0) { 471 free(buf); 472 ndmp_errno = ENDMP_DOOR_SRV_TIMEOUT; 473 (void) close(ndmp_door_fildes); 474 ndmp_door_fildes = -1; 475 return (-1); 476 } 477 478 dec_ctx = ndmp_door_decode_start(arg.data_ptr, arg.data_size); 479 rc = ndmp_door_get_uint32(dec_ctx); 480 if (rc != NDMP_DOOR_SRV_SUCCESS) { 481 free(buf); 482 ndmp_errno = ENDMP_DOOR_SRV_OPERATION; 483 return (-1); 484 } 485 return (0); 486 } 487 488 static int 489 ndmp_door_fini(void) 490 { 491 if ((ndmp_door_decode_finish(dec_ctx)) != 0) { 492 free(buf); 493 ndmp_errno = ENDMP_DOOR_DECODE_FINISH; 494 return (-1); 495 } 496 free(buf); 497 return (0); 498 } 499