Ejemplo n.º 1
0
Archivo: main.c Proyecto: jucs/musicfs
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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
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");
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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, &current_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, &current_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, &current_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, &current_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, &current_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);
}
Ejemplo n.º 7
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;
}