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