static void fuse_destroyed() { logging_log("Main", LOGGING_LEVEL_INFO, "*** Got EXIT COMMAND from FUSE, termination sequence initiated..."); logging_log("Main", LOGGING_LEVEL_INFO, "Terminating all other threads..."); downloader_shutdown(); logging_log("Main", LOGGING_LEVEL_INFO, "All other threads have terminated, cleaning up..."); http_free(); downloader_free(); searcher_free(); filesystem_free(); providers_free(); configuration_free(); logging_log("Main", LOGGING_LEVEL_INFO, "Cleanup almost finished, cleaning up the logging subsystem and exiting..."); logging_free(); fclose(stdin); fclose(stdout); fclose(stderr); }
void cli_context_free (cli_context_t *ctx) { if (ctx->conn) { xmmsc_unref (ctx->conn); } if (ctx->mode == CLI_EXECUTION_MODE_SHELL) { readline_free (); } command_trie_free (ctx->commands); cli_cache_free (ctx->cache); configuration_free (ctx->config); cmdnames_free (ctx->cmdnames); g_free (ctx); }
void master_free(Master* master) { MAGIC_ASSERT(master); if(master->topology) { topology_free(master->topology); } if(master->dns) { dns_free(master->dns); } if(master->config) { configuration_free(master->config); } if(master->random) { random_free(master->random); } MAGIC_CLEAR(master); g_free(master); message("simulation master destroyed"); }
gint shadow_main(gint argc, gchar* argv[]) { /* check the compiled GLib version */ if (!GLIB_CHECK_VERSION(2, 32, 0)) { g_printerr("** GLib version 2.32.0 or above is required but Shadow was compiled against version %u.%u.%u\n", (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION); return -1; } if(GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION == 40) { g_printerr("** You compiled against GLib version %u.%u.%u, which has bugs known to break Shadow. Please update to a newer version of GLib.\n", (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION); return -1; } /* check the that run-time GLib matches the compiled version */ const gchar* mismatch = glib_check_version(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); if(mismatch) { g_printerr("** The version of the run-time GLib library (%u.%u.%u) is not compatible with the version against which Shadow was compiled (%u.%u.%u). GLib message: '%s'\n", glib_major_version, glib_minor_version, glib_micro_version, (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION, mismatch); return -1; } /* setup configuration - this fails and aborts if invalid */ gchar* cmds = g_strjoinv(" ", argv); gchar** cmdv = g_strsplit(cmds, " ", 0); Configuration* config = configuration_new(argc, cmdv); g_free(cmds); g_strfreev(cmdv); if(!config) { /* incorrect options given */ return -1; } else if(config->printSoftwareVersion) { g_printerr("%s running GLib v%u.%u.%u and IGraph v%s\n%s\n", SHADOW_VERSION_STRING, (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION, #if defined(IGRAPH_VERSION) IGRAPH_VERSION, #else "(n/a)", #endif SHADOW_INFO_STRING); configuration_free(config); return 0; } /* check environment for LD_PRELOAD */ gchar** envlist = g_get_environ(); gboolean preloadSuccess = _main_checkPreloadEnvironment(envlist); g_strfreev(envlist); gboolean respawned = g_getenv("SHADOW_SPAWNED") != NULL ? TRUE : FALSE; if(respawned) { /* if shadow already respawned once and LD_PRELOAD still isnt correct, * then the user will need to provide the correct path */ if(!preloadSuccess) { g_printerr("** Environment Check Failed: LD_PRELOAD does not contain an absolute path to "INTERPOSELIBSTR"\n"); return -1; } /* NOTE: we ignore valgrind and preload options during the respawn */ } else { /* if preload is not set, or the user added a preload library, * or we are going to run valgrind, we need to respawn */ if(config->preloads || config->runValgrind || !preloadSuccess) { gchar** envlist = _main_getSpawnEnviroment(config->preloads, config->runValgrind); gchar* cmds = g_strjoinv(" ", argv); gchar** cmdv = g_strsplit(cmds, " ", 0); GError* error = NULL; gint exitStatus = 0; gboolean spawnSuccess = config->runValgrind ? _main_spawnShadowWithValgrind(cmdv, envlist, &exitStatus, &error) : _main_spawnShadow(cmdv, envlist, &exitStatus, &error); g_free(cmds); g_strfreev(cmdv); g_strfreev(envlist); if(!spawnSuccess) { g_printerr("** Error %i while re-spawning shadow process: %s\n", error->code, error->message); return -1; } /* child was run */ return (exitStatus == 0) ? 0 : -1; } } utility_assert(preloadSuccess); /* tell the preaload lib we are ready for action */ extern void interposer_setShadowIsLoaded(); interposer_setShadowIsLoaded(); /* allocate and initialize our main simulation driver */ gint returnCode = 0; shadowMaster = master_new(config); if(shadowMaster) { /* run the simulation */ returnCode = master_run(shadowMaster); /* cleanup */ master_free(shadowMaster); shadowMaster = NULL; } configuration_free(config); g_printerr("** shadow returning code %i (%s)\n", returnCode, (returnCode == 0) ? "success" : "error"); return returnCode; }
Configuration* configuration_new(gint argc, gchar* argv[]) { /* get memory */ Configuration* c = g_new0(Configuration, 1); MAGIC_INIT(c); c->argstr = g_strjoinv(" ", argv); const gchar* required_parameters = "shadow.config.xml"; gint nRequiredXMLFiles = 1; c->context = g_option_context_new(required_parameters); g_option_context_set_summary(c->context, "Shadow - run real applications over simulated networks"); g_option_context_set_description(c->context, "Shadow is a unique discrete-event network simulator that runs real " "applications like Tor, and distributed systems of thousands of nodes " "on a single machine. Shadow combines the accuracy of emulation with the " "efficiency and control of simulation, achieving the best of both approaches."); /* set defaults */ c->initialTCPWindow = 10; c->interfaceBufferSize = 1024000; c->interfaceBatchTime = 10; c->randomSeed = 1; c->cpuThreshold = -1; c->cpuPrecision = 200; c->heartbeatInterval = 60; /* set options to change defaults for the main group */ c->mainOptionGroup = g_option_group_new("main", "Main Options", "Primary simulator options", NULL, NULL); const GOptionEntry mainEntries[] = { { "debug", 'd', 0, G_OPTION_ARG_NONE, &(c->debug), "Pause at startup for debugger attachment", NULL }, { "heartbeat-frequency", 'h', 0, G_OPTION_ARG_INT, &(c->heartbeatInterval), "Log node statistics every N seconds [60]", "N" }, { "heartbeat-log-level", 'j', 0, G_OPTION_ARG_STRING, &(c->heartbeatLogLevelInput), "Log LEVEL at which to print node statistics ['message']", "LEVEL" }, { "heartbeat-log-info", 'i', 0, G_OPTION_ARG_STRING, &(c->heartbeatLogInfo), "Comma separated list of information contained in heartbeat ('node','socket','ram') ['node']", "LIST"}, { "log-level", 'l', 0, G_OPTION_ARG_STRING, &(c->logLevelInput), "Log LEVEL above which to filter messages ('error' < 'critical' < 'warning' < 'message' < 'info' < 'debug') ['message']", "LEVEL" }, { "preload", 'p', 0, G_OPTION_ARG_STRING, &(c->preloads), "LD_PRELOAD environment VALUE to use for function interposition (/path/to/lib:...) [None]", "VALUE" }, { "runahead", 'r', 0, G_OPTION_ARG_INT, &(c->minRunAhead), "If set, overrides the automatically calculated minimum TIME workers may run ahead when sending events between nodes, in milliseconds [0]", "TIME" }, { "seed", 's', 0, G_OPTION_ARG_INT, &(c->randomSeed), "Initialize randomness for each thread using seed N [1]", "N" }, { "workers", 'w', 0, G_OPTION_ARG_INT, &(c->nWorkerThreads), "Run concurrently with N worker threads [0]", "N" }, { "valgrind", 'x', 0, G_OPTION_ARG_NONE, &(c->runValgrind), "Run through valgrind for debugging", NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, &(c->printSoftwareVersion), "Print software version and exit", NULL }, { NULL }, }; g_option_group_add_entries(c->mainOptionGroup, mainEntries); g_option_context_set_main_group(c->context, c->mainOptionGroup); /* now fill in the default plug-in examples option group */ c->pluginsOptionGroup = g_option_group_new("sim", "Simulation Examples", "Built-in simulation examples", NULL, NULL); const GOptionEntry pluginEntries[] = { { "file", 0, 0, G_OPTION_ARG_NONE, &(c->runFileExample), "Run basic HTTP file transfer simulation", NULL }, { NULL }, }; g_option_group_add_entries(c->pluginsOptionGroup, pluginEntries); g_option_context_add_group(c->context, c->pluginsOptionGroup); /* now fill in the network option group */ GString* sockrecv = g_string_new(""); g_string_printf(sockrecv, "Initialize the socket receive buffer to N bytes [%i]", (gint)CONFIG_RECV_BUFFER_SIZE); GString* socksend = g_string_new(""); g_string_printf(socksend, "Initialize the socket send buffer to N bytes [%i]", (gint)CONFIG_SEND_BUFFER_SIZE); c->networkOptionGroup = g_option_group_new("sys", "System Options", "Simulated system/network behavior", NULL, NULL); const GOptionEntry networkEntries[] = { { "cpu-precision", 0, 0, G_OPTION_ARG_INT, &(c->cpuPrecision), "round measured CPU delays to the nearest TIME, in microseconds (negative value to disable fuzzy CPU delays) [200]", "TIME" }, { "cpu-threshold", 0, 0, G_OPTION_ARG_INT, &(c->cpuThreshold), "TIME delay threshold after which the CPU becomes blocked, in microseconds (negative value to disable CPU delays) (experimental!) [-1]", "TIME" }, { "interface-batch", 0, 0, G_OPTION_ARG_INT, &(c->interfaceBatchTime), "Batch TIME for network interface sends and receives, in milliseconds [10]", "TIME" }, { "interface-buffer", 0, 0, G_OPTION_ARG_INT, &(c->interfaceBufferSize), "Size of the network interface receive buffer, in bytes [1024000]", "N" }, { "interface-qdisc", 0, 0, G_OPTION_ARG_STRING, &(c->interfaceQueuingDiscipline), "The interface queuing discipline QDISC used to select the next sendable socket ('fifo' or 'rr') ['fifo']", "QDISC" }, { "socket-recv-buffer", 0, 0, G_OPTION_ARG_INT, &(c->initialSocketReceiveBufferSize), sockrecv->str, "N" }, { "socket-send-buffer", 0, 0, G_OPTION_ARG_INT, &(c->initialSocketSendBufferSize), socksend->str, "N" }, { "tcp-congestion-control", 0, 0, G_OPTION_ARG_STRING, &(c->tcpCongestionControl), "Congestion control algorithm to use for TCP ('aimd', 'reno', 'cubic') ['cubic']", "TCPCC" }, { "tcp-ssthresh", 0, 0, G_OPTION_ARG_INT, &(c->tcpSlowStartThreshold), "Set TCP ssthresh value instead of discovering it via packet loss or hystart [0]", "N" }, { "tcp-windows", 0, 0, G_OPTION_ARG_INT, &(c->initialTCPWindow), "Initialize the TCP send, receive, and congestion windows to N packets [10]", "N" }, { NULL }, }; g_option_group_add_entries(c->networkOptionGroup, networkEntries); g_option_context_add_group(c->context, c->networkOptionGroup); /* parse args */ GError *error = NULL; if (!g_option_context_parse(c->context, &argc, &argv, &error)) { g_printerr("** %s **\n", error->message); gchar* helpString = g_option_context_get_help(c->context, TRUE, NULL); g_printerr("%s", helpString); g_free(helpString); configuration_free(c); return NULL; } /* make sure we have the required arguments. program name is first arg. * printing the software version requires no other args. running a * plug-in example also requires no other args. */ if(!(c->printSoftwareVersion) && !(c->runFileExample) && (argc < nRequiredXMLFiles + 1)) { g_printerr("** Please provide the required parameters **\n"); gchar* helpString = g_option_context_get_help(c->context, TRUE, NULL); g_printerr("%s", helpString); g_free(helpString); configuration_free(c); return NULL; } if(c->nWorkerThreads < 0) { c->nWorkerThreads = 0; } if(c->logLevelInput == NULL) { c->logLevelInput = g_strdup("message"); } if(c->heartbeatLogLevelInput == NULL) { c->heartbeatLogLevelInput = g_strdup("message"); } if(c->heartbeatLogInfo == NULL) { c->heartbeatLogInfo = g_strdup("node"); } if(c->heartbeatInterval < 1) { c->heartbeatInterval = 1; } if(c->initialTCPWindow < 1) { c->initialTCPWindow = 1; } if(c->interfaceBufferSize < CONFIG_MTU) { c->interfaceBufferSize = CONFIG_MTU; } c->interfaceBatchTime *= SIMTIME_ONE_MILLISECOND; if(c->interfaceBatchTime == 0) { /* we require at least 1 nanosecond b/c of time granularity */ c->interfaceBatchTime = 1; } if(c->interfaceQueuingDiscipline == NULL) { c->interfaceQueuingDiscipline = g_strdup("fifo"); } if(!c->initialSocketReceiveBufferSize) { c->initialSocketReceiveBufferSize = CONFIG_RECV_BUFFER_SIZE; c->autotuneSocketReceiveBuffer = TRUE; } if(!c->initialSocketSendBufferSize) { c->initialSocketSendBufferSize = CONFIG_SEND_BUFFER_SIZE; c->autotuneSocketSendBuffer = TRUE; } if(c->tcpCongestionControl == NULL) { c->tcpCongestionControl = g_strdup("cubic"); } c->inputXMLFilenames = g_queue_new(); for(gint i = 1; i < argc; i++) { GString* filename = g_string_new(argv[i]); g_queue_push_tail(c->inputXMLFilenames, filename); } if(socksend) { g_string_free(socksend, TRUE); } if(sockrecv) { g_string_free(sockrecv, TRUE); } return c; }
int configuration_load (configuration_t *conf, const char *filename) { FILE *file; char buffer[20 * 1024]; char *ptr, *ptrEnd; off_t state = 0; size_t bytes; char key_name[CONF_KEY_NAME_MAXLEN + 1]; char value[CONF_VALUE_MAXLEN + 1]; off_t nline = 1; size_t len; char c; conf_key_t *key = NULL; conf_key_list_t *current_list = NULL, *parent_list = NULL; configuration_free (conf); /* Open file for reading. */ file = fopen (filename, "rb"); if (!file) { fprintf (stderr, "Couldn't open [%s] for reading.\n", filename); return -1; } current_list = &conf->root; len = 0; do { bytes = fread (buffer, 1, sizeof (buffer), file); if (bytes <= 0) { *buffer = '\n'; ptrEnd = buffer + 1; } else { ptrEnd = buffer + bytes; } ptr = buffer; while (ptr < ptrEnd) { switch (state) { case 0: /* No keys/values found yet. */ if (*ptr == '{') { if ((!key) || (!current_list)) { /* No parent key present. */ fprintf (stderr, "[%s:%lu] No parent key present.\n", filename, nline); fclose (file); return -1; } parent_list = current_list; current_list = NULL; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } current_list = parent_list; parent_list = current_list->parent; key = NULL; } else if (*ptr == COMMENT) { state = 8; } else if (*ptr == '\n') { nline++; } else if ((IS_ALPHA (*ptr)) || (IS_DIGIT (*ptr)) || (strchr (SAFE, *ptr))) { if (current_list) { key = NULL; } *key_name = *ptr; len = 1; state = 1; } else if ((*ptr != '\r') && (*ptr != ' ') && (*ptr != '\t')) { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 1: /* Reading key. */ if ((IS_ALPHA (*ptr)) || (IS_DIGIT (*ptr)) || (strchr (SAFE, *ptr))) { if (len >= CONF_KEY_NAME_MAXLEN) { /* Key name too long. */ fprintf (stderr, "[%s:%lu] Key name too long (> %d).\n", filename, nline, CONF_KEY_NAME_MAXLEN); fclose (file); return -1; } key_name[len++] = *ptr; } else if ((*ptr == '\r') || (*ptr == ' ') || (*ptr == '\t')) { key_name[len] = 0; if ((key = add_key (conf, parent_list, key, ¤t_list, key_name, len)) == NULL) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } state = 2; } else if (*ptr == '\n') { key_name[len] = 0; if ((key = add_key (conf, parent_list, key, ¤t_list, key_name, len)) == NULL) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key->type = KEY_MIGHT_HAVE_CHILDREN; nline++; state = 0; } else if (*ptr == '=') { key_name[len] = 0; if ((key = add_key (conf, parent_list, key, ¤t_list, key_name, len)) == NULL) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } state = 3; } else if (*ptr == '{') { key_name[len] = 0; if ((key = add_key (conf, parent_list, key, ¤t_list, key_name, len)) == NULL) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key->type = KEY_MIGHT_HAVE_CHILDREN; parent_list = current_list; current_list = NULL; state = 0; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } key_name[len] = 0; if ((key = add_key (conf, parent_list, key, ¤t_list, key_name, len)) == NULL) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key->type = KEY_MIGHT_HAVE_CHILDREN; current_list = parent_list; parent_list = current_list->parent; key = NULL; state = 0; } else { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 2: /* Space after key. */ if (*ptr == '\n') { key->type = KEY_MIGHT_HAVE_CHILDREN; nline++; state = 0; } else if (*ptr == COMMENT) { key->type = KEY_MIGHT_HAVE_CHILDREN; state = 8; } else if (*ptr == '=') { state = 3; } else if (*ptr == '{') { key->type = KEY_MIGHT_HAVE_CHILDREN; parent_list = current_list; current_list = NULL; state = 0; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } key->type = KEY_MIGHT_HAVE_CHILDREN; current_list = parent_list; parent_list = current_list->parent; key = NULL; state = 0; } else if ((*ptr != '\r') && (*ptr != ' ') && (*ptr != '\t')) { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 3: /* After '='. */ if ((IS_ALPHA (*ptr)) || (IS_DIGIT (*ptr)) || (strchr (SAFE, *ptr))) { *value = *ptr; len = 1; state = 4; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } /* The key has no value. */ if (set_value (conf, key, "", 0) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } current_list = parent_list; parent_list = current_list->parent; key = NULL; state = 0; } else if (*ptr == '"') { len = 0; state = 6; } else if (*ptr == '\n') { /* The key has no value. */ if (set_value (conf, key, "", 0) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key = NULL; nline++; state = 0; } else if ((*ptr != '\r') && (*ptr != ' ') && (*ptr != '\t')) { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 4: /* Reading value. */ if ((IS_ALPHA (*ptr)) || (IS_DIGIT (*ptr)) || (strchr (SAFE, *ptr))) { if (len >= CONF_VALUE_MAXLEN) { /* Value too long. */ fprintf (stderr, "[%s:%lu] Value too long (> %d).\n", filename, nline, CONF_VALUE_MAXLEN); fclose (file); return -1; } value[len++] = *ptr; } else if ((*ptr == '\r') || (*ptr == ' ') || (*ptr == '\t')) { if (set_value (conf, key, value, len) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key = NULL; state = 5; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } if (set_value (conf, key, value, len) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } current_list = parent_list; parent_list = current_list->parent; key = NULL; state = 0; } else if (*ptr == '\n') { if (set_value (conf, key, value, len) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key = NULL; nline++; state = 0; } else { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 5: /* After having read value. */ if (*ptr == '\n') { nline++; state = 0; } else if (*ptr == '}') { if (!parent_list) { /* No parent list present. */ fprintf (stderr, "[%s:%lu] No parent list present.\n", filename, nline); fclose (file); return -1; } current_list = parent_list; parent_list = current_list->parent; state = 0; } else if (*ptr == COMMENT) { state = 8; } else if ((*ptr != '\r') && (*ptr != ' ') && (*ptr != '\t')) { /* Wrong character. */ fprintf (stderr, "[%s:%lu] Wrong character found: [%c].\n", filename, nline, *ptr); fclose (file); return -1; } break; case 6: /* The value is between quotation marks. */ if (*ptr == '"') { if (set_value (conf, key, value, len) < 0) { /* Couldn't allocate memory. */ fprintf (stderr, "[%s:%lu] Couldn't allocate memory.\n", filename, nline); fclose (file); return -1; } key = NULL; state = 5; } else if (*ptr == '\\') { state = 7; } else if (*ptr == '\n') { if (len >= CONF_VALUE_MAXLEN) { /* Value too long. */ fprintf (stderr, "[%s:%lu] Value too long (> %d).\n", filename, nline, CONF_VALUE_MAXLEN); fclose (file); return -1; } value[len++] = *ptr; nline++; } else { if (len >= CONF_VALUE_MAXLEN) { /* Value too long. */ fprintf (stderr, "[%s:%lu] Value too long (> %d).\n", filename, nline, CONF_VALUE_MAXLEN); fclose (file); return -1; } value[len++] = *ptr; } break; case 7: /* Escape character. */ if (*ptr == 'r') { c = '\r'; } else if (*ptr == 'n') { c = '\n'; } else if (*ptr == 't') { c = '\t'; } else { c = *ptr; } if (len >= CONF_VALUE_MAXLEN) { /* Value too long. */ fprintf (stderr, "[%s:%lu] Value too long (> %d).\n", filename, nline, CONF_VALUE_MAXLEN); fclose (file); return -1; } value[len++] = c; state = 6; break; case 8: /* Comment. */ if (*ptr == '\n') { nline++; state = 0; } break; } ptr++; } } while (bytes > 0); fclose (file); return (((state == 0) && (!parent_list))?0:-1); }
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; }