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