Config files are currently read using glib's g_key_file_load_from_file function which is very inconvenient because it's limited by design to read only from "regular data files" in a filesystem. Because of this limitation notmuch can't read configs from pipes, fifos, sockets, stdin, etc. Not even "notmuch --config=/dev/stdin" works: Error reading configuration file /dev/stdin: Not a regular file So replace g_key_file_load_from_file with g_key_file_load_from_data which gives us much more freedom to read configs from multiple sources. This also helps the more security sensitive users: If someone has private information in the config file, it can be encrypted on disk, then decrypted in RAM and passed through a pipe directly to notmuch without the use of intermediate plain text files. Signed-off-by: Ioan-Adrian Ratiu <adi@adirat.com> --- notmuch-config.c | 53 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index bd52790..569cf0b 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -205,33 +205,62 @@ get_username_from_passwd_file (void *ctx) static notmuch_bool_t get_config_from_file (notmuch_config_t *config, notmuch_bool_t create_new) { + #define BUF_SIZE 4096 + char buffer[BUF_SIZE]; + size_t content_size = 1; // includes NULL + char *config_str = NULL; GError *error = NULL; - notmuch_bool_t ret = FALSE; - if (g_key_file_load_from_file (config->key_file, config->filename, - G_KEY_FILE_KEEP_COMMENTS, &error)) - return TRUE; - - if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) { + FILE *fp = fopen(config->filename, "r"); + if (fp == NULL) { /* If create_new is true, then the caller is prepared for a * default configuration file in the case of FILE NOT FOUND. */ if (create_new) { config->is_new = TRUE; - ret = TRUE; + return TRUE; } else { - fprintf (stderr, "Configuration file %s not found.\n" + fprintf (stderr, "Error opening config file '%s': %s\n" "Try running 'notmuch setup' to create a configuration.\n", + config->filename, strerror(errno)); + return FALSE; + } + } + + config_str = talloc_zero_array (config, char, BUF_SIZE); + if (config_str == NULL) { + fprintf (stderr, "Error reading '%s': Out of memory\n", config->filename); + return FALSE; + } + + while (fgets (buffer, BUF_SIZE, fp)) { + content_size += strlen(buffer); + config_str = talloc_realloc(config, config_str, char, content_size); + if (config_str == NULL) { + fprintf (stderr, "Error reading '%s': Failed to reallocate memory\n", config->filename); + return FALSE; } - } else { - fprintf (stderr, "Error reading configuration file %s: %s\n", - config->filename, error->message); + strcat (config_str, buffer); + } + + if (ferror (fp)) { + fprintf (stderr, "Error reading '%s': I/O error\n", config->filename); + return FALSE; } + fclose(fp); + + if (g_key_file_load_from_data (config->key_file, config_str, strlen(config_str), + G_KEY_FILE_KEEP_COMMENTS, &error)) + return TRUE; + + fprintf (stderr, "Error parsing config file '%s': %s\n", + config->filename, error->message); + g_error_free (error); - return ret; + return FALSE; } /* Open the named notmuch configuration file. If the filename is NULL, -- 2.10.2