1 /* 2 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <image.h> 7 #include <image_private.h> 8 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <OS.h> 13 14 #include <libroot_private.h> 15 #include <runtime_loader.h> 16 #include <syscalls.h> 17 #include <user_runtime.h> 18 19 20 thread_id 21 load_image(int32 argCount, const char **args, const char **environ) 22 { 23 char invoker[B_FILE_NAME_LENGTH]; 24 char **newArgs = NULL; 25 int32 envCount = 0; 26 thread_id thread; 27 28 if (argCount < 1 || environ == NULL) 29 return B_BAD_VALUE; 30 31 // test validity of executable + support for scripts 32 { 33 status_t status = __test_executable(args[0], invoker); 34 if (status < B_OK) 35 return status; 36 37 if (invoker[0]) { 38 status = __parse_invoke_line(invoker, &newArgs, 39 (char * const **)&args, &argCount, args[0]); 40 if (status < B_OK) 41 return status; 42 } 43 } 44 45 // count environment variables 46 while (environ[envCount] != NULL) 47 envCount++; 48 49 char** flatArgs = NULL; 50 size_t flatArgsSize; 51 status_t status = __flatten_process_args(args, argCount, environ, envCount, 52 &flatArgs, &flatArgsSize); 53 54 if (status == B_OK) { 55 thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount, 56 B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0); 57 58 free(flatArgs); 59 } else 60 thread = status; 61 62 free(newArgs); 63 return thread; 64 } 65 66 67 image_id 68 load_add_on(char const *name) 69 { 70 if (name == NULL) 71 return B_BAD_VALUE; 72 73 return __gRuntimeLoader->load_add_on(name, 0); 74 } 75 76 77 status_t 78 unload_add_on(image_id id) 79 { 80 return __gRuntimeLoader->unload_add_on(id); 81 } 82 83 84 status_t 85 get_image_symbol(image_id id, char const *symbolName, int32 symbolType, 86 void **_location) 87 { 88 return __gRuntimeLoader->get_image_symbol(id, symbolName, symbolType, 89 false, NULL, _location); 90 } 91 92 93 status_t 94 get_image_symbol_etc(image_id id, char const *symbolName, int32 symbolType, 95 bool recursive, image_id *_inImage, void **_location) 96 { 97 return __gRuntimeLoader->get_image_symbol(id, symbolName, symbolType, 98 recursive, _inImage, _location); 99 } 100 101 102 status_t 103 get_nth_image_symbol(image_id id, int32 num, char *nameBuffer, int32 *_nameLength, 104 int32 *_symbolType, void **_location) 105 { 106 return __gRuntimeLoader->get_nth_image_symbol(id, num, nameBuffer, _nameLength, _symbolType, _location); 107 } 108 109 110 status_t 111 _get_image_info(image_id id, image_info *info, size_t infoSize) 112 { 113 return _kern_get_image_info(id, info, infoSize); 114 } 115 116 117 status_t 118 _get_next_image_info(team_id team, int32 *cookie, image_info *info, size_t infoSize) 119 { 120 return _kern_get_next_image_info(team, cookie, info, infoSize); 121 } 122 123 124 void 125 clear_caches(void *address, size_t length, uint32 flags) 126 { 127 _kern_clear_caches(address, length, flags); 128 } 129 130 131 // #pragma mark - 132 133 134 static char * 135 next_argument(char **_start, bool separate) 136 { 137 char *line = *_start; 138 char quote = 0; 139 int32 i; 140 141 // eliminate leading spaces 142 while (line[0] == ' ') 143 line++; 144 145 if (line[0] == '"' || line[0] == '\'') { 146 quote = line[0]; 147 line++; 148 } 149 150 if (!line[0]) 151 return NULL; 152 153 for (i = 0;; i++) { 154 if (line[i] == '\\' && line[i + 1] != '\0') 155 continue; 156 157 if (line[i] == '\0') { 158 *_start = &line[i]; 159 return line; 160 } 161 if ((!quote && line[i] == ' ') || line[i] == quote) { 162 // argument separator! 163 if (separate) 164 line[i] = '\0'; 165 *_start = &line[i + 1]; 166 return line; 167 } 168 } 169 170 return NULL; 171 } 172 173 174 status_t 175 __parse_invoke_line(char *invoker, char ***_newArgs, 176 char * const **_oldArgs, int32 *_argCount, const char *arg0) 177 { 178 int32 i, count = 0; 179 char *arg = invoker; 180 char **newArgs; 181 182 // count arguments in the line 183 184 while (next_argument(&arg, false)) { 185 count++; 186 } 187 188 // this is a shell script and requires special treatment 189 newArgs = (char**)malloc((*_argCount + count + 1) * sizeof(void *)); 190 if (newArgs == NULL) 191 return B_NO_MEMORY; 192 193 // copy invoker and old arguments and to newArgs 194 195 for (i = 0; (arg = next_argument(&invoker, true)) != NULL; i++) { 196 newArgs[i] = arg; 197 } 198 for (i = 0; i < *_argCount; i++) { 199 if (i == 0) 200 newArgs[i + count] = (char*)arg0; 201 else 202 newArgs[i + count] = (char *)(*_oldArgs)[i]; 203 } 204 205 newArgs[i + count] = NULL; 206 207 *_newArgs = newArgs; 208 *_oldArgs = (char * const *)newArgs; 209 *_argCount += count; 210 211 return B_OK; 212 } 213 214 215 status_t 216 __get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) 217 { 218 return __gRuntimeLoader->get_next_image_dependency(id, cookie, _name); 219 } 220 221 222 status_t 223 __test_executable(const char *path, char *invoker) 224 { 225 return __gRuntimeLoader->test_executable(path, invoker); 226 } 227 228 229 /*! Allocates a flat buffer and copies the argument and environment strings 230 into it. The buffer starts with a char* array which contains pointers to 231 the strings of the arguments and environment, followed by the strings. Both 232 arguments and environment arrays are NULL-terminated. 233 */ 234 status_t 235 __flatten_process_args(const char* const* args, int32 argCount, 236 const char* const* env, int32 envCount, char*** _flatArgs, 237 size_t* _flatSize) 238 { 239 if (args == NULL || env == NULL) 240 return B_BAD_VALUE; 241 242 // determine total needed size 243 int32 argSize = 0; 244 for (int32 i = 0; i < argCount; i++) { 245 if (args[i] == NULL) 246 return B_BAD_VALUE; 247 argSize += strlen(args[i]) + 1; 248 } 249 250 int32 envSize = 0; 251 for (int32 i = 0; i < envCount; i++) { 252 if (env[i] == NULL) 253 return B_BAD_VALUE; 254 envSize += strlen(env[i]) + 1; 255 } 256 257 int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize; 258 if (size > MAX_PROCESS_ARGS_SIZE) 259 return B_TOO_MANY_ARGS; 260 261 // allocate space 262 char** flatArgs = (char**)malloc(size); 263 if (flatArgs == NULL) 264 return B_NO_MEMORY; 265 266 char** slot = flatArgs; 267 char* stringSpace = (char*)(flatArgs + argCount + envCount + 2); 268 269 // copy arguments and environment 270 for (int32 i = 0; i < argCount; i++) { 271 int32 argSize = strlen(args[i]) + 1; 272 memcpy(stringSpace, args[i], argSize); 273 *slot++ = stringSpace; 274 stringSpace += argSize; 275 } 276 277 *slot++ = NULL; 278 279 for (int32 i = 0; i < envCount; i++) { 280 int32 envSize = strlen(env[i]) + 1; 281 memcpy(stringSpace, env[i], envSize); 282 *slot++ = stringSpace; 283 stringSpace += envSize; 284 } 285 286 *slot++ = NULL; 287 288 *_flatArgs = flatArgs; 289 *_flatSize = size; 290 return B_OK; 291 } 292 293 294 extern "C" void _call_init_routines_(void); 295 void 296 _call_init_routines_(void) 297 { 298 // This is called by the original BeOS startup code. 299 // We don't need it, because our loader already does the job, right? 300 } 301 302