Exemplo n.º 1
0
/**
 * Prepare SQL queries and perform them.
 *
 * @param format printf-like string of SQL query
 * @param callback pointer to function to be called on results of SQL query
 * @param firstarg pointer to buffer for callback returned data
 * @return 0 (always, due to SQLite policy)
 */
int tagsistant_real_query(
	dbi_conn dbi,
	const char *format,
	int (*callback)(void *, dbi_result),
	char *file,
	int line,
	void *firstarg,
	...)
{
	va_list ap;
	va_start(ap, firstarg);

	/* check if connection has been created */
	if (NULL == dbi) {
		dbg('s', LOG_ERR, "ERROR! DBI connection was not initialized!");
		return(0);
	}

#if TAGSISTANT_USE_QUERY_MUTEX
	/* lock the connection mutex */
	g_mutex_lock(&tagsistant_query_mutex);
#endif

	/* check if the connection is alive */
	if (!dbi_conn_ping(dbi)	&& dbi_conn_connect(dbi) < 0) {
#if TAGSISTANT_USE_QUERY_MUTEX
		g_mutex_unlock(&tagsistant_query_mutex);
#endif
		dbg('s', LOG_ERR, "ERROR! DBI Connection has gone!");
		return(0);
	}

	/* replace all the single or double quotes with "<><>" in the format */
	gchar *escaped_format = g_regex_replace_literal(RX1, format, -1, 0, "<><>", 0, NULL);

	/* format the statement */
	gchar *statement = g_strdup_vprintf(escaped_format, ap);
	if (NULL == statement) {
#if TAGSISTANT_USE_QUERY_MUTEX
		/* lock the connection mutex */
		g_mutex_unlock(&tagsistant_query_mutex);
#endif
		dbg('s', LOG_ERR, "Null SQL statement");
		g_free(escaped_format);
		return(0);
	}

	/* prepend a backslash to all the single quotes inside the arguments */
	gchar *escaped_statement_tmp = g_regex_replace_literal(RX2, statement, -1, 0, "''", 0, NULL);

	/* replace "<><>" with a single quote */
	gchar *escaped_statement = g_regex_replace_literal(RX3, escaped_statement_tmp, -1, 0, "'", 0, NULL);

	/* log and do the query */
	dbg('s', LOG_INFO, "SQL from %s:%d: [%s]", file, line, escaped_statement);
	dbi_result result = dbi_conn_query(dbi, escaped_statement);

	tagsistant_dirty_logging(escaped_statement);
	tagsistant_wal(dbi, escaped_statement);

	g_free_null(escaped_format);
	g_free_null(escaped_statement_tmp);
	g_free_null(escaped_statement);

	/* call the callback function on results or report an error */
	int rows = 0;
	if (result) {

		if (callback) {
			while (dbi_result_next_row(result)) {
				callback(firstarg, result);
				rows++;
			}
		}
		dbi_result_free(result);

	} else {

		/* get the error message */
		const char *errmsg = NULL;
		dbi_conn_error(dbi, &errmsg);
		if (errmsg) dbg('s', LOG_ERR, "Error: %s.", errmsg);

	}

#if TAGSISTANT_USE_QUERY_MUTEX
	g_mutex_unlock(&tagsistant_query_mutex);
#endif

	return(rows);
}
Exemplo n.º 2
0
/**
 * Tagsistant main function, where everything starts...
 *
 * @param argc command line argument number
 * @param argv command line argument list
 * @return 0 when unmounted, a positive error number if something prevents the mount
 */
