1 /* 2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002, Manuel J. Petit. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include "runtime_loader_private.h" 11 12 #include <syscalls.h> 13 #include <user_runtime.h> 14 15 #include <directories.h> 16 17 #include <string.h> 18 #include <stdlib.h> 19 #include <sys/stat.h> 20 21 #include <algorithm> 22 23 24 struct user_space_program_args *gProgramArgs; 25 void *__gCommPageAddress; 26 27 28 static const char * 29 search_path_for_type(image_type type) 30 { 31 const char *path = NULL; 32 33 switch (type) { 34 case B_APP_IMAGE: 35 path = getenv("PATH"); 36 break; 37 case B_LIBRARY_IMAGE: 38 path = getenv("LIBRARY_PATH"); 39 break; 40 case B_ADD_ON_IMAGE: 41 path = getenv("ADDON_PATH"); 42 break; 43 44 default: 45 return NULL; 46 } 47 48 if (path != NULL) 49 return path; 50 51 // The environment variables may not have been set yet - in that case, 52 // we're returning some useful defaults. 53 // Since the kernel does not set any variables, this is also needed 54 // to start the root shell. 55 56 switch (type) { 57 case B_APP_IMAGE: 58 return kUserBinDirectory 59 // TODO: Remove! 60 ":" kCommonBinDirectory 61 ":" kGlobalBinDirectory 62 ":" kAppsDirectory 63 ":" kPreferencesDirectory 64 ":" kSystemAppsDirectory 65 ":" kSystemPreferencesDirectory 66 ":" kCommonDevelopToolsBinDirectory; 67 68 case B_LIBRARY_IMAGE: 69 return kAppLocalLibDirectory 70 ":" kUserNonpackagedLibDirectory 71 ":" kUserLibDirectory 72 // TODO: Remove! 73 ":" kCommonNonpackagedLibDirectory 74 ":" kCommonLibDirectory 75 ":" kSystemLibDirectory; 76 77 case B_ADD_ON_IMAGE: 78 return kAppLocalAddonsDirectory 79 ":" kUserNonpackagedAddonsDirectory 80 ":" kUserAddonsDirectory 81 // TODO: Remove! 82 ":" kCommonNonpackagedAddonsDirectory 83 ":" kSystemAddonsDirectory; 84 85 default: 86 return NULL; 87 } 88 } 89 90 91 static int 92 try_open_executable(const char *dir, int dirLength, const char *name, 93 const char *programPath, const char *abiSpecificSubDir, char *path, 94 size_t pathLength) 95 { 96 size_t nameLength = strlen(name); 97 struct stat stat; 98 status_t status; 99 100 // construct the path 101 if (dirLength > 0) { 102 char *buffer = path; 103 size_t subDirLen = 0; 104 105 if (programPath == NULL) 106 programPath = gProgramArgs->program_path; 107 108 if (dirLength >= 2 && strncmp(dir, "%A", 2) == 0) { 109 // Replace %A with current app folder path (of course, 110 // this must be the first part of the path) 111 char *lastSlash = strrchr(programPath, '/'); 112 int bytesCopied; 113 114 // copy what's left (when the application name is removed) 115 if (lastSlash != NULL) { 116 strlcpy(buffer, programPath, 117 std::min((long)pathLength, lastSlash + 1 - programPath)); 118 } else 119 strlcpy(buffer, ".", pathLength); 120 121 bytesCopied = strlen(buffer); 122 buffer += bytesCopied; 123 pathLength -= bytesCopied; 124 dir += 2; 125 dirLength -= 2; 126 } else if (abiSpecificSubDir != NULL) { 127 // We're looking for a library or an add-on and the executable has 128 // not been compiled with a compiler using the same ABI as the one 129 // the OS has been built with. Thus we only look in subdirs 130 // specific to that ABI. 131 subDirLen = strlen(abiSpecificSubDir) + 1; 132 } 133 134 if (dirLength + 1 + subDirLen + nameLength >= pathLength) 135 return B_NAME_TOO_LONG; 136 137 memcpy(buffer, dir, dirLength); 138 buffer[dirLength] = '/'; 139 if (subDirLen > 0) { 140 memcpy(buffer + dirLength + 1, abiSpecificSubDir, subDirLen - 1); 141 buffer[dirLength + subDirLen] = '/'; 142 } 143 strcpy(buffer + dirLength + 1 + subDirLen, name); 144 } else { 145 if (nameLength >= pathLength) 146 return B_NAME_TOO_LONG; 147 148 strcpy(path + dirLength + 1, name); 149 } 150 151 TRACE(("runtime_loader: try_open_container(): %s\n", path)); 152 153 // Test if the target is a symbolic link, and correct the path in this case 154 155 status = _kern_read_stat(-1, path, false, &stat, sizeof(struct stat)); 156 if (status < B_OK) 157 return status; 158 159 if (S_ISLNK(stat.st_mode)) { 160 char buffer[PATH_MAX]; 161 size_t length = PATH_MAX - 1; 162 char *lastSlash; 163 164 // it's a link, indeed 165 status = _kern_read_link(-1, path, buffer, &length); 166 if (status < B_OK) 167 return status; 168 buffer[length] = '\0'; 169 170 lastSlash = strrchr(path, '/'); 171 if (buffer[0] != '/' && lastSlash != NULL) { 172 // relative path 173 strlcpy(lastSlash + 1, buffer, lastSlash + 1 - path + pathLength); 174 } else 175 strlcpy(path, buffer, pathLength); 176 } 177 178 return _kern_open(-1, path, O_RDONLY, 0); 179 } 180 181 182 static int 183 search_executable_in_path_list(const char *name, const char *pathList, 184 int pathListLen, const char *programPath, const char *abiSpecificSubDir, 185 char *pathBuffer, size_t pathBufferLength) 186 { 187 const char *pathListEnd = pathList + pathListLen; 188 status_t status = B_ENTRY_NOT_FOUND; 189 190 TRACE(("runtime_loader: search_container_in_path_list() %s in %.*s\n", name, 191 pathListLen, pathList)); 192 193 while (pathListLen > 0) { 194 const char *pathEnd = pathList; 195 int fd; 196 197 // find the next ':' or run till the end of the string 198 while (pathEnd < pathListEnd && *pathEnd != ':') 199 pathEnd++; 200 201 fd = try_open_executable(pathList, pathEnd - pathList, name, 202 programPath, abiSpecificSubDir, pathBuffer, pathBufferLength); 203 if (fd >= 0) { 204 // see if it's a dir 205 struct stat stat; 206 status = _kern_read_stat(fd, NULL, true, &stat, sizeof(struct stat)); 207 if (status == B_OK) { 208 if (!S_ISDIR(stat.st_mode)) 209 return fd; 210 status = B_IS_A_DIRECTORY; 211 } 212 _kern_close(fd); 213 } 214 215 pathListLen = pathListEnd - pathEnd - 1; 216 pathList = pathEnd + 1; 217 } 218 219 return status; 220 } 221 222 223 int 224 open_executable(char *name, image_type type, const char *rpath, 225 const char *programPath, const char *abiSpecificSubDir) 226 { 227 char buffer[PATH_MAX]; 228 int fd = B_ENTRY_NOT_FOUND; 229 230 if (strchr(name, '/')) { 231 // the name already contains a path, we don't have to search for it 232 fd = _kern_open(-1, name, O_RDONLY, 0); 233 if (fd >= 0 || type == B_APP_IMAGE) 234 return fd; 235 236 // can't search harder an absolute path add-on name! 237 if (type == B_ADD_ON_IMAGE && name[0] == '/') 238 return fd; 239 240 // Even though ELF specs don't say this, we give shared libraries 241 // and relative path based add-ons another chance and look 242 // them up in the usual search paths - at 243 // least that seems to be what BeOS does, and since it doesn't hurt... 244 if (type == B_LIBRARY_IMAGE) { 245 // For library (but not add-on), strip any path from name. 246 // Relative path of add-on is kept. 247 const char* paths = strrchr(name, '/') + 1; 248 memmove(name, paths, strlen(paths) + 1); 249 } 250 } 251 252 // try rpath (DT_RPATH) 253 if (rpath != NULL) { 254 // It consists of a colon-separated search path list. Optionally a 255 // second search path list follows, separated from the first by a 256 // semicolon. 257 const char *semicolon = strchr(rpath, ';'); 258 const char *firstList = (semicolon ? rpath : NULL); 259 const char *secondList = (semicolon ? semicolon + 1 : rpath); 260 // If there is no ';', we set only secondList to simplify things. 261 if (firstList) { 262 fd = search_executable_in_path_list(name, firstList, 263 semicolon - firstList, programPath, NULL, buffer, 264 sizeof(buffer)); 265 } 266 if (fd < 0) { 267 fd = search_executable_in_path_list(name, secondList, 268 strlen(secondList), programPath, NULL, buffer, sizeof(buffer)); 269 } 270 } 271 272 // If not found yet, let's evaluate the system path variables to find the 273 // shared object. 274 if (fd < 0) { 275 if (const char *paths = search_path_for_type(type)) { 276 fd = search_executable_in_path_list(name, paths, strlen(paths), 277 programPath, abiSpecificSubDir, buffer, sizeof(buffer)); 278 } 279 } 280 281 if (fd >= 0) { 282 // we found it, copy path! 283 TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer)); 284 strlcpy(name, buffer, PATH_MAX); 285 } 286 287 return fd; 288 } 289 290 291 /*! 292 Tests if there is an executable file at the provided path. It will 293 also test if the file has a valid ELF header or is a shell script. 294 Even if the runtime loader does not need to be able to deal with 295 both types, the caller will give scripts a proper treatment. 296 */ 297 status_t 298 test_executable(const char *name, char *invoker) 299 { 300 char path[B_PATH_NAME_LENGTH]; 301 char buffer[B_FILE_NAME_LENGTH]; 302 // must be large enough to hold the ELF header 303 status_t status; 304 ssize_t length; 305 int fd; 306 307 if (name == NULL) 308 return B_BAD_VALUE; 309 310 strlcpy(path, name, sizeof(path)); 311 312 fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL); 313 if (fd < B_OK) 314 return fd; 315 316 // see if it's executable at all 317 status = _kern_access(-1, path, X_OK, false); 318 if (status != B_OK) 319 goto out; 320 321 // read and verify the ELF header 322 323 length = _kern_read(fd, 0, buffer, sizeof(buffer)); 324 if (length < 0) { 325 status = length; 326 goto out; 327 } 328 329 status = elf_verify_header(buffer, length); 330 if (status == B_NOT_AN_EXECUTABLE) { 331 // test for shell scripts 332 if (!strncmp(buffer, "#!", 2)) { 333 char *end; 334 buffer[min_c((size_t)length, sizeof(buffer) - 1)] = '\0'; 335 336 end = strchr(buffer, '\n'); 337 if (end == NULL) { 338 status = E2BIG; 339 goto out; 340 } else 341 end[0] = '\0'; 342 343 if (invoker) 344 strcpy(invoker, buffer + 2); 345 346 status = B_OK; 347 } 348 } else if (status == B_OK) { 349 elf_ehdr *elfHeader = (elf_ehdr *)buffer; 350 if (elfHeader->e_entry == 0) { 351 // we don't like to open shared libraries 352 status = B_NOT_AN_EXECUTABLE; 353 } else if (invoker) 354 invoker[0] = '\0'; 355 } 356 357 out: 358 _kern_close(fd); 359 return status; 360 } 361 362 363 /*! 364 This is the main entry point of the runtime loader as 365 specified by its ld-script. 366 */ 367 int 368 runtime_loader(void* _args, void* commpage) 369 { 370 void *entry = NULL; 371 int returnCode; 372 373 gProgramArgs = (struct user_space_program_args *)_args; 374 __gCommPageAddress = commpage; 375 376 // Relocate the args and env arrays -- they are organized in a contiguous 377 // buffer which the kernel just copied into user space without adjusting the 378 // pointers. 379 { 380 int32 i; 381 addr_t relocationOffset = 0; 382 383 if (gProgramArgs->arg_count > 0) 384 relocationOffset = (addr_t)gProgramArgs->args[0]; 385 else if (gProgramArgs->env_count > 0) 386 relocationOffset = (addr_t)gProgramArgs->env[0]; 387 388 // That's basically: <new buffer address> - <old buffer address>. 389 // It looks a little complicated, since we don't have the latter one at 390 // hand and thus need to reconstruct it (<first string pointer> - 391 // <arguments + environment array sizes>). 392 relocationOffset = (addr_t)gProgramArgs->args - relocationOffset 393 + (gProgramArgs->arg_count + gProgramArgs->env_count + 2) 394 * sizeof(char*); 395 396 for (i = 0; i < gProgramArgs->arg_count; i++) 397 gProgramArgs->args[i] += relocationOffset; 398 399 for (i = 0; i < gProgramArgs->env_count; i++) 400 gProgramArgs->env[i] += relocationOffset; 401 } 402 403 #if DEBUG_RLD 404 close(0); open("/dev/console", 0); /* stdin */ 405 close(1); open("/dev/console", 0); /* stdout */ 406 close(2); open("/dev/console", 0); /* stderr */ 407 #endif 408 409 if (heap_init() < B_OK) 410 return 1; 411 412 rldexport_init(); 413 rldelf_init(); 414 415 load_program(gProgramArgs->program_path, &entry); 416 417 if (entry == NULL) 418 return -1; 419 420 // call the program entry point (usually _start()) 421 returnCode = ((int (*)(int, void *, void *))entry)(gProgramArgs->arg_count, 422 gProgramArgs->args, gProgramArgs->env); 423 424 terminate_program(); 425 426 return returnCode; 427 } 428