int main() { char tmp[100]; const char *string; int major, minor, subminor; igraph_version(&string, &major, &minor, &subminor); if (subminor != 0) { sprintf(tmp, "%i.%i.%i", major, minor, subminor); } else { sprintf(tmp, "%i.%i", major, minor); } if (strcmp(string, tmp)) { return 1; } return 0; }
static gint _main_helper(Options* options) { /* start off with some status messages */ #if defined(IGRAPH_VERSION) gint igraphMajor = -1, igraphMinor = -1, igraphPatch = -1; igraph_version(NULL, &igraphMajor, &igraphMinor, &igraphPatch); gchar* startupStr = g_strdup_printf("Starting %s with GLib v%u.%u.%u and IGraph v%i.%i.%i", SHADOW_VERSION_STRING, (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION, igraphMajor, igraphMinor, igraphPatch); #else gchar* startupStr = g_strdup_printf("Starting %s with GLib v%u.%u.%u (IGraph version not available)", SHADOW_VERSION_STRING, (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION); #endif message("%s", startupStr); /* avoid logging the message to stderr twice (only log if this is not a relaunch) */ if(g_getenv("SHADOW_SPAWNED") == NULL) { g_printerr("** %s\n", startupStr); } g_free(startupStr); message(SHADOW_INFO_STRING); message("logging current startup arguments and environment"); gchar** envlist = g_get_environ(); gchar** arglist = g_strsplit(options_getArgumentString(options), " ", 0); _main_logEnvironment(arglist, envlist); g_strfreev(arglist); g_strfreev(envlist); /* check if we still need to setup our required environment and relaunch */ if(g_getenv("SHADOW_SPAWNED") == NULL) { message("shadow will automatically adjust environment and relaunch"); message("loading shadow configuration file"); /* we need to relaunch. * first lets load the config file to help us setup the environment */ const GString* fileName = options_getInputXMLFilename(options); if(!fileName) { return EXIT_FAILURE; } GString* file = utility_getFileContents(fileName->str); if(!file) { critical("unable to read config file contents"); return EXIT_FAILURE; } Configuration* config = configuration_new(options, file); g_string_free(file, TRUE); file = NULL; if(!config) { critical("there was a problem parsing the Shadow config file, and we can't run without it"); return EXIT_FAILURE; } message("shadow configuration file loaded, parsed, and passed validation"); /* now start to set up the environment */ gchar** envlist = g_get_environ(); GString* commandBuffer = g_string_new(options_getArgumentString(options)); if(!envlist || !commandBuffer) { critical("there was a problem loading existing environment"); configuration_free(config); return EXIT_FAILURE; } message("setting up LD_PRELOAD environment"); /* compute the proper LD_PRELOAD value, extract the shadow preload file and * set it as a command line argument if needed */ gchar* preloadArgValue = NULL; { /* before we restart, we should: * -set the shadow preload lib as a command line arg * -make sure it does not exist in LD_PRELOAD, but otherwise leave LD_PRELOAD in place * we need to search for our preload lib. our order of preference follows. */ /* 1. existing "--preload=" option value */ if(_main_isValidPathToPreloadLib(options_getPreloadString(options))) { preloadArgValue = g_strdup(options_getPreloadString(options)); } /* 2. the 'preload' attribute value of the 'shadow' element in shadow.config.xml */ /* we only need to search if we haven't already found a valid path */ if(!preloadArgValue) { ConfigurationShadowElement* element = configuration_getShadowElement(config); if(element && element->preloadPath.isSet) { gchar* path = element->preloadPath.string->str; if(_main_isValidPathToPreloadLib(path)) { preloadArgValue = g_strdup(path); } } } /* 3. the LD_PRELOAD value */ GString* preloadEnvValueBuffer = NULL; /* we always search the env variable and remove existing Shadow preload libs */ if(g_environ_getenv(envlist, "LD_PRELOAD") != NULL) { gchar** tokens = g_strsplit(g_environ_getenv(envlist, "LD_PRELOAD"), ":", 0); for(gint i = 0; tokens[i] != NULL; i++) { /* each token in the env variable should be an absolute path */ if(_main_isValidPathToPreloadLib(tokens[i])) { /* found a valid path, only save it if we don't have one yet (from options or config) */ if(!preloadArgValue) { preloadArgValue = g_strdup(tokens[i]); } } else { /* maintain non-shadow entries */ if(preloadEnvValueBuffer) { g_string_append_printf(preloadEnvValueBuffer, ":%s", tokens[i]); } else { preloadEnvValueBuffer = g_string_new(tokens[i]); } } } g_strfreev(tokens); } /* 4. the 'environment' attribute of the 'shadow' configuration element in shadow.config.xml */ /* always go through the 'environment' attribute of the 'shadow' element to pull in any keys defined there */ { ConfigurationShadowElement* element = configuration_getShadowElement(config); if(element && element->environment.isSet) { /* entries are split by ';' */ gchar** envTokens = g_strsplit(element->environment.string->str, ";", 0); for(gint i = 0; envTokens[i] != NULL; i++) { /* each env entry is key=value, get 2 tokens max */ gchar** items = g_strsplit(envTokens[i], "=", 2); gchar* key = items[0]; gchar* value = items[1]; if(key != NULL && value != NULL) { /* check if the key is LD_PRELOAD */ if(!g_ascii_strncasecmp(key, "LD_PRELOAD", 10)) { gchar** preloadTokens = g_strsplit(value, ":", 0); for(gint j = 0; preloadTokens[j] != NULL; j++) { /* each token in the env variable should be an absolute path */ if(_main_isValidPathToPreloadLib(preloadTokens[j])) { /* found a valid path, only save it if we don't have one yet (from options or config) */ if(!preloadArgValue) { preloadArgValue = g_strdup(preloadTokens[j]); } } else { /* maintain non-shadow entries */ if(preloadEnvValueBuffer) { g_string_append_printf(preloadEnvValueBuffer, ":%s", preloadTokens[j]); } else { preloadEnvValueBuffer = g_string_new(preloadTokens[j]); } } } g_strfreev(preloadTokens); } else { /* set the key=value pair, but don't overwrite any existing settings */ envlist = g_environ_setenv(envlist, key, value, 0); } } g_strfreev(items); } g_strfreev(envTokens); } } /* save away the non-shadow preload libs */ if(preloadEnvValueBuffer) { envlist = g_environ_setenv(envlist, "LD_PRELOAD", preloadEnvValueBuffer->str, 1); g_string_free(preloadEnvValueBuffer, TRUE); preloadEnvValueBuffer = NULL; } else { envlist = g_environ_unsetenv(envlist, "LD_PRELOAD"); } /* 5. as a last hope, try looking in RPATH since shadow is built with one */ /* we only need to search if we haven't already found a valid path */ if(!preloadArgValue) { gchar* rpathStr = _main_getRPath(); if(rpathStr != NULL) { gchar** tokens = g_strsplit(rpathStr, ":", 0); for(gint i = 0; tokens[i] != NULL; i++) { GString* candidateBuffer = g_string_new(NULL); /* rpath specifies directories, so look inside */ g_string_printf(candidateBuffer, "%s/%s", tokens[i], INTERPOSELIBSTR); gchar* candidate = g_string_free(candidateBuffer, FALSE); if(_main_isValidPathToPreloadLib(candidate)) { preloadArgValue = candidate; break; } else { g_free(candidate); } } g_strfreev(tokens); } g_free(rpathStr); } /* if we still didn't find our preload lib, that is a user error */ if(!preloadArgValue) { critical("can't find path to %s, did you specify an absolute path to an existing readable file?", INTERPOSELIBSTR); configuration_free(config); return EXIT_FAILURE; } /* now that we found the correct path to the preload lib, first remove any possibly * incomplete path that might exist in the command line args, and then replace it * with the path that we found and verified is correct. */ { /* first remove all preload options */ gchar** tokens = g_strsplit(commandBuffer->str, " ", 0); g_string_free(commandBuffer, TRUE); commandBuffer = NULL; for(gint i = 0; tokens[i] != NULL; i++) { /* use -1 to search the entire string */ if(!g_ascii_strncasecmp(tokens[i], "--preload=", 10)) { /* skip this key=value string */ } else if(!g_ascii_strncasecmp(tokens[i], "-p", 2)) { /* skip this key, and also the next arg which is the value */ i++; } else { if(commandBuffer) { g_string_append_printf(commandBuffer, " %s", tokens[i]); } else { commandBuffer = g_string_new(tokens[i]); } } } g_strfreev(tokens); /* now add back in the preload option */ g_string_append_printf(commandBuffer, " --preload=%s", preloadArgValue); } } message("setting up LD_STATIC_TLS_EXTRA environment"); /* compute the proper TLS size we need for dlmopen()ing all of the plugins, * but only do this if the user didn't manually specify a size */ if(g_environ_getenv(envlist, "LD_STATIC_TLS_EXTRA") == NULL) { gchar* staticTLSValue = _main_getStaticTLSValue(options, config, preloadArgValue); envlist = g_environ_setenv(envlist, "LD_STATIC_TLS_EXTRA", staticTLSValue, 0); message("we need %s total bytes of static TLS storage", staticTLSValue); g_free(staticTLSValue); } /* cleanup unused string */ if(preloadArgValue) { g_free(preloadArgValue); preloadArgValue = NULL; } /* are we running valgrind */ if(options_doRunValgrind(options)) { message("setting up environment for valgrind"); /* make glib friendlier to valgrind */ envlist = g_environ_setenv(envlist, "G_DEBUG", "gc-friendly", 0); envlist = g_environ_setenv(envlist, "G_SLICE", "always-malloc", 0); /* add the valgrind command and some default options */ g_string_prepend(commandBuffer, "valgrind --leak-check=full --show-reachable=yes --track-origins=yes --trace-children=yes --log-file=shadow-valgrind-%p.log --error-limit=no "); } else { /* The following can be used to add internal GLib memory validation that * will abort the program if it finds an error. This is only useful outside * of the valgrind context, as otherwise valgrind will complain about * the implementation of the GLib validator. * e.g. $ G_SLICE=debug-blocks shadow --file * * envlist = g_environ_setenv(envlist, "G_SLICE", "debug-blocks", 0); */ } /* keep track that we are relaunching shadow */ envlist = g_environ_setenv(envlist, "SHADOW_SPAWNED", "TRUE", 1); gchar* command = g_string_free(commandBuffer, FALSE); gchar** arglist = g_strsplit(command, " ", 0); g_free(command); configuration_free(config); message("environment was updated; shadow is relaunching now with new environment"); Logger* logger = logger_getDefault(); if(logger) { logger_setDefault(NULL); logger_unref(logger); } /* execvpe only returns if there is an error, otherwise the current process * image is replaced with a new process */ gint returnValue = execvpe(arglist[0], arglist, envlist); /* cleanup */ if(envlist) { g_strfreev(envlist); } if(arglist) { g_strfreev(arglist); } critical("** Error %i while re-launching shadow process: %s", returnValue, g_strerror(returnValue)); return EXIT_FAILURE; } /* we dont need to relaunch, so we can run the simulation */ /* make sure we have initialized static tls */ if(!_main_verifyStaticTLS()) { critical("** Shadow Setup Check Failed: LD_STATIC_TLS_EXTRA does not contain a nonzero value"); return EXIT_FAILURE; } /* make sure we have the shadow preload lib */ if(!_main_isValidPathToPreloadLib(options_getPreloadString(options))) { critical("** Shadow Setup Check Failed: cannot find absolute path to "INTERPOSELIBSTR""); return EXIT_FAILURE; } /* now load the preload library into shadow's namespace */ if(!_main_loadShadowPreload(options)) { critical("** Shadow Setup Check Failed: unable to load preload library"); return EXIT_FAILURE; } /* tell the preload lib we are ready for action */ extern int interposer_setShadowIsLoaded(int); int interposerResult = interposer_setShadowIsLoaded(1); if(interposerResult != 0) { /* it was not intercepted, meaning our preload library is not set up properly */ critical("** Shadow Setup Check Failed: preload library is not correctly interposing functions"); return EXIT_FAILURE; } message("startup checks passed, we are ready to start simulation"); /* pause for debugger attachment if the option is set */ if(options_doRunDebug(options)) { gint pid = (gint)getpid(); message("Pausing with SIGTSTP to enable debugger attachment (pid %i)", pid); g_printerr("** Pausing with SIGTSTP to enable debugger attachment (pid %i)\n", pid); raise(SIGTSTP); message("Resuming now"); } /* allocate and initialize our main simulation driver */ gint returnCode = 0; shadowMaster = master_new(options); message("log message buffering is enabled for efficiency"); logger_setEnableBuffering(logger_getDefault(), TRUE); if(shadowMaster) { /* run the simulation */ returnCode = master_run(shadowMaster); /* cleanup */ master_free(shadowMaster); shadowMaster = NULL; } message("%s simulation was shut down cleanly, returning code %i", SHADOW_VERSION_STRING, returnCode); return returnCode; }