int main(int argc, char *argv[])
{
    struct fuse_args args = { 0, NULL, 0 };
	int res;

#ifndef MACOSX
	char *destfile = getenv("MALLOC_TRACE");
	if (destfile != NULL && strlen(destfile)) {
		fprintf(stderr, "\n *** logging g_malloc() calls to %s ***\n", destfile);
		mtrace();
	}
#endif

	/*
	 * set some values inside tagsistant context structure
	 */
	tagsistant.progname = argv[0];
	tagsistant.debug = FALSE;

	/*
	 * zero all the debug options
	 */
	int i = 0;
	for (; i < 128; i++) tagsistant.dbg[i] = 0;

	/*
	 * parse command line options
	 */
	GError *error = NULL;
	GOptionContext *context = g_option_context_new ("[repository path] <mount point>");
	g_option_context_add_main_entries (context, tagsistant_options, NULL);
	g_option_context_set_help_enabled (context, FALSE);
	if (!g_option_context_parse (context, &argc, &argv, &error)) {
		fprintf(stderr, "\n *** option parsing failed: %s\n", error->message);
		exit (1);
	}

	/*
	 * print the help screen
	 */
	if (tagsistant.show_help) {
		tagsistant_usage(argv[0], tagsistant.verbose);

		if (tagsistant.verbose) {
			fuse_opt_add_arg(&args, argv[0]);
			fuse_opt_add_arg(&args, "--help");
			tagsistant_fuse_main(&args, &tagsistant_oper);
		}

		exit(0);
	}

	/*
	 * show Tagsistant and FUSE version
	 */
	if (tagsistant.show_version) {
		fprintf(stderr, "Tagsistant (tagfs) v.%s (codename: %s)\nBuild: %s FUSE_USE_VERSION: %d\n",
			PACKAGE_VERSION, TAGSISTANT_CODENAME, TAGSISTANT_BUILDNUMBER, FUSE_USE_VERSION);

		fuse_opt_add_arg(&args, "-V");
		fuse_opt_add_arg(&args, "--version");
		tagsistant_fuse_main(&args, &tagsistant_oper);

		exit(0);
	}

	/*
	 * look for a mount point (and a repository too)
	 */
	if (tagsistant.remaining_opts && *tagsistant.remaining_opts) {
		if (tagsistant.remaining_opts[1] && *(tagsistant.remaining_opts[1])) {
			tagsistant.repository = *tagsistant.remaining_opts;
			tagsistant.mountpoint = *(tagsistant.remaining_opts + 1);

			// fprintf(stderr, "\n *** repository %s *** \n\n", tagsistant.repository);
			// fprintf(stderr, "\n *** mountpoint %s *** \n\n", tagsistant.mountpoint);
		} else {
			tagsistant.mountpoint = *tagsistant.remaining_opts;

			// fprintf(stderr, "\n *** mountpoint %s *** \n\n", tagsistant.mountpoint);
		}
	} else {
		fprintf(stderr, "\n *** No mountpoint provided *** \n");
		tagsistant_usage(argv[0], 0);
		exit(2);
	}

	/*
	 * default repository
	 */
	if (!tagsistant.repository) {
		tagsistant.repository = g_strdup_printf("%s/.tagsistant/", g_getenv("HOME"));
	}

	/*
	 * default tag-listing suffix
	 */
	if (!tagsistant.tags_suffix) {
		tagsistant.tags_suffix = g_strdup(TAGSISTANT_DEFAULT_TAGS_SUFFIX);
	}

	/*
	 * compute the triple tag detector regexp
	 */
	if (tagsistant.namespace_suffix) {
		tagsistant.triple_tag_regex = g_strdup_printf("\\%s$", tagsistant.namespace_suffix);
	} else {
		tagsistant.triple_tag_regex = g_strdup(TAGSISTANT_DEFAULT_TRIPLE_TAG_REGEX);
	}

	/* do some tuning on FUSE options */
//	fuse_opt_add_arg(&args, "-s");
//	fuse_opt_add_arg(&args, "-odirect_io");
	fuse_opt_add_arg(&args, "-obig_writes");
	fuse_opt_add_arg(&args, "-omax_write=32768");
	fuse_opt_add_arg(&args, "-omax_read=32768");
	fuse_opt_add_arg(&args, "-ofsname=tagsistant");
//	fuse_opt_add_arg(&args, "-ofstype=tagsistant");
//	fuse_opt_add_arg(&args, "-ouse_ino,readdir_ino");
//	fuse_opt_add_arg(&args, "-oallow_other");

#ifdef MACOSX
	fuse_opt_add_arg(&args, "-odefer_permissions");
	gchar *volname = g_strdup_printf("-ovolname=%s", tagsistant.mountpoint);
	fuse_opt_add_arg(&args, volname);
	g_free_null(volname);
#else
	/* fuse_opt_add_arg(&args, "-odefault_permissions"); */
#endif

	/*
	 * parse debugging flags
	 */
	if (tagsistant.debug_flags) {
		char *dbg_ptr = tagsistant.debug_flags;
		while (*dbg_ptr) {
			tagsistant.dbg[(int) *dbg_ptr] = 1;
			dbg_ptr++;
		}
	}

	/*
	 * Will run as a single threaded application?
	 */
	if (tagsistant.singlethread) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** operating in single thread mode ***\n");
		fuse_opt_add_arg(&args, "-s");
	}

	/*
	 * Will run readonly?
	 */
	if (tagsistant.readonly) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** mounting tagsistant read-only ***\n");
		fuse_opt_add_arg(&args, "-r");
	}

	/*
	 * Will run in foreground?
	 *
	 * A little explanation is required here. Many users reported tha autotagging
	 * does not work when Tagsistant is started without -f. FUSE -f switch just
	 * tells FUSE to not fork in the background. This means that Tagsistant keeps
	 * the console busy and never detaches. It's very useful for debugging but
	 * very annoying in everyday life. However when FUSE send Tagsistant in the
	 * background, something wrong happens with the scheduling of the autotagging
	 * thread. On the other hand, when the -f switch is used, autotagging works
	 * as expected.
	 *
	 * As a workaround, FUSE is always provided with the -f switch, while the
	 * background is reached by Tagsistant itself with a fork() call.
	 */
	fuse_opt_add_arg(&args, "-f");
	if (tagsistant.foreground) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** will run in foreground ***\n");
	}

	/*
	 * Will be verbose?
	 */
	if (tagsistant.verbose) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** will log verbosely ***\n");
		fuse_opt_add_arg(&args, "-d");
	}

	/*
	 * Have received DB options?
	 */
	if (tagsistant.dboptions) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** connecting to %s\n", tagsistant.dboptions);
	}

	/*
	 * The repository was provided?
	 */
	if (tagsistant.repository) {
		if (!tagsistant.quiet)
			fprintf(stderr, " *** saving repository in %s\n", tagsistant.repository);
	}

	/*
	 * add FUSE options
	 */
	gchar **fuse_opt = tagsistant.fuse_opts;
	while (fuse_opt && *fuse_opt) {
		fprintf(stderr, " *** Adding FUSE options %s\n", *fuse_opt);
		gchar *fuse_opt_string = g_strdup_printf("-o%s", *fuse_opt);
		fuse_opt_add_arg(&args, fuse_opt_string);
		fuse_opt++;
	}

	/*
	 * checking if mount point exists or can be created
	 */
	struct stat mst;
	if ((lstat(tagsistant.mountpoint, &mst) == -1) && (errno == ENOENT)) {
		if (mkdir(tagsistant.mountpoint, S_IRWXU|S_IRGRP|S_IXGRP) != 0) {
			// tagsistant_usage(tagsistant.progname);
			if (!tagsistant.quiet)
				fprintf(stderr, "\n *** Mountpoint %s does not exists and can't be created! ***\n", tagsistant.mountpoint);
			if (!tagsistant.show_config)
				exit(1);
		}
	}

	if (!tagsistant.quiet)
		fprintf(stderr, "\n"
		" Tagsistant (tagfs) v.%s (codename: %s)\n"
		" Build: %s FUSE_USE_VERSION: %d\n"
		" (c) 2006-2014 Tx0 <*****@*****.**>\n"
		" For license informations, see %s -h\n\n"
		, PACKAGE_VERSION, TAGSISTANT_CODENAME, TAGSISTANT_BUILDNUMBER
		, FUSE_USE_VERSION, tagsistant.progname
	);

	/* checking repository */
	if (!tagsistant.repository || (strcmp(tagsistant.repository, "") == 0)) {
		if (strlen(getenv("HOME"))) {
			g_free_null(tagsistant.repository);
			tagsistant.repository = g_strdup_printf("%s/.tagsistant", getenv("HOME"));
			if (!tagsistant.quiet)
				fprintf(stderr, " Using default repository %s\n", tagsistant.repository);
		} else {
			// tagsistant_usage(tagsistant.progname);
			if (!tagsistant.show_config) {
				if (!tagsistant.quiet)
					fprintf(stderr, "\n *** No repository provided with -r ***\n");
				exit(2);
			}
		}
	}

	/* removing last slash */
	int replength = strlen(tagsistant.repository) - 1;
	if (tagsistant.repository[replength] == '/') {
		tagsistant.repository[replength] = '\0';
	}

	/* checking if repository path begings with ~ */
	if (tagsistant.repository[0] == '~') {
		char *home_path = getenv("HOME");
		if (home_path != NULL) {
			char *relative_path = g_strdup(tagsistant.repository + 1);
			g_free_null(tagsistant.repository);
			tagsistant.repository = g_strdup_printf("%s%s", home_path, relative_path);
			g_free_null(relative_path);
			dbg('b', LOG_INFO, "Repository path is %s", tagsistant.repository);
		} else {
			dbg('b', LOG_ERR, "Repository path starts with '~', but $HOME was not available!");
		}
	} else 

	/* checking if repository is a relative path */
	if (tagsistant.repository[0] != '/') {
		dbg('b', LOG_ERR, "Repository path is relative [%s]", tagsistant.repository);
		char *cwd = getcwd(NULL, 0);
		if (cwd == NULL) {
			dbg('b', LOG_ERR, "Error getting working directory, will leave repository path as is");
		} else {
			gchar *absolute_repository = g_strdup_printf("%s/%s", cwd, tagsistant.repository);
			g_free_null(tagsistant.repository);
			tagsistant.repository = absolute_repository;
			dbg('b', LOG_ERR, "Repository path is %s", tagsistant.repository);
		}
	}

	struct stat repstat;
	if (lstat(tagsistant.repository, &repstat) == -1) {
		if(mkdir(tagsistant.repository, 755) == -1) {
			if (!tagsistant.quiet)
				fprintf(stderr, "\n *** REPOSITORY: Can't mkdir(%s): %s ***\n", tagsistant.repository, strerror(errno));
			exit(2);
		}
	}
	chmod(tagsistant.repository, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);

	/* opening (or creating) SQL tags database */
	tagsistant.tags = g_strdup_printf("%s/tags.sql", tagsistant.repository);

	/* tags.sql is also used by getattr() as a guaranteed file when asked for stats/ files */
	struct stat tags_st;
	if (-1 == stat(tagsistant.tags, &tags_st)) {
		int tags_fd = creat(tagsistant.tags, S_IRUSR|S_IWUSR);
		if (tags_fd) close(tags_fd);
	}

	/* checking file archive directory */
	tagsistant.archive = g_strdup_printf("%s/archive/", tagsistant.repository);

	if (lstat(tagsistant.archive, &repstat) == -1) {
		if(mkdir(tagsistant.archive, 755) == -1) {
			if (!tagsistant.quiet)
				fprintf(stderr, "\n *** ARCHIVE: Can't mkdir(%s): %s ***\n", tagsistant.archive, strerror(errno));
			exit(2);
		}
	}
	chmod(tagsistant.archive, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);

	dbg('b', LOG_INFO, "Debug is enabled: %s", tagsistant.debug ? "yes" : "no");

	umask(0);

