1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <fcntl.h> 36 #include <sys/shm.h> 37 #include <dlfcn.h> 38 #include <sys/systeminfo.h> 39 #include <sys/utsname.h> 40 41 #include <fcode/private.h> 42 #include <fcode/log.h> 43 44 #include <fcdriver/fcdriver.h> 45 46 static char *default_search_path; 47 static char search_proto[] = 48 "/usr/platform/%s/lib/efcode%s:" 49 "/usr/platform/%s/lib/efcode%s:" 50 "/usr/lib/efcode%s"; 51 52 /* 53 * Build the library/drop-in fcode search path. If there's no architecture 54 * passed, we build the search path (per the PSARC decision): 55 * /usr/platform/`uname -i`/lib/efcode 56 * /usr/platform/`uname -m`/lib/efcode 57 * /usr/lib/efcode 58 * If there is an architecture passed, we prepend the following search path to 59 * the above: 60 * /usr/platform/`uname -i`/lib/efcode/{architecture} 61 * /usr/platform/`uname -m`/lib/efcode/{architecture} 62 * /usr/lib/efcode/{architecture} 63 * This allows FCode drop-in searches to find FCode in the non-architecture 64 * directories. 65 */ 66 static void 67 build_default_search_path(char *arch) 68 { 69 char platform[100], *p; 70 struct stat statb; 71 struct utsname utsname; 72 int len; 73 74 sysinfo(SI_PLATFORM, platform, sizeof (platform)); 75 uname(&utsname); 76 len = strlen(search_proto) + strlen(platform) + strlen(utsname.machine); 77 if (*arch != '\0') { 78 len += len + (3 * strlen(arch)) + 1; 79 } 80 default_search_path = MALLOC(len); 81 if (*arch != '\0') { 82 sprintf(default_search_path, search_proto, platform, arch, 83 utsname.machine, arch, arch); 84 p = default_search_path + strlen(default_search_path); 85 *p++ = ':'; 86 } else 87 p = default_search_path; 88 89 sprintf(p, search_proto, platform, "", utsname.machine, "", ""); 90 } 91 92 static void 93 set_default_search_path(fcode_env_t *env) 94 { 95 if (default_search_path) 96 FREE(default_search_path); 97 98 parse_word(env); 99 default_search_path = pop_a_duped_string(env, NULL); 100 } 101 102 static void 103 get_default_search_path(fcode_env_t *env) 104 { 105 push_a_string(env, default_search_path); 106 } 107 108 /* 109 * Complicated by fact that a library (e.g. a 32-bit library) can match the 110 * file name. But if we're running as 64-bit, dlopen on that library will 111 * fail. 112 */ 113 static char * 114 search_path(char *name, char *search, int (*fn)(char *)) 115 { 116 char *p, *next_p; 117 char *tpath, *fpath; 118 119 fpath = STRDUP(search); 120 for (p = fpath; p != NULL; p = next_p) { 121 if ((next_p = strchr(p, ':')) != NULL) 122 *next_p++ = '\0'; 123 tpath = MALLOC(strlen(p) + strlen(name) + 2); 124 sprintf(tpath, "%s/%s", p, name); 125 if ((*fn)(tpath)) { 126 FREE(fpath); 127 return (tpath); 128 } 129 FREE(tpath); 130 } 131 FREE(fpath); 132 return (NULL); 133 } 134 135 static int 136 load_lib_file(char *path) 137 { 138 struct stat buf; 139 140 debug_msg(DEBUG_FIND_FCODE, "load_lib_file: '%s' -> ", path); 141 if (stat(path, &buf)) { 142 debug_msg(DEBUG_FIND_FCODE, "stat failed\n"); 143 return (0); 144 } 145 if (dlopen(path, RTLD_NOW) != NULL) { 146 debug_msg(DEBUG_FIND_FCODE, "OK\n"); 147 return (1); 148 } 149 debug_msg(DEBUG_FIND_FCODE, "dlopen failed\n"); 150 return (0); 151 } 152 153 static int 154 is_fcode_file(char *path) 155 { 156 struct stat statb; 157 int fd; 158 uchar_t header[8]; 159 int status; 160 static char func_name[] = "is_fcode_file"; 161 extern int check_fcode_header(char *, uchar_t *, int); 162 163 debug_msg(DEBUG_FIND_FCODE, "%s: '%s' -> ", func_name, path); 164 if ((fd = open(path, 0)) < 0) { 165 debug_msg(DEBUG_FIND_FCODE, "%s: '%s' can't open\n", func_name, 166 path); 167 return (0); 168 } 169 if (fstat(fd, &statb) != 0 || read(fd, header, sizeof (header)) < 0) { 170 debug_msg(DEBUG_FIND_FCODE, "%s: '%s' can't fstat/read\n", 171 func_name, path); 172 close(fd); 173 return (0); 174 } 175 status = check_fcode_header(path, header, statb.st_size); 176 debug_msg(DEBUG_FIND_FCODE, "%s: '%s' format %s\n", func_name, path, 177 status ? "OK" : "NOT OK"); 178 close(fd); 179 return (status); 180 } 181 182 static char * 183 find_lib_file(fcode_env_t *env, char *prefix, char *name, char *suffix, 184 int (*fn)(char *)) 185 { 186 char *search, *fname; 187 char *lib_name; 188 common_data_t *cdp = env->private; 189 190 if ((search = cdp->search_path) == NULL && 191 (search = default_search_path) == NULL) { 192 log_message(MSG_ERROR, "find_lib_file: no search path\n"); 193 return (NULL); 194 } 195 196 lib_name = MALLOC(strlen(name) + strlen(prefix) + strlen(suffix) + 1); 197 sprintf(lib_name, "%s%s%s", prefix, name, suffix); 198 fname = search_path(lib_name, search, fn); 199 FREE(lib_name); 200 return (fname); 201 } 202 203 char * 204 search_for_fcode_file(fcode_env_t *env, char *basename) 205 { 206 return (find_lib_file(env, "", basename, ".fc", is_fcode_file)); 207 } 208 209 static void 210 load_appropriate_file(fcode_env_t *env, char *name, device_t *d) 211 { 212 char *fname; 213 214 if ((fname = find_lib_file(env, "lfc_", name, ".so", load_lib_file)) 215 != NULL) { 216 debug_msg(DEBUG_FIND_FCODE, "Loading Library: %s\n", fname); 217 FREE(fname); 218 } else if ((fname = search_for_fcode_file(env, name)) != NULL) { 219 debug_msg(DEBUG_FIND_FCODE, "Loading Fcode: %s\n", fname); 220 run_fcode_from_file(env, fname, 0); 221 FREE(fname); 222 } else { 223 throw_from_fclib(env, 1, 224 "Can't find 'lfc_%s.so' or '%s.fc'\n", name, name); 225 } 226 } 227 228 void 229 install_node_data(fcode_env_t *env, device_t *d) 230 { 231 prop_t *p; 232 device_t *cd; 233 char libname[512]; 234 static char func_name[] = "install_node_data"; 235 236 if (d->parent) { 237 if ((p = lookup_package_property(env, "device_type", 238 d->parent)) == NULL) { 239 log_message(MSG_ERROR, "%s: no 'device_type' property" 240 " for '%s'\n", func_name, get_path(env, d->parent)); 241 return; 242 } 243 /* 244 * Warning: lookup_package_property uses a static data area to 245 * build the property node returned, so we have to grab a copy 246 * of the data. 247 */ 248 strcpy(libname, (char *)p->data); 249 strcat(libname, "_"); 250 } else 251 libname[0] = '\0'; 252 253 if ((p = lookup_package_property(env, "device_type", d)) == NULL) { 254 log_message(MSG_ERROR, "%s: no 'device_type' property for" 255 " '%s'\n", func_name, get_path(env, d)); 256 return; 257 } 258 259 /* 260 * Warning: lookup_package_property uses a static data area to build 261 * the property node returned, so we have to grab a copy of the 262 * data. 263 */ 264 strcat(libname, (char *)p->data); 265 266 debug_msg(DEBUG_FIND_FCODE, "%s: `%s` lname: '%s'\n", func_name, 267 get_path(env, d), libname); 268 269 load_appropriate_file(env, libname, d); 270 } 271 272 #pragma init(_init) 273 274 static void 275 _init(void) 276 { 277 fcode_env_t *env = initial_env; 278 279 ASSERT(env); 280 NOTICE; 281 282 #if defined(__sparcv9) 283 build_default_search_path("/sparcv9"); 284 #else 285 build_default_search_path(""); 286 #endif 287 FORTH(0, "set-default-search-path", set_default_search_path); 288 FORTH(0, "get-default-search-path", get_default_search_path); 289 } 290