about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/common.c97
-rw-r--r--src/common.h4
-rw-r--r--src/config/account.c47
3 files changed, 57 insertions, 91 deletions
diff --git a/src/common.c b/src/common.c
index fc1f60ab..658a3a4e 100644
--- a/src/common.c
+++ b/src/common.c
@@ -471,92 +471,35 @@ get_mentions(gboolean whole_word, gboolean case_sensitive, const char* const mes
     return mentions;
 }
 
-/*
- * Take an NULL-terminated array used as the tokens of a command, and optionally
- * pointers to the string arrays that will store each lines of the call standard
- * output and standard error.
- *
- * argv - NULL-terminated string array containing the tokens of the command
- *        line to spawn
- * output_ptr - a pointer to the string array where to store spawned command
- *              standard output
- *              set to NULL to ignore the command standard output
- * error_ptr - a pointer to the string array where to store spawned command
- *             standard error
- *             set to NULL to ignore the command standard error
- *
- * Returns:
- * - TRUE if the command has been successfully spawned and exited normally
- * - FALSE otherwise
- */
 gboolean
-call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr)
+call_external(gchar** argv, gchar** std_out, gchar** std_err)
 {
-    gchar* stdout_str = NULL;
-    gchar** stdout_str_ptr = &stdout_str;
-    gchar* stderr_str = NULL;
-    gchar** stderr_str_ptr = &stderr_str;
     GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
-    gint status;
-    GError* error = NULL;
-    gchar* cmd = NULL;
-
-    cmd = g_strjoinv(" ", argv);
-    log_debug("Calling external: %s", cmd);
-
-    if (!output_ptr) {
-        stdout_str_ptr = NULL;
+    if (std_out == NULL)
         flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
-    }
-
-    if (!error_ptr) {
-        stderr_str_ptr = NULL;
+    if (std_err == NULL)
         flags |= G_SPAWN_STDERR_TO_DEV_NULL;
-    }
 
-    if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, stdout_str_ptr, stderr_str_ptr, &status, &error)) {
-        log_error("Spawning '%s' failed: %s.", cmd, error->message);
-        g_error_free(error);
-        error = NULL;
-        return FALSE;
-    }
-
-    if (!g_spawn_check_exit_status(status, &error)) {
-        log_error("Calling '%s' failed: %s.", cmd, error->message);
-        g_error_free(error);
-        error = NULL;
+    gint exit_status;
+    gboolean spawn_result;
+    GError* spawn_error;
+    spawn_result = g_spawn_sync(NULL, // Inherit the parent PWD.
+                                argv,
+                                NULL, // Inherit the parent environment.
+                                flags,
+                                NULL, NULL, // No func. before exec() in child.
+                                std_out, std_err,
+                                &exit_status, &spawn_error);
+
+    if (!spawn_result
+        || !g_spawn_check_exit_status(exit_status, &spawn_error)) {
+        gchar* cmd = g_strjoinv(" ", argv);
+        log_error("Spawning '%s' failed with '%s'.", cmd, spawn_error->message);
         g_free(cmd);
-        cmd = NULL;
-        g_free(stdout_str);
-        stdout_str = NULL;
-        stdout_str_ptr = NULL;
-        if (stderr_str && strlen(stderr_str)) {
-            log_error("Called command returned the following on stderr: %s.", stderr_str);
-        }
-        g_free(stderr_str);
-        stderr_str = NULL;
-        stderr_str_ptr = NULL;
-        return FALSE;
+        g_error_free(spawn_error);
     }
 
-    g_free(cmd);
-    cmd = NULL;
-
-    if (output_ptr) {
-        *output_ptr = g_strsplit(stdout_str, "\n", 0);
-        g_free(stdout_str);
-        stdout_str = NULL;
-        stdout_str_ptr = NULL;
-    }
-
-    if (error_ptr) {
-        *error_ptr = g_strsplit(stderr_str, "\n", 0);
-        g_free(stderr_str);
-        stderr_str = NULL;
-        stderr_str_ptr = NULL;
-    }
-
-    return TRUE;
+    return spawn_result;
 }
 
 gchar**
diff --git a/src/common.h b/src/common.h
index 44a61a79..bd33bf90 100644
--- a/src/common.h
+++ b/src/common.h
@@ -104,10 +104,10 @@ void get_file_paths_recursive(const char* directory, GSList** contents);
 
 char* get_random_string(int length);
 
-gboolean call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr);
+gboolean call_external(gchar** argv, gchar** std_out, gchar** std_err);
 gchar** format_call_external_argv(const char* template, const char* url, const char* filename);
 
 gchar* unique_filename_from_url(const char* url, const char* path);
-gchar* get_expanded_path(const char *path);
+gchar* get_expanded_path(const char* path);
 
 #endif
diff --git a/src/config/account.c b/src/config/account.c
index c0f508b4..627c4a1c 100644
--- a/src/config/account.c
+++ b/src/config/account.c
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
 
 #include <glib.h>
 
@@ -200,27 +201,49 @@ account_eval_password(ProfAccount* account)
     assert(account != NULL);
     assert(account->eval_password != NULL);
 
-    gchar** output = NULL;
-    gchar** error = NULL;
+    errno = 0;
+
+    FILE* stream = popen(account->eval_password, "r");
+    if (stream == NULL) {
+        const char* errmsg = strerror(errno);
+        if (errmsg) {
+            log_error("Could not execute `eval_password` command (%s).",
+                      errmsg);
+        } else {
+            log_error("Failed to allocate memory for `eval_password` command.");
+        }
+        return FALSE;
+    }
 
-    gchar* argv[] = { "sh", "-c", account->eval_password, NULL };
-    if (!call_external(argv, &output, &error)) {
+    account->password = g_malloc(READ_BUF_SIZE);
+    if (!account->password) {
+        log_error("Failed to allocate enough memory to read `eval_password` "
+                  "output.");
         return FALSE;
     }
 
-    if (!output || !output[0]) {
-        log_error("Failed to read eval_password output");
-        g_strfreev(output);
-        output = NULL;
+    account->password = fgets(account->password, READ_BUF_SIZE, stream);
+    if (!account->password) {
+        log_error("Failed to read password from stream.");
         return FALSE;
     }
 
-    account->password = strdup(output[0]);
-    g_strfreev(output);
-    output = NULL;
+    int exit_status = pclose(stream);
+    if (exit_status > 0) {
+        log_error("Command for `eval_password` returned error status (%s).",
+                  exit_status);
+        return FALSE;
+    } else if (exit_status < 0) {
+        log_error("Failed to close stream for `eval_password` command output "
+                  "(%s).",
+                  strerror(errno));
+        return FALSE;
+    };
 
+    // Remove leading and trailing whitespace from output.
+    g_strstrip(account->password);
     if (!account->password) {
-        log_error("Failed to allocate enough memory to read eval_password output");
+        log_error("Empty password returned by `eval_password` command.");
         return FALSE;
     }