#ifdef _DEBUG_SYSLOG
	tagsistant_init_syslog();
#endif

#if REGISTER_CLEANUP
	signal(2,  cleanup); /* SIGINT */
	signal(11, cleanup); /* SIGSEGV */
	signal(15, cleanup); /* SIGTERM */
#endif

#if !(GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 32)
	/*
	 * init the threading library
	 */
	g_thread_init(NULL);
#endif

	/*
	 * load repository.ini
	 */
	tagsistant_manage_repository_ini();

	/*
	 * loading plugins
	 */
	tagsistant_plugin_loader();

	/*
	 * fix the archive
	 */
	tagsistant_fix_archive();

	dbg('b', LOG_INFO, "Mounting filesystem");

	dbg('b', LOG_INFO, "Fuse options:");
	int fargc = args.argc;
	while (fargc) {
		dbg('b', LOG_INFO, "%.2d: %s", fargc, args.argv[fargc]);
		fargc--;
	}

	/*
	 * Send Tagsistant in the background, if applies
	 */
	if (!tagsistant.foreground) {
		pid_t pid = fork();
		if (pid) {
			if (!tagsistant.quiet)
				fprintf(stderr, "\n *** going in the background (PID: %d) ***\n", pid);
			exit(0);
		}
	}

	/*
	 * initialize db connection, SQL schema,
	 * an other subsystems
	 */
	tagsistant_db_init();
	tagsistant_create_schema();
	tagsistant_wal_sync();
	tagsistant_path_resolution_init();
	tagsistant_reasoner_init();
	tagsistant_utils_init();
	tagsistant_deduplication_init();

	/* SQLite requires tagsistant to run in single thread mode */
	if (tagsistant.sql_database_driver == TAGSISTANT_DBI_SQLITE_BACKEND) {
		// tagsistant.singlethread = TRUE;
		// fuse_opt_add_arg(&args, "-s");
	}

	/*
	 * print configuration if requested
	 */
	if (tagsistant.show_config) tagsistant_show_config();

	/* add the mount point */
	fuse_opt_add_arg(&args, tagsistant.mountpoint);

