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