1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <fcntl.h> 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <errno.h> 32 #include <sys/types.h> 33 #include <sys/sysevent.h> 34 #include <libsysevent.h> 35 #include <sys/vlds.h> 36 #include "libds.h" 37 38 #define PTRTOUINT64(ptr) ((uint64_t)((uintptr_t)(ptr))) 39 static char vlds_device[] = 40 "/devices/virtual-devices@100/channel-devices@200/" 41 "virtual-domain-service@0:vlds"; 42 43 typedef struct dslibentry { 44 ds_hdl_t dsl_hdl; 45 uint32_t dsl_flags; 46 uint32_t dsl_tflags; 47 char *dsl_service; 48 ds_ops_t dsl_ops; 49 } dslibentry_t; 50 51 /* dsl_tflags */ 52 #define DSL_ENTRY_INUSE 0x0001 /* handle is currently active */ 53 54 #define MIN_DSLIB_ENTRIES 64 55 static dslibentry_t *dslibtab; 56 static int ndslib; 57 58 /* 59 * Lock to protect the dslibtab table. We only need to protect this 60 * table for those functions which actually look at or modify the table: 61 * service registration (ds_svc_reg/ds_clnt_reg), service unregistration 62 * (ds_hdl_unreg) or during callbacks (ds_recv) 63 */ 64 static mutex_t dslib_lock; 65 66 static int ds_fd = -1; 67 68 static char *ds_sid_name = "vlds"; 69 70 static evchan_t *ds_evchan; 71 72 /* 73 * Static functions internal to dslib. 74 */ 75 static dslibentry_t *ds_hdl_to_dslibentry(ds_hdl_t hdl); 76 static dslibentry_t *ds_new_dslibentry(void); 77 static uint_t ds_service_count(char *service, boolean_t is_client); 78 static dslibentry_t *ds_lookup_dslibentry(char *service, boolean_t is_client); 79 static dslibentry_t *ds_register_dslibentry(ds_hdl_t hdl, char *service, 80 boolean_t is_client); 81 static void ds_free_dslibentry(dslibentry_t *dsp, int force_unreg); 82 static int ds_recv(sysevent_t *sep, void *arg); 83 static void ds_string_arg(vlds_string_t *dsp, char *str); 84 static int ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags); 85 86 static dslibentry_t * 87 ds_hdl_to_dslibentry(ds_hdl_t hdl) 88 { 89 int i; 90 dslibentry_t *dsp; 91 92 for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) { 93 if (hdl == dsp->dsl_hdl) 94 return (dsp); 95 } 96 return (NULL); 97 } 98 99 static dslibentry_t * 100 ds_new_dslibentry(void) 101 { 102 int newndslib; 103 dslibentry_t *dsp; 104 105 if ((dsp = ds_hdl_to_dslibentry(0)) != NULL) 106 return (dsp); 107 108 /* double the size */ 109 newndslib = ndslib << 1; 110 if ((dslibtab = realloc(dslibtab, newndslib * sizeof (dslibentry_t))) 111 == NULL) 112 return (NULL); 113 dsp = &dslibtab[ndslib]; 114 (void) memset(dsp, 0, (newndslib - ndslib) * sizeof (dslibentry_t)); 115 ndslib = newndslib; 116 return (dsp); 117 } 118 119 static uint_t 120 ds_service_count(char *service, boolean_t is_client) 121 { 122 int i; 123 dslibentry_t *dsp; 124 uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0; 125 uint_t count = 0; 126 127 for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) { 128 if (dsp->dsl_hdl != 0 && 129 strcmp(dsp->dsl_service, service) == 0 && 130 (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) { 131 count++; 132 } 133 } 134 return (count); 135 } 136 137 static dslibentry_t * 138 ds_lookup_dslibentry(char *service, boolean_t is_client) 139 { 140 int i; 141 dslibentry_t *dsp; 142 uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0; 143 144 for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) { 145 if (dsp->dsl_hdl != 0 && 146 strcmp(dsp->dsl_service, service) == 0 && 147 (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) { 148 return (dsp); 149 } 150 } 151 return (NULL); 152 } 153 154 static dslibentry_t * 155 ds_register_dslibentry(ds_hdl_t hdl, char *service, boolean_t is_client) 156 { 157 dslibentry_t *dsp, *orig_dsp; 158 159 if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) { 160 dsp->dsl_tflags |= DSL_ENTRY_INUSE; 161 return (dsp); 162 } 163 164 if ((orig_dsp = ds_lookup_dslibentry(service, is_client)) == NULL) { 165 return (NULL); 166 } 167 168 if ((orig_dsp->dsl_tflags & DSL_ENTRY_INUSE) == 0) { 169 /* use the original structure entry */ 170 orig_dsp->dsl_tflags |= DSL_ENTRY_INUSE; 171 orig_dsp->dsl_hdl = hdl; 172 return (orig_dsp); 173 } 174 175 /* allocate a new structure entry */ 176 if ((dsp = ds_new_dslibentry()) == NULL) 177 return (NULL); 178 179 *dsp = *orig_dsp; 180 dsp->dsl_service = strdup(orig_dsp->dsl_service); 181 dsp->dsl_hdl = hdl; 182 return (dsp); 183 } 184 185 /* 186 * Want to leave an entry in the dslib table even though all the 187 * handles may have been unregistered for it. 188 */ 189 static void 190 ds_free_dslibentry(dslibentry_t *dsp, int force_unreg) 191 { 192 uint_t nhdls; 193 194 /* 195 * Find out if we have 1 or 2 or more handles for the given 196 * service. Having one implies that we want to leave the entry 197 * intact but marked as not in use unless this is a ds_unreg_hdl 198 * (force_unreg is true). 199 */ 200 nhdls = ds_service_count(dsp->dsl_service, 201 (dsp->dsl_flags & VLDS_REG_CLIENT) != 0); 202 203 if ((nhdls == 1 && force_unreg) || nhdls >= 2) { 204 dsp->dsl_hdl = 0; 205 if (dsp->dsl_service) { 206 free(dsp->dsl_service); 207 } 208 (void) memset(dsp, 0, sizeof (dslibentry_t)); 209 } else if (nhdls == 1) { 210 dsp->dsl_tflags &= ~DSL_ENTRY_INUSE; 211 } 212 } 213 214 /*ARGSUSED*/ 215 static int 216 ds_recv(sysevent_t *sep, void *arg) 217 { 218 nvlist_t *nvl; 219 uint64_t hdl; 220 ds_ver_t ver; 221 ds_domain_hdl_t dhdl; 222 uchar_t *bufp; 223 boolean_t is_client; 224 uint_t buflen; 225 char *subclass; 226 char *servicep; 227 dslibentry_t *dsp; 228 ds_cb_arg_t cb_arg; 229 230 subclass = sysevent_get_subclass_name(sep); 231 if (sysevent_get_attr_list(sep, &nvl) != 0) { 232 return (0); 233 } 234 235 if (nvlist_lookup_uint64(nvl, VLDS_HDL, &hdl) == 0) { 236 if (strcmp(subclass, ESC_VLDS_REGISTER) == 0) { 237 void (*reg_cb)(ds_hdl_t, ds_cb_arg_t, ds_ver_t *, 238 ds_domain_hdl_t) = NULL; 239 240 if (nvlist_lookup_string(nvl, VLDS_SERVICE_ID, 241 &servicep) == 0 && 242 nvlist_lookup_boolean_value(nvl, VLDS_ISCLIENT, 243 &is_client) == 0) { 244 (void) mutex_lock(&dslib_lock); 245 if ((dsp = ds_register_dslibentry(hdl, 246 servicep, is_client)) != NULL) { 247 reg_cb = dsp->dsl_ops.ds_reg_cb; 248 cb_arg = dsp->dsl_ops.cb_arg; 249 } 250 (void) mutex_unlock(&dslib_lock); 251 if (reg_cb != NULL && 252 nvlist_lookup_uint64(nvl, VLDS_DOMAIN_HDL, 253 &dhdl) == 0 && 254 nvlist_lookup_uint16(nvl, VLDS_VER_MAJOR, 255 &ver.major) == 0 && 256 nvlist_lookup_uint16(nvl, VLDS_VER_MINOR, 257 &ver.minor) == 0) { 258 (reg_cb)((ds_hdl_t)hdl, cb_arg, &ver, 259 dhdl); 260 } 261 } 262 } else if (strcmp(subclass, ESC_VLDS_UNREGISTER) == 0) { 263 void (*unreg_cb)(ds_hdl_t, ds_cb_arg_t) = NULL; 264 265 (void) mutex_lock(&dslib_lock); 266 if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) { 267 unreg_cb = dsp->dsl_ops.ds_unreg_cb; 268 cb_arg = dsp->dsl_ops.cb_arg; 269 ds_free_dslibentry(dsp, 0); 270 } 271 (void) mutex_unlock(&dslib_lock); 272 if (unreg_cb != NULL) { 273 (unreg_cb)((ds_hdl_t)hdl, cb_arg); 274 } 275 } else if (strcmp(subclass, ESC_VLDS_DATA) == 0) { 276 void (*data_cb)(ds_hdl_t, ds_cb_arg_t, void *, 277 size_t) = NULL; 278 279 (void) mutex_lock(&dslib_lock); 280 if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) { 281 data_cb = dsp->dsl_ops.ds_data_cb; 282 cb_arg = dsp->dsl_ops.cb_arg; 283 } 284 (void) mutex_unlock(&dslib_lock); 285 if (data_cb != NULL && 286 nvlist_lookup_byte_array(nvl, VLDS_DATA, &bufp, 287 &buflen) == 0) { 288 (data_cb)((ds_hdl_t)hdl, cb_arg, bufp, buflen); 289 } 290 } 291 } 292 nvlist_free(nvl); 293 return (0); 294 } 295 296 static void 297 ds_string_arg(vlds_string_t *dsp, char *str) 298 { 299 if (str == NULL) { 300 dsp->vlds_strp = 0; 301 dsp->vlds_strlen = 0; 302 } else { 303 dsp->vlds_strp = PTRTOUINT64(str); 304 dsp->vlds_strlen = strlen(str) + 1; 305 } 306 } 307 308 static int 309 ds_init_sysev(void) 310 { 311 char evchan_name[MAX_CHNAME_LEN]; 312 313 (void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, (int)getpid()); 314 if (sysevent_evc_bind(evchan_name, &ds_evchan, 0) != 0) { 315 return (errno); 316 } 317 if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS, 318 ds_recv, NULL, 0) != 0) { 319 (void) sysevent_evc_unbind(ds_evchan); 320 ds_evchan = NULL; 321 return (errno); 322 } 323 return (0); 324 } 325 326 int 327 ds_init(void) 328 { 329 if (ds_fd >= 0) 330 return (0); 331 332 if ((ds_fd = open(vlds_device, 0)) < 0) 333 return (errno); 334 335 if (dslibtab == NULL) { 336 dslibtab = malloc(sizeof (dslibentry_t) * MIN_DSLIB_ENTRIES); 337 if (dslibtab == NULL) 338 return (errno = ENOMEM); 339 ndslib = MIN_DSLIB_ENTRIES; 340 (void) memset(dslibtab, 0, sizeof (dslibentry_t) * ndslib); 341 } 342 343 (void) mutex_init(&dslib_lock, USYNC_THREAD, NULL); 344 return (0); 345 } 346 347 static int 348 ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags) 349 { 350 dslibentry_t *dsp; 351 vlds_svc_reg_arg_t vlds_arg; 352 vlds_cap_t vlds_cap; 353 vlds_ver_t vlds_vers[VLDS_MAX_VERS]; 354 uint64_t hdl_arg; 355 ds_hdl_t hdl; 356 uint_t nhdls; 357 int i; 358 359 if (cap == NULL || ops == NULL || cap->svc_id == NULL || 360 cap->vers == NULL || (flags & (~VLDS_REG_CLIENT)) != 0) { 361 return (errno = EINVAL); 362 } 363 364 if (cap->nvers > VLDS_MAX_VERS) { 365 return (errno = EINVAL); 366 } 367 368 if (ds_fd < 0 && (errno = ds_init()) != 0) { 369 return (errno); 370 } 371 372 if (ds_hdl_lookup(cap->svc_id, (flags & VLDS_REG_CLIENT), NULL, 1, 373 &nhdls) == 0 && nhdls == 1) { 374 return (errno = EALREADY); 375 } 376 377 (void) mutex_lock(&dslib_lock); 378 if ((dsp = ds_new_dslibentry()) == NULL) { 379 (void) mutex_unlock(&dslib_lock); 380 return (errno = ENOMEM); 381 } 382 383 /* Setup device driver capability structure. */ 384 385 /* service string */ 386 ds_string_arg(&vlds_cap.vlds_service, cap->svc_id); 387 388 /* version array */ 389 for (i = 0; i < cap->nvers; i++) { 390 vlds_vers[i].vlds_major = cap->vers[i].major; 391 vlds_vers[i].vlds_minor = cap->vers[i].minor; 392 } 393 vlds_cap.vlds_versp = PTRTOUINT64(vlds_vers); 394 vlds_cap.vlds_nver = cap->nvers; 395 396 /* 397 * Format args for VLDS_SVC_REG ioctl. 398 */ 399 400 vlds_arg.vlds_capp = PTRTOUINT64(&vlds_cap); 401 402 /* op flags */ 403 if (ops->ds_reg_cb != NULL) 404 flags |= VLDS_REGCB_VALID; 405 if (ops->ds_unreg_cb != NULL) 406 flags |= VLDS_UNREGCB_VALID; 407 if (ops->ds_data_cb != NULL) 408 flags |= VLDS_DATACB_VALID; 409 vlds_arg.vlds_reg_flags = flags; 410 411 /* returned handle */ 412 vlds_arg.vlds_hdlp = PTRTOUINT64(&hdl_arg); 413 414 if (ioctl(ds_fd, VLDS_SVC_REG, &vlds_arg) < 0) { 415 (void) mutex_unlock(&dslib_lock); 416 return (errno); 417 } 418 419 /* 420 * Setup user callback sysevent channel. 421 */ 422 if ((flags & VLDS_ANYCB_VALID) != 0 && ds_evchan == NULL && 423 ds_init_sysev() != 0) { 424 (void) mutex_unlock(&dslib_lock); 425 (void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg); 426 return (errno); 427 } 428 429 hdl = hdl_arg; 430 431 /* 432 * Set entry values in dslibtab. 433 */ 434 dsp->dsl_hdl = hdl; 435 dsp->dsl_flags = flags; 436 dsp->dsl_tflags = 0; 437 dsp->dsl_service = strdup(cap->svc_id); 438 dsp->dsl_ops = *ops; 439 (void) mutex_unlock(&dslib_lock); 440 return (0); 441 } 442 443 /* 444 * Registers a service provider. Kicks off the handshake with other 445 * domain(s) to announce servce. Callback events are as described above. 446 */ 447 int 448 ds_svc_reg(ds_capability_t *cap, ds_ops_t *ops) 449 { 450 return (ds_register(cap, ops, 0)); 451 } 452 453 /* 454 * Registers interest in a service from a specific domain. When that 455 * service is registered, the register callback is invoked. When that 456 * service is unregistered, the unregister callback is invoked. When 457 * data is received, the receive data callback is invoked. 458 */ 459 int 460 ds_clnt_reg(ds_capability_t *cap, ds_ops_t *ops) 461 { 462 return (ds_register(cap, ops, VLDS_REG_CLIENT)); 463 } 464 465 /* 466 * Given a service name and type, returns the existing handle(s), if 467 * one or more exist. This could be used to poll for the connection being 468 * registered or unregistered, rather than using the register/unregister 469 * callbacks. 470 */ 471 int 472 ds_hdl_lookup(char *service, boolean_t is_client, ds_hdl_t *hdlsp, 473 uint_t maxhdls, uint_t *nhdlsp) 474 { 475 vlds_hdl_lookup_arg_t vlds_arg; 476 uint64_t nhdls_arg; 477 478 errno = 0; 479 if (ds_fd < 0) { 480 return (errno = EBADF); 481 } 482 483 if (service == NULL) { 484 return (errno = EINVAL); 485 } 486 487 ds_string_arg(&vlds_arg.vlds_service, service); 488 vlds_arg.vlds_isclient = is_client ? VLDS_REG_CLIENT : 0; 489 vlds_arg.vlds_hdlsp = PTRTOUINT64(hdlsp); 490 vlds_arg.vlds_maxhdls = maxhdls; 491 vlds_arg.vlds_nhdlsp = PTRTOUINT64(&nhdls_arg); 492 493 if (ioctl(ds_fd, VLDS_HDL_LOOKUP, &vlds_arg) < 0) { 494 return (errno); 495 } 496 497 *nhdlsp = nhdls_arg; 498 return (0); 499 } 500 501 /* 502 * Given a handle, return its associated domain. 503 */ 504 int 505 ds_domain_lookup(ds_hdl_t hdl, ds_domain_hdl_t *dhdlp) 506 { 507 vlds_dmn_lookup_arg_t vlds_arg; 508 uint64_t dhdl_arg; 509 510 if (ds_fd < 0) { 511 return (errno = EBADF); 512 } 513 514 vlds_arg.vlds_hdl = hdl; 515 vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg); 516 517 if (ioctl(ds_fd, VLDS_DMN_LOOKUP, &vlds_arg) < 0) { 518 return (errno); 519 } 520 521 if (dhdlp) { 522 *dhdlp = dhdl_arg; 523 } 524 525 return (0); 526 } 527 528 /* 529 * Unregisters either a service or an interest in that service 530 * indicated by the supplied handle. 531 */ 532 int 533 ds_unreg_hdl(ds_hdl_t hdl) 534 { 535 dslibentry_t *dsp; 536 vlds_unreg_hdl_arg_t vlds_arg; 537 538 (void) mutex_lock(&dslib_lock); 539 if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) { 540 ds_free_dslibentry(dsp, 1); 541 } 542 (void) mutex_unlock(&dslib_lock); 543 544 if (ds_fd >= 0) { 545 vlds_arg.vlds_hdl = hdl; 546 (void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg); 547 } 548 549 return (0); 550 } 551 552 /* 553 * Send data to the appropriate service provider or client 554 * indicated by the provided handle. The sender will block 555 * until the message has been sent. There is no guarantee 556 * that multiple calls to ds_send_msg by the same thread 557 * will result in the data showing up at the receiver in 558 * the same order as sent. If multiple messages are required, 559 * it will be up to the sender and receiver to implement a 560 * protocol. 561 */ 562 int 563 ds_send_msg(ds_hdl_t hdl, void *buf, size_t buflen) 564 { 565 vlds_send_msg_arg_t vlds_arg; 566 567 if (ds_fd < 0) { 568 return (errno = EBADF); 569 } 570 571 vlds_arg.vlds_hdl = hdl; 572 vlds_arg.vlds_bufp = PTRTOUINT64(buf); 573 vlds_arg.vlds_buflen = buflen; 574 575 if (ioctl(ds_fd, VLDS_SEND_MSG, &vlds_arg) < 0) { 576 return (errno); 577 } 578 579 return (0); 580 } 581 582 /* 583 * Receive data from the appropriate service provider or client 584 * indicated by the provided handle. The sender will block 585 * until a message has been received. 586 */ 587 int 588 ds_recv_msg(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen) 589 { 590 vlds_recv_msg_arg_t vlds_arg; 591 uint64_t msglen_arg; 592 593 if (ds_fd < 0) { 594 return (errno = EBADF); 595 } 596 597 vlds_arg.vlds_hdl = hdl; 598 vlds_arg.vlds_bufp = PTRTOUINT64(buf); 599 vlds_arg.vlds_buflen = buflen; 600 vlds_arg.vlds_msglenp = PTRTOUINT64(&msglen_arg); 601 602 if (ioctl(ds_fd, VLDS_RECV_MSG, &vlds_arg) < 0) { 603 if (errno == EFBIG && msglen) { 604 *msglen = msglen_arg; 605 } 606 return (errno); 607 } 608 609 if (msglen) { 610 *msglen = msglen_arg; 611 } 612 613 return (0); 614 } 615 616 int 617 ds_isready(ds_hdl_t hdl, boolean_t *is_ready) 618 { 619 vlds_hdl_isready_arg_t vlds_arg; 620 uint64_t is_ready_arg; 621 622 if (ds_fd < 0) { 623 return (errno = EBADF); 624 } 625 626 vlds_arg.vlds_hdl = hdl; 627 vlds_arg.vlds_isreadyp = PTRTOUINT64(&is_ready_arg); 628 629 if (ioctl(ds_fd, VLDS_HDL_ISREADY, &vlds_arg) < 0) { 630 return (errno); 631 } 632 633 *is_ready = (is_ready_arg != 0); 634 return (0); 635 } 636 637 /* 638 * Given a domain name, return its associated domain handle. 639 */ 640 int 641 ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp) 642 { 643 vlds_dom_nam2hdl_arg_t vlds_arg; 644 uint64_t dhdl_arg; 645 646 if (ds_fd < 0) { 647 return (errno = EBADF); 648 } 649 650 ds_string_arg(&vlds_arg.vlds_domain_name, domain_name); 651 vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg); 652 653 if (ioctl(ds_fd, VLDS_DOM_NAM2HDL, &vlds_arg) < 0) { 654 return (errno); 655 } 656 657 if (dhdlp) { 658 *dhdlp = dhdl_arg; 659 } 660 661 return (0); 662 } 663 664 /* 665 * Given a domain handle, return its associated domain name. 666 */ 667 int 668 ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char *domain_name, uint_t maxnamlen) 669 { 670 vlds_dom_hdl2nam_arg_t vlds_arg; 671 672 if (ds_fd < 0) { 673 return (errno = EBADF); 674 } 675 676 vlds_arg.vlds_dhdl = dhdl; 677 vlds_arg.vlds_domain_name.vlds_strp = PTRTOUINT64(domain_name); 678 vlds_arg.vlds_domain_name.vlds_strlen = maxnamlen; 679 680 if (ioctl(ds_fd, VLDS_DOM_HDL2NAM, &vlds_arg) < 0) { 681 return (errno); 682 } 683 684 return (0); 685 } 686 687 void 688 ds_unreg_svc(char *service, boolean_t is_client) 689 { 690 ds_hdl_t hdl; 691 uint_t nhdls; 692 693 while (ds_hdl_lookup(service, is_client, &hdl, 1, &nhdls) == 0 && 694 nhdls == 1) { 695 (void) ds_unreg_hdl(hdl); 696 } 697 } 698 699 void 700 ds_fini(void) 701 { 702 int i; 703 dslibentry_t *dsp; 704 705 if (ds_fd >= 0) { 706 (void) close(ds_fd); 707 ds_fd = -1; 708 } 709 if (ds_evchan) { 710 (void) sysevent_evc_unsubscribe(ds_evchan, ds_sid_name); 711 (void) sysevent_evc_unbind(ds_evchan); 712 ds_evchan = NULL; 713 } 714 if (ndslib > 0) { 715 (void) mutex_lock(&dslib_lock); 716 for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) { 717 if (dsp->dsl_hdl == 0) 718 continue; 719 if (dsp->dsl_service) { 720 free(dsp->dsl_service); 721 } 722 } 723 free(dslibtab); 724 ndslib = 0; 725 dslibtab = NULL; 726 (void) mutex_unlock(&dslib_lock); 727 (void) mutex_destroy(&dslib_lock); 728 } 729 } 730