#if HAVE_SYS_XATTR_H
	if (tagsistant.enable_xattr) {
		tagsistant_oper.setxattr    = tagsistant_setxattr;
		tagsistant_oper.getxattr    = tagsistant_getxattr;
		tagsistant_oper.listxattr   = tagsistant_listxattr;
		tagsistant_oper.removexattr = tagsistant_removexattr;
	}
#endif

	/*
	 * run FUSE main event loop
	 */
	res = tagsistant_fuse_main(&args, &tagsistant_oper);
	fuse_opt_free_args(&args);

	/*
	 * unloading plugins
	 */
	tagsistant_plugin_unloader();

	/* free memory to better perform memory leak profiling */
	g_free_null(tagsistant.dboptions);
	g_free_null(tagsistant.repository);
	g_free_null(tagsistant.archive);
	g_free_null(tagsistant.tags);

	return(res);
}
Exemplo n.º 3
0
/**
 * magmad main function.
 *
 * @param argc number of arguments on command line
 * @param argv vector of arguments on command line
 * @return 0 on success, positive number on error
 */
int main(int argc, char **argv)
{
#if GLIB_MAJOR_VERSION < 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 34)
	/* init GLib thread and type system */
	g_type_init();
#endif

	/* blank umask */
	umask(0);

#ifdef MAGMA_DEBUG_SYSLOG
	/* open syslog connection */
	openlog(magma_environment.progname, LOG_PID, LOG_DAEMON);
#endif

	/* init the log system */
	magma_init_log();

	/* allowing core dumps */
	struct rlimit rlim;
	rlim.rlim_cur = RLIM_INFINITY;
	rlim.rlim_max = RLIM_INFINITY;

	/* read command line */
	magma_parse_args(argc, argv, &magma_environment);

	/* setup process resources */
	int resout = setrlimit(RLIMIT_CORE, &rlim);
	if (-1 == resout) {
		dbg(LOG_ERR, DEBUG_ERR, "While setting core dump size: %s", strerror(errno));
	}

#ifdef MAGMA_ENABLE_DUMP_TO_FILE
	init_dump_to_file("/tmp/magmad.dump");
#endif /* MAGMA_ENABLE_DUMP_TO_FILE */

	/* print debug mask */
	char *dmask = magma_print_log_mask(magma_environment.log);
	dbg(LOG_INFO, DEBUG_BOOT, "Enabled log channels: %s", dmask);
	g_free_null(dmask);

	dbg(LOG_INFO, DEBUG_BOOT, "PID: %d", getpid());

	dbg(LOG_INFO, DEBUG_BOOT, " sizeof(ino_t) == %lu [expecting 8] [config.h says %d]", sizeof(ino_t), SIZEOF_INO_T);
	dbg(LOG_INFO, DEBUG_BOOT, "sizeof(size_t) == %lu [expecting 4] [config.h says %d]", sizeof(size_t), SIZEOF_SIZE_T);
	dbg(LOG_INFO, DEBUG_BOOT, " sizeof(dev_t) == %lu [expecting 8] [config.h says %d]", sizeof(dev_t), SIZEOF_DEV_T);
	dbg(LOG_INFO, DEBUG_BOOT, "sizeof(mode_t) == %lu [expecting 4] [config.h says %d]", sizeof(mode_t), SIZEOF_MODE_T);

	/*
	 * if debug mask includes DEBUG_MALLOC,
	 * memory debugging is enabled. ENV variable MALLOC_TRACE should
	 * contain the name of stack trace file to be later analyzed with
	 * mtrace command line utility. filename is set to failsafe value
	 * here but can be overwritten on program start
	 */
	if (magma_environment.log[DEBUG_MALLOC]) {
		gchar *tracefile = g_strdup_printf("/tmp/magmad.memorytrace.%s", magma_environment.nickname);
		if (getenv("MALLOC_TRACE") == NULL)
			setenv("MALLOC_TRACE", tracefile, 1);
		dbg(LOG_INFO, DEBUG_BOOT, "Enabling memory trace in file %s", getenv("MALLOC_TRACE"));
		mtrace();
		g_free_null(tracefile);
	}

	/* creates the first node representing this node */
	magma_config_myself(
		magma_environment.nickname,
		magma_environment.servername,
		magma_environment.ipaddr,
		magma_environment.port,
		magma_environment.bandwidth,
		magma_environment.storage,
		magma_environment.hashpath);

	dbg(LOG_INFO, DEBUG_BOOT, "Myself created as follow:");
	dbg(LOG_INFO, DEBUG_BOOT, "...ip address: %s", magma_environment.ipaddr);
	dbg(LOG_INFO, DEBUG_BOOT, "....node port: %d", magma_environment.port);
	dbg(LOG_INFO, DEBUG_BOOT, "....node name: %s", magma_environment.nickname);
	dbg(LOG_INFO, DEBUG_BOOT, "....fqdn name: %s", magma_environment.servername);
	dbg(LOG_INFO, DEBUG_BOOT, "....bandwidth: %d", magma_environment.bandwidth);
	dbg(LOG_INFO, DEBUG_BOOT, "......storage: %d", magma_environment.storage);

	/*
	 * initialize the flare system
	 */
	magma_flare_system_init();

	/*
	 * Enable node protocol
	 */
	magma_open_node_socket();

	/*
	 * Build the network
	 */
	magma_build_network(
		magma_environment.bootstrap,
		magma_environment.bootserver,
		MAGMA_NODE_PORT,
		MAGMA_START_BALANCER);

	dbg(LOG_INFO, DEBUG_BOOT, "lava ring created! first node is %s", lava->first_node->node_name);

	/*
	 * report on syslog about network
	 */
	magma_volcano *nodep = lava->first_node;
	dbg(LOG_INFO, DEBUG_BOOT, "MAGMA network is formed by %d nodes", lava->participants);
	do {
		dbg(LOG_INFO, DEBUG_BOOT, "Node %s has sector: ", nodep->node_name);
		dbg(LOG_INFO, DEBUG_BOOT, "  [%s", nodep->start_key);
		dbg(LOG_INFO, DEBUG_BOOT, "   %s]", nodep->stop_key);
		nodep = nodep->next;
	} while (nodep && nodep != lava->first_node);

#ifdef MAGMA_ENABLE_NFS_INTERFACE
	magma_start_nfs_interface();
#endif

	/*
	 * Enable console protocol
	 */
	magma_open_console_socket();

	/*
	 * Enable flare protocol TCP socket
	 */
	magma_open_flare_socket();

	/*
	 * Create the GLib main loop
	 */
	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
	g_timeout_add(2000, magma_save_this_node, NULL);

	/* start event cycle */
	g_main_loop_run(loop);
	g_main_loop_unref(loop);

	dbg(LOG_INFO, DEBUG_BOOT, "terminating. Good bye ;-)");

	return(0);
}
Exemplo n.º 4
0
/**
 * magmad command line parsing code 
 *
 * @param argc number of command line arguments
 * @param argv vector of command line arguments
 */
