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