#include "para.h"
#include "error.h"
#include "string.h"
+#include "lsu.h"
+#include "fd.h"
static int lsu_lopsub_error(int ret, char **errctx, char **result, unsigned *num_chars)
{
*num_chars = n;
return 1;
}
+
+/**
+ * Merge command line options and config file options.
+ *
+ * This function parses the options stored in the configuration file and merges
+ * them with the currently effective options. If the application supports
+ * config files, it is supposed to call this after the command line options
+ * have been parsed. If the application also supports config file reloading,
+ * the function will be called for that purpose.
+ *
+ * \param path Config file path, usually the argument to --config-file.
+ * \param dflt Relative to ~/.paraslash, ignored if path is not NULL.
+ * \param lpr Value-result pointer.
+ * \param cmd Passed to lls_parse() and lls_merge().
+ * \param suite Needed to tell whether cmd is the supercommand.
+ * \param flags See enum \ref lsu_merge_cf_flags.
+ *
+ * The function does nothing if path is NULL and the default config file does
+ * not exist, or if path is an empty file. Otherwise, the options of the config
+ * file are parsed, the parse result is merged with lpr, and the merged parse
+ * result is returned via lpr.
+ *
+ * By default, lpr is freed if the merge was done, but this can be changed by
+ * including MCF_DONT_FREE flags.
+ *
+ * \return Zero if there was nothing to do, one if the config file options were
+ * merged successfully, negative error code on failure. It is considered an error
+ * if path is given, but the file does not exist.
+ */
+int lsu_merge_config_file_options(const char *path, const char *dflt,
+ struct lls_parse_result **lpr, const struct lls_command *cmd,
+ const struct lls_suite *suite, unsigned flags)
+{
+ int ret;
+ void *map;
+ size_t sz;
+ int cf_argc;
+ char *cf, **cf_argv, *errctx = NULL;
+ struct lls_parse_result *old_lpr = *lpr, *cf_lpr, *merged_lpr;
+ const char *subcmd_name;
+
+ if (path)
+ cf = para_strdup(path);
+ else {
+ char *home = para_homedir();
+ cf = make_message("%s/.paraslash/%s", home, dflt);
+ free(home);
+ }
+ ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+ if (ret < 0) {
+ if (ret == -E_EMPTY)
+ ret = 0;
+ else if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && !path)
+ ret = 0;
+ else
+ PARA_ERROR_LOG("failed to mmap config file %s\n", cf);
+ goto free_cf;
+ }
+ subcmd_name = (lls_cmd(0, suite) == cmd)? NULL : lls_command_name(cmd);
+ ret = lls(lls_convert_config(map, sz, subcmd_name, &cf_argv, &errctx));
+ para_munmap(map, sz);
+ if (ret < 0) {
+ PARA_ERROR_LOG("failed to convert config file %s\n", cf);
+ goto lopsub_error;
+ }
+ cf_argc = ret;
+ ret = lls(lls_parse(cf_argc, cf_argv, cmd, &cf_lpr, &errctx));
+ lls_free_argv(cf_argv);
+ if (ret < 0) {
+ PARA_ERROR_LOG("failed to parse config file %s\n", cf);
+ goto lopsub_error;
+ }
+ if (flags & MCF_OVERRIDE)
+ ret = lls(lls_merge(cf_lpr, old_lpr, cmd, &merged_lpr, &errctx));
+ else
+ ret = lls(lls_merge(old_lpr, cf_lpr, cmd, &merged_lpr, &errctx));
+ lls_free_parse_result(cf_lpr, cmd);
+ if (ret < 0) {
+ PARA_ERROR_LOG("could not merge options in %s\n", cf);
+ goto lopsub_error;
+ }
+ if (!(flags & MCF_DONT_FREE))
+ lls_free_parse_result(old_lpr, cmd);
+ *lpr = merged_lpr;
+ ret = 1;
+ goto free_cf;
+lopsub_error:
+ assert(ret < 0);
+ if (errctx)
+ PARA_ERROR_LOG("lopsub error: %s\n", errctx);
+ free(errctx);
+free_cf:
+ free(cf);
+ return ret;
+}
const struct lls_suite *suite,
const char *(*aux_info_cb)(unsigned cmd_num, bool verbose),
char **result, unsigned *num_chars);
+
+/** Flags for \ref lsu_merge_config_file_options(). */
+enum lsu_merge_cf_flags {
+ /**
+ * Whether the options specified in the configuration file should
+ * override the currently effective options. At application startup
+ * this is usually unset so that command line options take precedence
+ * over config file options. However, if the application supports
+ * re-reading the configuration, it can make sense to enable this flag.
+ */
+ MCF_OVERRIDE = 1,
+ /**
+ * After the two lopsub parse results have been merged, the merged
+ * parse result usually becomes the effective configuration and the
+ * parse result which corresponds to the former effective options is no
+ * longer needed. Therefore \ref lsu_merge_config_file_options() frees
+ * this former parse result by default. This flag instructs the
+ * function to keep it. This is mostly useful if the application
+ * supports re-reading the config file so that the parse result which
+ * corresponds to the command line options is kept for future calls to
+ * \ref lsu_merge_config_file_options().
+ */
+ MCF_DONT_FREE = 2,
+};
+
+int lsu_merge_config_file_options(const char *path, const char *dflt,
+ struct lls_parse_result **lpr, const struct lls_command *cmd,
+ const struct lls_suite *suite, unsigned flags);
#include "server.lsg.h"
#include "para.h"
#include "error.h"
+#include "lsu.h"
#include "crypt.h"
#include "afh.h"
#include "string.h"
void parse_config_or_die(bool reload)
{
int ret;
- char *cf = NULL, *errctx = NULL, *user_list_file = NULL;
- void *map;
- size_t sz;
- int cf_argc;
- char **cf_argv;
- struct lls_parse_result *cf_lpr, *merged_lpr;
- char *home = para_homedir();
-
- if (OPT_GIVEN(CONFIG_FILE))
- cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
- else
- cf = make_message("%s/.paraslash/server.conf", home);
- if (!mmd || getpid() != afs_pid) {
- if (OPT_GIVEN(USER_LIST))
- user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
- else
- user_list_file = make_message("%s/.paraslash/server.users", home);
- }
- free(home);
- ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
- if (ret < 0) {
- if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
- goto free_cf;
- if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
- goto free_cf;
- server_lpr = cmdline_lpr;
- goto success;
- }
- ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
- para_munmap(map, sz);
- if (ret < 0)
- goto free_cf;
- cf_argc = ret;
- ret = lls(lls_parse(cf_argc, cf_argv, CMD_PTR, &cf_lpr, &errctx));
- lls_free_argv(cf_argv);
- if (ret < 0)
- goto free_cf;
- if (reload) /* config file overrides command line */
- ret = lls(lls_merge(cf_lpr, cmdline_lpr, CMD_PTR, &merged_lpr,
- &errctx));
- else /* command line options override config file options */
- ret = lls(lls_merge(cmdline_lpr, cf_lpr, CMD_PTR, &merged_lpr,
- &errctx));
- lls_free_parse_result(cf_lpr, CMD_PTR);
- if (ret < 0)
- goto free_cf;
+ unsigned flags = MCF_DONT_FREE;
+
if (server_lpr != cmdline_lpr)
lls_free_parse_result(server_lpr, CMD_PTR);
- server_lpr = merged_lpr;
-success:
+ server_lpr = cmdline_lpr;
+ if (reload)
+ flags |= MCF_OVERRIDE;
+ ret = lsu_merge_config_file_options(OPT_STRING_VAL(CONFIG_FILE),
+ "server.conf", &server_lpr, CMD_PTR, server_suite, flags);
+ if (ret < 0) {
+ PARA_EMERG_LOG("failed to parse config file: %s\n",
+ para_strerror(-ret));
+ exit(EXIT_FAILURE);
+ }
daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
if (OPT_GIVEN(LOGFILE)) {
daemon_set_logfile(OPT_STRING_VAL(LOGFILE));
if (OPT_GIVEN(LOG_TIMING))
daemon_set_flag(DF_LOG_TIMING);
daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
- if (user_list_file)
+ if (!reload || getpid() != afs_pid) {
+ char *user_list_file;
+ if (OPT_GIVEN(USER_LIST))
+ user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
+ else {
+ char *home = para_homedir();
+ user_list_file = make_message("%s/.paraslash/server.users", home);
+ free(home);
+ }
init_user_list(user_list_file);
- ret = 1;
-free_cf:
- free(cf);
- free(user_list_file);
- if (ret < 0) {
- if (errctx)
- PARA_ERROR_LOG("%s\n", errctx);
- free(errctx);
- PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- exit(EXIT_FAILURE);
+ free(user_list_file);
}
+ return;
}
/*