void magma_parse_args(int argc, char **argv)
{
	memset(magma_environment.log, 0, 255);

	magma_environment.progname = *argv;						/* saving program name */
	magma_environment.port = MAGMA_PORT;					/* default port */
	magma_environment.servername = g_strdup("");			/* default server name */
	magma_environment.nickname = g_strdup("");				/* default server nickname */
	magma_environment.ipaddr = g_strdup("");				/* default server IP address */
	magma_environment.hashpath = g_strdup("");				/* default server path for local storage */
	magma_environment.bootserver = NULL;					/* default remote boot server */
	magma_environment.secretkey = NULL;
	magma_environment.bandwidth = MAGMA_DEFAULT_BANDWIDTH;	/* Declared bandwidth */
	magma_environment.storage = MAGMA_DEFAULT_STORAGE;		/* Declared storage */
	magma_environment.bootstrap = 0;						/* If true, this node should bootstrap a new network, if false this node should join an existing one */

	/*
	 * cycling through options
	 */
	char c;
	while ((c = getopt(argc, argv, "blhHA?D:Tp:i:n:s:d:w:r:k:" )) != -1) {
		switch (c) {
			case 'b':
				if (magma_environment.bootserver) {
					dbg(LOG_ERR, DEBUG_BOOT, "Bootstrap and remote server can't be specified together. Exiting now.");
					exit(1);
				}
				magma_environment.bootstrap = 1;
				break;
			case 'h':
			case 'H':
				magma_usage(NULL);
				break;
			case 'A':
				memset(magma_environment.log, 1, 255);
				dbg(LOG_INFO, DEBUG_BOOT, "Enabling all debug statements");
				break;
			case 'D':
				if (optarg) {
					magma_environment.logstring = g_strdup(optarg);
					dbg(LOG_INFO, DEBUG_BOOT, "Setting debug mask to %s", magma_environment.logstring);
				}
				break;
			case 'p':
				if (optarg) {
					magma_environment.port = atol(optarg);
					dbg(LOG_INFO, DEBUG_BOOT, "port: %d", magma_environment.port);
				}
				break;
			case 'i':
				if (optarg) {
					g_free_null(magma_environment.ipaddr);
					magma_environment.ipaddr = g_strdup(optarg);
					dbg(LOG_INFO, DEBUG_BOOT, "Server local IP addr: %s", magma_environment.ipaddr);
				}
				break;
			case 'n':
				if (optarg) {
					g_free_null(magma_environment.nickname);
					magma_environment.nickname = g_strndup(optarg, 255);
					dbg(LOG_INFO, DEBUG_BOOT, "Server Nickname: %s", magma_environment.nickname);
				}
				break;
			case 's':
				if (optarg) {
					g_free_null(magma_environment.servername);
					magma_environment.servername = g_strndup(optarg, 255);
					dbg(LOG_INFO, DEBUG_BOOT, "Server FQDN name: %s", magma_environment.servername);
				}
				break;
			case 'd':
				if (optarg) {
					g_free_null(magma_environment.hashpath);
					magma_environment.hashpath = g_strdup(optarg);
					if (magma_environment.hashpath[strlen(magma_environment.hashpath) - 1] == '/') {
						magma_environment.hashpath[strlen(magma_environment.hashpath) - 1] = '\0';
					}
					dbg(LOG_INFO, DEBUG_BOOT, "Hash Dir Path: %s", magma_environment.hashpath);
				}
				break;
			case 'w':
				if (optarg) {
					magma_environment.bandwidth = atol(optarg);
					dbg(LOG_INFO, DEBUG_BOOT, "Declared Bandwidth: %dKbit/s", magma_environment.bandwidth);
				}
				break;
			case 'r':
				if (optarg) {
					if (magma_environment.bootstrap) {
						dbg(LOG_ERR, DEBUG_BOOT, "Bootstrap and remote server can't be specified together. Exiting now.");
						exit(1);
					}
					g_free_null(magma_environment.bootserver);
					char *portp = NULL;
					if ((portp = rindex(optarg,':')) != NULL) {
						*portp = '\0';
						portp++;
						magma_environment.bootport = atoi(portp);
					} else {
						magma_environment.bootport = MAGMA_PORT;
					}
					magma_environment.bootserver = g_strdup(optarg);
					magma_environment.bootstrap = 0;
					dbg(LOG_INFO, DEBUG_BOOT, "Remote boot server: %s:%u", magma_environment.bootserver, magma_environment.bootport);
				}
				break;
			case 'k':
				if (optarg) {
					magma_environment.secretkey = g_strdup(optarg);
					dbg(LOG_INFO, DEBUG_BOOT, "Secret Key is [%s]", magma_environment.secretkey);
				}
				break;
			case '?':
				if (isprint(optopt)) {
					dbg(LOG_ERR, DEBUG_ERR, "Unknown option -%c", optopt);
					magma_usage(NULL);
				} else {
					dbg(LOG_INFO, DEBUG_BOOT, "Unknown option character \\x%x", optopt);
				}
				break;
			default:
				break;
		}
	}

	magma_expand_log_channels(&magma_environment);

	GResolver *resolver = g_resolver_get_default();

	/*
	 * try to replace default nickname with a valid one from the DNS
	 */
	if (!strlen(magma_environment.nickname)) {
		char *hostname = malloc(HOST_NAME_MAX);
		if (hostname != NULL) {
			if (gethostname(hostname, HOST_NAME_MAX) == 0) {
				g_free_null(magma_environment.nickname);
				magma_environment.nickname = g_strdup(hostname);
			}
			g_free_null(hostname);
		}
	}
	
	/*
	 * try to replace default server name with a valid one from the DNS
	 */
	if (!strlen(magma_environment.servername)) {
		/*
		struct hostent *h = gethostbyname(magma_environment.nickname);
		if (h != NULL) {
			g_free_null(magma_environment.servername);
			magma_environment.servername = g_strdup(h->h_name);
			if (index(magma_environment.servername, '.') == NULL) {
				// server name should be a fully qualified name!!!
				magma_usage("Server Fully Qualified Name is not Fully Qualified!");
			}
		}
		*/

		GList *addr = g_resolver_lookup_by_name(resolver, magma_environment.nickname, NULL, NULL);
		gchar *addr_string = g_list_nth_data(addr, 0);

		if (!addr_string) {
			gchar *string = g_strdup_printf(
				"No FQDN provided and magmad was unable to resolve one from %s",
				magma_environment.nickname);
			magma_usage(string);
		} else {
			if (!index(magma_environment.servername, '.')) {
				magma_usage("Server Fully Qualified Name is not Fully Qualified!");
			}
		}
	}
	
	/*
	 * Without a valid IP address the server can't start.
	 * Try to resolve magma_environment.servername and exit
	 * if the operation fails
	 */
	if (inet_aton(magma_environment.ipaddr, NULL) == 0) {
		GList *addr = g_resolver_lookup_by_name(resolver, magma_environment.servername, NULL, NULL);
		gchar *addr_string = g_list_nth_data(addr, 0);

		if (!addr_string) {
			gchar *string = g_strdup_printf("No IP address provided and can't resolve %s", magma_environment.servername);
			magma_usage(string);
		} else {
			magma_environment.ipaddr = addr_string;
		}
	}

	/*
	 * if neither boot server or bootstrap has been specified, the
	 * server should load its state from last saved lava topology
	 */
	if (!magma_environment.bootstrap && !magma_environment.bootserver) {
		if (!magma_environment.nickname || !strlen(magma_environment.nickname)) {
			magma_usage("Please specify server nickname to allow status loading from disk!");
		}
	} else if (magma_environment.secretkey == NULL ) {
		magma_usage("No secret key specified! Network can't be created or joined!");
	}

	g_object_unref(resolver);
}