1 /* $NetBSD: citrus_module.c,v 1.3 2003/08/07 16:42:38 agc Exp $ */ 2 3 /*- 4 * Copyright (c)1999, 2000, 2001, 2002 Citrus Project, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /*- 30 * Copyright (c) 1998 The NetBSD Foundation, Inc. 31 * All rights reserved. 32 * 33 * This code is derived from software contributed to The NetBSD Foundation 34 * by Paul Kranenburg. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the NetBSD 47 * Foundation, Inc. and its contributors. 48 * 4. Neither the name of The NetBSD Foundation nor the names of its 49 * contributors may be used to endorse or promote products derived 50 * from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 * POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 /*- 66 * Copyright (c) 1993 67 * The Regents of the University of California. All rights reserved. 68 * 69 * This code is derived from software contributed to Berkeley by 70 * Paul Borman at Krystal Technologies. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. Redistributions in binary form must reproduce the above copyright 78 * notice, this list of conditions and the following disclaimer in the 79 * documentation and/or other materials provided with the distribution. 80 * 3. Neither the name of the University nor the names of its contributors 81 * may be used to endorse or promote products derived from this software 82 * without specific prior written permission. 83 * 84 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94 * SUCH DAMAGE. 95 */ 96 97 #include <sys/cdefs.h> 98 #if defined(LIBC_SCCS) && !defined(lint) 99 __RCSID("$NetBSD: citrus_module.c,v 1.3 2003/08/07 16:42:38 agc Exp $"); 100 #endif /* LIBC_SCCS and not lint */ 101 102 #include <assert.h> 103 #include <errno.h> 104 #include <limits.h> 105 #include <string.h> 106 #include <stdio.h> 107 #include <stdlib.h> 108 #include <unistd.h> 109 #include <locale.h> 110 #include <stddef.h> 111 #include <paths.h> 112 #include "citrus_module.h" 113 114 #include <sys/types.h> 115 #include <dirent.h> 116 #include <dlfcn.h> 117 118 #ifdef _I18N_DYNAMIC 119 120 static int _getdewey(int [], char *); 121 static int _cmpndewey(int [], int, int [], int); 122 static const char *_findshlib(char *, int *, int *); 123 124 static char *_pathI18nModule = NULL; 125 126 /* from libexec/ld.aout_so/shlib.c */ 127 #undef major 128 #undef minor 129 #define MAXDEWEY 3 /*ELF*/ 130 131 static int 132 _getdewey(int dewey[], char *cp) 133 { 134 int i, n; 135 136 _DIAGASSERT(dewey != NULL); 137 _DIAGASSERT(cp != NULL); 138 139 for (n = 0, i = 0; i < MAXDEWEY; i++) { 140 if (*cp == '\0') 141 break; 142 143 if (*cp == '.') cp++; 144 if (*cp < '0' || '9' < *cp) 145 return 0; 146 147 dewey[n++] = (int)strtol(cp, &cp, 10); 148 } 149 150 return n; 151 } 152 153 /* 154 * Compare two dewey arrays. 155 * Return -1 if `d1' represents a smaller value than `d2'. 156 * Return 1 if `d1' represents a greater value than `d2'. 157 * Return 0 if equal. 158 */ 159 static int 160 _cmpndewey(int d1[], int n1, int d2[], int n2) 161 { 162 register int i; 163 164 _DIAGASSERT(d1 != NULL); 165 _DIAGASSERT(d2 != NULL); 166 167 for (i = 0; i < n1 && i < n2; i++) { 168 if (d1[i] < d2[i]) 169 return -1; 170 if (d1[i] > d2[i]) 171 return 1; 172 } 173 174 if (n1 == n2) 175 return 0; 176 177 if (i == n1) 178 return -1; 179 180 if (i == n2) 181 return 1; 182 183 /* XXX cannot happen */ 184 return 0; 185 } 186 187 static const char * 188 _findshlib(char *name, int *majorp, int *minorp) 189 { 190 int dewey[MAXDEWEY]; 191 int ndewey; 192 int tmp[MAXDEWEY]; 193 int i; 194 int len; 195 char *lname; 196 static char path[PATH_MAX]; 197 int major, minor; 198 const char *search_dirs[1]; 199 const int n_search_dirs = 1; 200 201 _DIAGASSERT(name != NULL); 202 _DIAGASSERT(majorp != NULL); 203 _DIAGASSERT(minorp != NULL); 204 205 major = *majorp; 206 minor = *minorp; 207 path[0] = '\0'; 208 search_dirs[0] = _pathI18nModule; 209 len = strlen(name); 210 lname = name; 211 212 ndewey = 0; 213 214 for (i = 0; i < n_search_dirs; i++) { 215 DIR *dd = opendir(search_dirs[i]); 216 struct dirent *dp; 217 int found_dot_a = 0; 218 int found_dot_so = 0; 219 220 if (dd == NULL) 221 continue; 222 223 while ((dp = readdir(dd)) != NULL) { 224 int n; 225 226 if (dp->d_namlen < len + 4) 227 continue; 228 if (strncmp(dp->d_name, lname, (size_t)len) != 0) 229 continue; 230 if (strncmp(dp->d_name+len, ".so.", 4) != 0) 231 continue; 232 233 if ((n = _getdewey(tmp, dp->d_name+len+4)) == 0) 234 continue; 235 236 if (major != -1 && found_dot_a) 237 found_dot_a = 0; 238 239 /* XXX should verify the library is a.out/ELF? */ 240 241 if (major == -1 && minor == -1) { 242 goto compare_version; 243 } else if (major != -1 && minor == -1) { 244 if (tmp[0] == major) 245 goto compare_version; 246 } else if (major != -1 && minor != -1) { 247 if (tmp[0] == major) { 248 if (n == 1 || tmp[1] >= minor) 249 goto compare_version; 250 } 251 } 252 253 /* else, this file does not qualify */ 254 continue; 255 256 compare_version: 257 if (_cmpndewey(tmp, n, dewey, ndewey) <= 0) 258 continue; 259 260 /* We have a better version */ 261 found_dot_so = 1; 262 snprintf(path, sizeof(path), "%s/%s", search_dirs[i], 263 dp->d_name); 264 found_dot_a = 0; 265 bcopy(tmp, dewey, sizeof(dewey)); 266 ndewey = n; 267 *majorp = dewey[0]; 268 *minorp = dewey[1]; 269 } 270 closedir(dd); 271 272 if (found_dot_a || found_dot_so) 273 /* 274 * There's a lib in this dir; take it. 275 */ 276 return path[0] ? path : NULL; 277 } 278 279 return path[0] ? path : NULL; 280 } 281 282 void * 283 _citrus_find_getops(_citrus_module_t handle, const char *modname, 284 const char *ifname) 285 { 286 char name[PATH_MAX]; 287 void *p; 288 289 _DIAGASSERT(handle != NULL); 290 _DIAGASSERT(modname != NULL); 291 _DIAGASSERT(ifname != NULL); 292 293 #ifdef __ELF__ 294 snprintf(name, sizeof(name), "_citrus_%s_%s_getops", modname, ifname); 295 #else 296 /* a.out case */ 297 snprintf(name, sizeof(name), "__citrus_%s_%s_getops", modname, ifname); 298 #endif 299 p = dlsym((void *)handle, name); 300 return p; 301 } 302 303 int 304 _citrus_load_module(_citrus_module_t *rhandle, const char *encname) 305 { 306 const char *p; 307 char path[PATH_MAX]; 308 int maj, min; 309 void *handle; 310 311 _DIAGASSERT(rhandle != NULL); 312 313 if (_pathI18nModule == NULL) { 314 p = getenv("PATH_I18NMODULE"); 315 if (p != NULL && !issetugid()) { 316 _pathI18nModule = strdup(p); 317 if (_pathI18nModule == NULL) 318 return ENOMEM; 319 } else 320 _pathI18nModule = _PATH_I18NMODULE; 321 } 322 323 (void)snprintf(path, sizeof(path), "lib%s", encname); 324 maj = I18NMODULE_MAJOR; 325 min = -1; 326 p = _findshlib(path, &maj, &min); 327 if (!p) 328 return (EINVAL); 329 handle = dlopen(p, RTLD_LAZY); 330 if (!handle) 331 return (EINVAL); 332 333 *rhandle = (_citrus_module_t)handle; 334 335 return (0); 336 } 337 338 void 339 _citrus_unload_module(_citrus_module_t handle) 340 { 341 if (handle) 342 dlclose((void *)handle); 343 } 344 #else 345 /* !_I18N_DYNAMIC */ 346 347 void * 348 /*ARGSUSED*/ 349 _citrus_find_getops(_citrus_module_t handle, const char *modname, 350 const char *ifname) 351 { 352 return (NULL); 353 } 354 355 int 356 /*ARGSUSED*/ 357 _citrus_load_module(_citrus_module_t *rhandle, char const *modname) 358 { 359 return (EINVAL); 360 } 361 362 void 363 /*ARGSUSED*/ 364 _citrus_unload_module(_citrus_module_t handle) 365 { 366 } 367 #endif 368