1 /*-
2  * Copyright (c) 2002 Jordan DeLong
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of contributors may be
14  *    used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "editor.h"
30 #include <dlfcn.h>
31 
32 static LIST_HEAD(, module) module_list = LIST_HEAD_INITIALIZER(module_list);
33 
module_unload(module_t * module)34 static void module_unload(module_t *module) {
35 	u_char symname[512];
36 	void (*shutdown)();
37 
38 	/* call the module's shutdown routine */
39 	if (strlcpy(symname, SYM_PREFIX, sizeof(symname)) >= sizeof(symname))
40 		goto toobad;
41 	if (strlcat(symname, module->name, sizeof(symname)) >= sizeof(symname))
42 		goto toobad;
43 	if (strlcat(symname, "_shutdown", sizeof(symname)) >= sizeof(symname))
44 		goto toobad;
45 	shutdown = dlsym(module->hnd, symname);
46 	if (shutdown)
47 		shutdown();
48 
49 toobad:
50 #ifndef USE_DMALLOC
51 	dlclose(module->hnd);
52 #endif
53 	LIST_REMOVE(module, m_list);
54 	free(module->name);
55 	free(module);
56 }
57 
module_shutdown()58 void module_shutdown() {
59 	while (!LIST_EMPTY(&module_list))
60 		module_unload(LIST_FIRST(&module_list));
61 }
62 
loadmod(u_char * name)63 static __inline void *loadmod(u_char *name) {
64 	u_char fullpath[PATH_MAX];
65 	char *modpath, *tmp;
66 	char *path, *expath;
67 	void *hnd;
68 
69 	modpath = ckstrdup(MODULE_PATH);
70 	tmp = modpath;
71 
72 	hnd = NULL;
73 	while ((path = strsep(&tmp, ":")) != NULL && !hnd) {
74 		expath = tilde_expand(path);
75 
76 		if (snprintf(fullpath, sizeof(fullpath), "%s/%s.so", expath,
77 				name) >= sizeof(fullpath)) {
78 			warnx("path to module exceeds PATH_MAX");
79 			goto next;
80 		}
81 
82 		/*
83 		 * the only way to determine why dlopen failed is by
84 		 * calling dlerror; so try an access first so we don't
85 		 * print dlerrors for nonexistant files.
86 		 */
87 		if (access(fullpath, R_OK) != 0)
88 			goto next;
89 
90 		hnd = dlopen(fullpath, RTLD_LAZY);
91 		if (!hnd)
92 			warnx("failed dlopen for %s: %s", fullpath, dlerror());
93 next:
94 		free(expath);
95 	}
96 	free(modpath);
97 
98 	return hnd;
99 }
100 
module_load(u_char * name)101 module_t *module_load(u_char *name) {
102 	u_char symname[512];
103 	module_t *module;
104 	int (*init)();
105 	void *hnd;
106 
107 	hnd = loadmod(name);
108 	if (!hnd)
109 		return NULL;
110 
111 	/* call the init routine, bail if it returns -1 */
112 	if (strlcpy(symname, SYM_PREFIX, sizeof(symname)) >= sizeof(symname))
113 		goto bail;
114 	if (strlcat(symname, name, sizeof(symname)) >= sizeof(symname))
115 		goto bail;
116 	if (strlcat(symname, "_init", sizeof(symname)) >= sizeof(symname))
117 		goto bail;
118 	init = dlsym(hnd, symname);
119 	if (init && init() == -1)
120 		goto bail;
121 
122 	/* add the module to the list of loaded modules */
123 	module = ckmalloc(sizeof(module_t));
124 	module->name = ckstrdup(name);
125 	module->hnd = hnd;
126 	LIST_INSERT_HEAD(&module_list, module, m_list);
127 
128 	return module;
129 
130 bail:
131 	dlclose(hnd);
132 	return NULL;
133 }
134