xref: /illumos-gate/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c (revision 36589d6bb0cdae89e166b57b0d64ae56d53247d9)
1*36589d6bSRobert Mustacchi /*
2*36589d6bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*36589d6bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*36589d6bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*36589d6bSRobert Mustacchi  * 1.0 of the CDDL.
6*36589d6bSRobert Mustacchi  *
7*36589d6bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*36589d6bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*36589d6bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*36589d6bSRobert Mustacchi  */
11*36589d6bSRobert Mustacchi 
12*36589d6bSRobert Mustacchi /*
13*36589d6bSRobert Mustacchi  * Copyright 2015 Joyent, Inc.
14*36589d6bSRobert Mustacchi  */
15*36589d6bSRobert Mustacchi 
16*36589d6bSRobert Mustacchi /*
17*36589d6bSRobert Mustacchi  * varpd plugin management
18*36589d6bSRobert Mustacchi  */
19*36589d6bSRobert Mustacchi 
20*36589d6bSRobert Mustacchi #include <libvarpd_impl.h>
21*36589d6bSRobert Mustacchi #include <errno.h>
22*36589d6bSRobert Mustacchi #include <umem.h>
23*36589d6bSRobert Mustacchi #include <assert.h>
24*36589d6bSRobert Mustacchi #include <strings.h>
25*36589d6bSRobert Mustacchi #include <dlfcn.h>
26*36589d6bSRobert Mustacchi #include <link.h>
27*36589d6bSRobert Mustacchi #include <stdio.h>
28*36589d6bSRobert Mustacchi 
29*36589d6bSRobert Mustacchi static varpd_impl_t *varpd_load_handle;
30*36589d6bSRobert Mustacchi static const char *varpd_load_path;
31*36589d6bSRobert Mustacchi static mutex_t varpd_load_lock;
32*36589d6bSRobert Mustacchi static cond_t varpd_load_cv;
33*36589d6bSRobert Mustacchi 
34*36589d6bSRobert Mustacchi int
libvarpd_plugin_comparator(const void * lp,const void * rp)35*36589d6bSRobert Mustacchi libvarpd_plugin_comparator(const void *lp, const void *rp)
36*36589d6bSRobert Mustacchi {
37*36589d6bSRobert Mustacchi 	int ret;
38*36589d6bSRobert Mustacchi 	const varpd_plugin_t *lpp, *rpp;
39*36589d6bSRobert Mustacchi 
40*36589d6bSRobert Mustacchi 	lpp = lp;
41*36589d6bSRobert Mustacchi 	rpp = rp;
42*36589d6bSRobert Mustacchi 
43*36589d6bSRobert Mustacchi 	ret = strcmp(lpp->vpp_name, rpp->vpp_name);
44*36589d6bSRobert Mustacchi 	if (ret > 0)
45*36589d6bSRobert Mustacchi 		return (1);
46*36589d6bSRobert Mustacchi 	if (ret < 0)
47*36589d6bSRobert Mustacchi 		return (-1);
48*36589d6bSRobert Mustacchi 	return (0);
49*36589d6bSRobert Mustacchi }
50*36589d6bSRobert Mustacchi 
51*36589d6bSRobert Mustacchi varpd_plugin_register_t *
libvarpd_plugin_alloc(uint_t version,int * errp)52*36589d6bSRobert Mustacchi libvarpd_plugin_alloc(uint_t version, int *errp)
53*36589d6bSRobert Mustacchi {
54*36589d6bSRobert Mustacchi 	int err;
55*36589d6bSRobert Mustacchi 	varpd_plugin_register_t *vprp;
56*36589d6bSRobert Mustacchi 
57*36589d6bSRobert Mustacchi 	if (errp == NULL)
58*36589d6bSRobert Mustacchi 		errp = &err;
59*36589d6bSRobert Mustacchi 
60*36589d6bSRobert Mustacchi 	if (version != VARPD_VERSION_ONE) {
61*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
62*36589d6bSRobert Mustacchi 		    "unsupported registration version %u - %s\n",
63*36589d6bSRobert Mustacchi 		    version, varpd_load_path);
64*36589d6bSRobert Mustacchi 		*errp = EINVAL;
65*36589d6bSRobert Mustacchi 		return (NULL);
66*36589d6bSRobert Mustacchi 	}
67*36589d6bSRobert Mustacchi 
68*36589d6bSRobert Mustacchi 	vprp = umem_alloc(sizeof (varpd_plugin_register_t), UMEM_DEFAULT);
69*36589d6bSRobert Mustacchi 	if (vprp == NULL) {
70*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
71*36589d6bSRobert Mustacchi 		    "failed to allocate registration handle - %s\n",
72*36589d6bSRobert Mustacchi 		    varpd_load_path);
73*36589d6bSRobert Mustacchi 		*errp = ENOMEM;
74*36589d6bSRobert Mustacchi 		return (NULL);
75*36589d6bSRobert Mustacchi 	}
76*36589d6bSRobert Mustacchi 
77*36589d6bSRobert Mustacchi 	vprp->vpr_version = VARPD_VERSION_ONE;
78*36589d6bSRobert Mustacchi 
79*36589d6bSRobert Mustacchi 	return (vprp);
80*36589d6bSRobert Mustacchi }
81*36589d6bSRobert Mustacchi 
82*36589d6bSRobert Mustacchi void
libvarpd_plugin_free(varpd_plugin_register_t * vprp)83*36589d6bSRobert Mustacchi libvarpd_plugin_free(varpd_plugin_register_t *vprp)
84*36589d6bSRobert Mustacchi {
85*36589d6bSRobert Mustacchi 	umem_free(vprp, sizeof (varpd_plugin_register_t));
86*36589d6bSRobert Mustacchi }
87*36589d6bSRobert Mustacchi 
88*36589d6bSRobert Mustacchi int
libvarpd_plugin_register(varpd_plugin_register_t * vprp)89*36589d6bSRobert Mustacchi libvarpd_plugin_register(varpd_plugin_register_t *vprp)
90*36589d6bSRobert Mustacchi {
91*36589d6bSRobert Mustacchi 	varpd_plugin_t *vpp;
92*36589d6bSRobert Mustacchi 	varpd_plugin_t lookup;
93*36589d6bSRobert Mustacchi 
94*36589d6bSRobert Mustacchi 	vpp = umem_alloc(sizeof (varpd_plugin_t), UMEM_DEFAULT);
95*36589d6bSRobert Mustacchi 	if (vpp == NULL) {
96*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
97*36589d6bSRobert Mustacchi 		    "failed to allocate memory for the varpd_plugin_t - %s\n",
98*36589d6bSRobert Mustacchi 		    varpd_load_path);
99*36589d6bSRobert Mustacchi 		return (ENOMEM);
100*36589d6bSRobert Mustacchi 	}
101*36589d6bSRobert Mustacchi 
102*36589d6bSRobert Mustacchi 	/* Watch out for an evil plugin */
103*36589d6bSRobert Mustacchi 	if (vprp->vpr_version != VARPD_VERSION_ONE) {
104*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
105*36589d6bSRobert Mustacchi 		    "unsupported registration version %u - %s\n",
106*36589d6bSRobert Mustacchi 		    vprp->vpr_version, varpd_load_path);
107*36589d6bSRobert Mustacchi 		return (EINVAL);
108*36589d6bSRobert Mustacchi 	}
109*36589d6bSRobert Mustacchi 
110*36589d6bSRobert Mustacchi 	mutex_enter(&varpd_load_lock);
111*36589d6bSRobert Mustacchi 	if (varpd_load_handle == NULL)
112*36589d6bSRobert Mustacchi 		libvarpd_panic("varpd_load_handle was unexpectedly null");
113*36589d6bSRobert Mustacchi 
114*36589d6bSRobert Mustacchi 	mutex_enter(&varpd_load_handle->vdi_lock);
115*36589d6bSRobert Mustacchi 	lookup.vpp_name = vprp->vpr_name;
116*36589d6bSRobert Mustacchi 	if (avl_find(&varpd_load_handle->vdi_plugins, &lookup, NULL) != NULL) {
117*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
118*36589d6bSRobert Mustacchi 		    "module already exists with requested name '%s' - %s\n",
119*36589d6bSRobert Mustacchi 		    vprp->vpr_name, varpd_load_path);
120*36589d6bSRobert Mustacchi 		mutex_exit(&varpd_load_handle->vdi_lock);
121*36589d6bSRobert Mustacchi 		mutex_exit(&varpd_load_lock);
122*36589d6bSRobert Mustacchi 		umem_free(vpp, sizeof (varpd_plugin_t));
123*36589d6bSRobert Mustacchi 		return (EEXIST);
124*36589d6bSRobert Mustacchi 	}
125*36589d6bSRobert Mustacchi 	vpp->vpp_name = strdup(vprp->vpr_name);
126*36589d6bSRobert Mustacchi 	if (vpp->vpp_name == NULL) {
127*36589d6bSRobert Mustacchi 		(void) fprintf(stderr,
128*36589d6bSRobert Mustacchi 		    "failed to allocate memory to duplicate name - %s\n",
129*36589d6bSRobert Mustacchi 		    varpd_load_path);
130*36589d6bSRobert Mustacchi 		mutex_exit(&varpd_load_handle->vdi_lock);
131*36589d6bSRobert Mustacchi 		mutex_exit(&varpd_load_lock);
132*36589d6bSRobert Mustacchi 		umem_free(vpp, sizeof (varpd_plugin_t));
133*36589d6bSRobert Mustacchi 		return (ENOMEM);
134*36589d6bSRobert Mustacchi 	}
135*36589d6bSRobert Mustacchi 
136*36589d6bSRobert Mustacchi 	vpp->vpp_mode = vprp->vpr_mode;
137*36589d6bSRobert Mustacchi 	vpp->vpp_ops = vprp->vpr_ops;
138*36589d6bSRobert Mustacchi 	if (mutex_init(&vpp->vpp_lock, USYNC_THREAD | LOCK_ERRORCHECK,
139*36589d6bSRobert Mustacchi 	    NULL) != 0)
140*36589d6bSRobert Mustacchi 		libvarpd_panic("failed to create plugin's vpp_lock");
141*36589d6bSRobert Mustacchi 	vpp->vpp_active = 0;
142*36589d6bSRobert Mustacchi 	avl_add(&varpd_load_handle->vdi_plugins, vpp);
143*36589d6bSRobert Mustacchi 	mutex_exit(&varpd_load_handle->vdi_lock);
144*36589d6bSRobert Mustacchi 	mutex_exit(&varpd_load_lock);
145*36589d6bSRobert Mustacchi 
146*36589d6bSRobert Mustacchi 	return (0);
147*36589d6bSRobert Mustacchi }
148*36589d6bSRobert Mustacchi 
149*36589d6bSRobert Mustacchi varpd_plugin_t *
libvarpd_plugin_lookup(varpd_impl_t * vip,const char * name)150*36589d6bSRobert Mustacchi libvarpd_plugin_lookup(varpd_impl_t *vip, const char *name)
151*36589d6bSRobert Mustacchi {
152*36589d6bSRobert Mustacchi 	varpd_plugin_t lookup, *ret;
153*36589d6bSRobert Mustacchi 
154*36589d6bSRobert Mustacchi 	lookup.vpp_name = name;
155*36589d6bSRobert Mustacchi 	mutex_enter(&vip->vdi_lock);
156*36589d6bSRobert Mustacchi 	ret = avl_find(&vip->vdi_plugins, &lookup, NULL);
157*36589d6bSRobert Mustacchi 	mutex_exit(&vip->vdi_lock);
158*36589d6bSRobert Mustacchi 
159*36589d6bSRobert Mustacchi 	return (ret);
160*36589d6bSRobert Mustacchi }
161*36589d6bSRobert Mustacchi 
162*36589d6bSRobert Mustacchi /* ARGSUSED */
163*36589d6bSRobert Mustacchi static int
libvarpd_plugin_load_cb(varpd_impl_t * vip,const char * path,void * unused)164*36589d6bSRobert Mustacchi libvarpd_plugin_load_cb(varpd_impl_t *vip, const char *path, void *unused)
165*36589d6bSRobert Mustacchi {
166*36589d6bSRobert Mustacchi 	void *dlp;
167*36589d6bSRobert Mustacchi 
168*36589d6bSRobert Mustacchi 	varpd_load_path = path;
169*36589d6bSRobert Mustacchi 	dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW);
170*36589d6bSRobert Mustacchi 	if (dlp == NULL)
171*36589d6bSRobert Mustacchi 		(void) fprintf(stderr, "dlopen failed - %s\n", path);
172*36589d6bSRobert Mustacchi 	path = NULL;
173*36589d6bSRobert Mustacchi 
174*36589d6bSRobert Mustacchi 	return (0);
175*36589d6bSRobert Mustacchi }
176*36589d6bSRobert Mustacchi 
177*36589d6bSRobert Mustacchi int
libvarpd_plugin_load(varpd_handle_t * vph,const char * path)178*36589d6bSRobert Mustacchi libvarpd_plugin_load(varpd_handle_t *vph, const char *path)
179*36589d6bSRobert Mustacchi {
180*36589d6bSRobert Mustacchi 	int ret = 0;
181*36589d6bSRobert Mustacchi 	varpd_impl_t *vip = (varpd_impl_t *)vph;
182*36589d6bSRobert Mustacchi 
183*36589d6bSRobert Mustacchi 	if (vip == NULL || path == NULL)
184*36589d6bSRobert Mustacchi 		return (EINVAL);
185*36589d6bSRobert Mustacchi 	mutex_enter(&varpd_load_lock);
186*36589d6bSRobert Mustacchi 	while (varpd_load_handle != NULL)
187*36589d6bSRobert Mustacchi 		(void) cond_wait(&varpd_load_cv, &varpd_load_lock);
188*36589d6bSRobert Mustacchi 	varpd_load_handle = vip;
189*36589d6bSRobert Mustacchi 	mutex_exit(&varpd_load_lock);
190*36589d6bSRobert Mustacchi 
191*36589d6bSRobert Mustacchi 	ret = libvarpd_dirwalk(vip, path, ".so", libvarpd_plugin_load_cb, NULL);
192*36589d6bSRobert Mustacchi 
193*36589d6bSRobert Mustacchi 	mutex_enter(&varpd_load_lock);
194*36589d6bSRobert Mustacchi 	varpd_load_handle = NULL;
195*36589d6bSRobert Mustacchi 	(void) cond_signal(&varpd_load_cv);
196*36589d6bSRobert Mustacchi 	mutex_exit(&varpd_load_lock);
197*36589d6bSRobert Mustacchi 
198*36589d6bSRobert Mustacchi 	return (ret);
199*36589d6bSRobert Mustacchi }
200*36589d6bSRobert Mustacchi 
201*36589d6bSRobert Mustacchi int
libvarpd_plugin_walk(varpd_handle_t * vph,libvarpd_plugin_walk_f func,void * arg)202*36589d6bSRobert Mustacchi libvarpd_plugin_walk(varpd_handle_t *vph, libvarpd_plugin_walk_f func,
203*36589d6bSRobert Mustacchi     void *arg)
204*36589d6bSRobert Mustacchi {
205*36589d6bSRobert Mustacchi 	varpd_impl_t *vip = (varpd_impl_t *)vph;
206*36589d6bSRobert Mustacchi 	varpd_plugin_t *vpp;
207*36589d6bSRobert Mustacchi 
208*36589d6bSRobert Mustacchi 	mutex_enter(&vip->vdi_lock);
209*36589d6bSRobert Mustacchi 	for (vpp = avl_first(&vip->vdi_plugins); vpp != NULL;
210*36589d6bSRobert Mustacchi 	    vpp = AVL_NEXT(&vip->vdi_plugins, vpp)) {
211*36589d6bSRobert Mustacchi 		if (func(vph, vpp->vpp_name, arg) != 0) {
212*36589d6bSRobert Mustacchi 			mutex_exit(&vip->vdi_lock);
213*36589d6bSRobert Mustacchi 			return (1);
214*36589d6bSRobert Mustacchi 		}
215*36589d6bSRobert Mustacchi 	}
216*36589d6bSRobert Mustacchi 	mutex_exit(&vip->vdi_lock);
217*36589d6bSRobert Mustacchi 	return (0);
218*36589d6bSRobert Mustacchi }
219*36589d6bSRobert Mustacchi 
220*36589d6bSRobert Mustacchi void
libvarpd_plugin_init(void)221*36589d6bSRobert Mustacchi libvarpd_plugin_init(void)
222*36589d6bSRobert Mustacchi {
223*36589d6bSRobert Mustacchi 	if (mutex_init(&varpd_load_lock, USYNC_THREAD | LOCK_RECURSIVE |
224*36589d6bSRobert Mustacchi 	    LOCK_ERRORCHECK, NULL) != 0)
225*36589d6bSRobert Mustacchi 		libvarpd_panic("failed to create varpd_load_lock");
226*36589d6bSRobert Mustacchi 
227*36589d6bSRobert Mustacchi 	if (cond_init(&varpd_load_cv, USYNC_THREAD, NULL) != 0)
228*36589d6bSRobert Mustacchi 		libvarpd_panic("failed to create varpd_load_cv");
229*36589d6bSRobert Mustacchi 
230*36589d6bSRobert Mustacchi 	varpd_load_handle = NULL;
231*36589d6bSRobert Mustacchi }
232*36589d6bSRobert Mustacchi 
233*36589d6bSRobert Mustacchi void
libvarpd_plugin_fini(void)234*36589d6bSRobert Mustacchi libvarpd_plugin_fini(void)
235*36589d6bSRobert Mustacchi {
236*36589d6bSRobert Mustacchi 	assert(varpd_load_handle == NULL);
237*36589d6bSRobert Mustacchi 	if (mutex_destroy(&varpd_load_lock) != 0)
238*36589d6bSRobert Mustacchi 		libvarpd_panic("failed to destroy varpd_load_lock");
239*36589d6bSRobert Mustacchi 	if (cond_destroy(&varpd_load_cv) != 0)
240*36589d6bSRobert Mustacchi 		libvarpd_panic("failed to destroy varpd_load_cv");
241*36589d6bSRobert Mustacchi }
242*36589d6bSRobert Mustacchi 
243*36589d6bSRobert Mustacchi void
libvarpd_plugin_prefork(void)244*36589d6bSRobert Mustacchi libvarpd_plugin_prefork(void)
245*36589d6bSRobert Mustacchi {
246*36589d6bSRobert Mustacchi 	mutex_enter(&varpd_load_lock);
247*36589d6bSRobert Mustacchi 	while (varpd_load_handle != NULL)
248*36589d6bSRobert Mustacchi 		(void) cond_wait(&varpd_load_cv, &varpd_load_lock);
249*36589d6bSRobert Mustacchi }
250*36589d6bSRobert Mustacchi 
251*36589d6bSRobert Mustacchi void
libvarpd_plugin_postfork(void)252*36589d6bSRobert Mustacchi libvarpd_plugin_postfork(void)
253*36589d6bSRobert Mustacchi {
254*36589d6bSRobert Mustacchi 	(void) cond_signal(&varpd_load_cv);
255*36589d6bSRobert Mustacchi 	mutex_exit(&varpd_load_lock);
256*36589d6bSRobert Mustacchi }
257