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