Code

plugin: fix crash
[ncmpc.git] / src / plugin.c
index fcfaea9752e124bb48008daf70d2ee57a2d50504..f9049ecfa77458285c07da66f4946f542a1b4959 100644 (file)
@@ -1,5 +1,5 @@
 /* ncmpc (Ncurses MPD Client)
- * (c) 2004-2010 The Music Player Daemon Project
+ * (c) 2004-2017 The Music Player Daemon Project
  * Project homepage: http://musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
  */
 
 #include "plugin.h"
+#include "Compiler.h"
 
 #include <assert.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 
 struct plugin_pipe {
+       struct plugin_cycle *cycle;
+
        /** the pipe to the plugin process, or -1 if none is currently
            open */
        int fd;
-       /** the GLib channel of #fd */
-       GIOChannel *channel;
-       /** the GLib IO watch of #channel */
+       /** the GLib IO watch of #fd */
        guint event_id;
        /** the output of the current plugin */
        GString *data;
@@ -71,18 +72,15 @@ struct plugin_cycle {
 static bool
 register_plugin(struct plugin_list *list, char *path)
 {
-       int ret;
        struct stat st;
-
-       ret = stat(path, &st);
-       if (ret < 0)
+       if (stat(path, &st) < 0)
                return false;
 
        g_ptr_array_add(list->plugins, path);
        return true;
 }
 
-static gint 
+static gint
 plugin_compare_func_alpha(gconstpointer plugin1, gconstpointer plugin2)
 {
        return strcmp(* (char * const *) plugin1, * (char * const *) plugin2);
@@ -98,19 +96,14 @@ plugin_list_sort(struct plugin_list *list, GCompareFunc compare_func)
 bool
 plugin_list_load_directory(struct plugin_list *list, const char *path)
 {
-       GDir *dir;
-       const char *name;
-       char *plugin;
-       bool ret;
-
-       dir = g_dir_open(path, 0, NULL);
+       GDir *dir = g_dir_open(path, 0, NULL);
        if (dir == NULL)
                return false;
 
+       const char *name;
        while ((name = g_dir_read_name(dir)) != NULL) {
-               plugin = g_build_filename(path, name, NULL);
-               ret = register_plugin(list, plugin);
-               if (!ret)
+               char *plugin = g_build_filename(path, name, NULL);
+               if (!register_plugin(list, plugin))
                        g_free(plugin);
        }
 
@@ -134,9 +127,6 @@ next_plugin(struct plugin_cycle *cycle);
 static void
 plugin_eof(struct plugin_cycle *cycle, struct plugin_pipe *p)
 {
-       int ret, status;
-
-       g_io_channel_unref(p->channel);
        close(p->fd);
        p->fd = -1;
 
@@ -144,7 +134,7 @@ plugin_eof(struct plugin_cycle *cycle, struct plugin_pipe *p)
        if (cycle->pipe_stdout.fd != -1 || cycle->pipe_stderr.fd != -1)
                return;
 
-       ret = waitpid(cycle->pid, &status, 0);
+       int status, ret = waitpid(cycle->pid, &status, 0);
        cycle->pid = -1;
 
        if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
@@ -173,24 +163,20 @@ plugin_eof(struct plugin_cycle *cycle, struct plugin_pipe *p)
 }
 
 static gboolean
-plugin_data(G_GNUC_UNUSED GIOChannel *source,
-           G_GNUC_UNUSED GIOCondition condition, gpointer data)
+plugin_data(gcc_unused GIOChannel *source,
+           gcc_unused GIOCondition condition, gpointer data)
 {
-       struct plugin_cycle *cycle = data;
-       struct plugin_pipe *p = NULL;
-       char buffer[256];
-       ssize_t nbytes;
+       struct plugin_pipe *p = data;
+       assert(p->fd >= 0);
 
+       struct plugin_cycle *cycle = p->cycle;
        assert(cycle != NULL);
        assert(cycle->pid > 0);
-       if (source == cycle->pipe_stdout.channel)
-               p = &cycle->pipe_stdout;
-       else if (source == cycle->pipe_stderr.channel)
-               p = &cycle->pipe_stderr;
-       assert(p != NULL);
-       assert(p->fd >= 0);
 
-       nbytes = condition & G_IO_IN ? read(p->fd, buffer, sizeof(buffer)) : 0;
+       char buffer[256];
+       ssize_t nbytes = condition & G_IO_IN
+               ? read(p->fd, buffer, sizeof(buffer))
+               : 0;
        if (nbytes <= 0) {
                plugin_eof(cycle, p);
                return FALSE;
@@ -225,19 +211,18 @@ plugin_delayed_fail(gpointer data)
 static void
 plugin_fd_add(struct plugin_cycle *cycle, struct plugin_pipe *p, int fd)
 {
+       p->cycle = cycle;
        p->fd = fd;
        p->data = g_string_new(NULL);
-       p->channel = g_io_channel_unix_new(fd);
-       p->event_id = g_io_add_watch(p->channel, G_IO_IN|G_IO_HUP,
-                                    plugin_data, cycle);
+       GIOChannel *channel = g_io_channel_unix_new(fd);
+       p->event_id = g_io_add_watch(channel, G_IO_IN|G_IO_HUP,
+                                    plugin_data, p);
+       g_io_channel_unref(channel);
 }
 
 static int
 start_plugin(struct plugin_cycle *cycle, const char *plugin_path)
 {
-       int ret, fds_stdout[2], fds_stderr[2];
-       pid_t pid;
-
        assert(cycle != NULL);
        assert(cycle->pid < 0);
        assert(cycle->pipe_stdout.fd < 0);
@@ -250,17 +235,18 @@ start_plugin(struct plugin_cycle *cycle, const char *plugin_path)
        g_free(cycle->argv[0]);
        cycle->argv[0] = g_path_get_basename(plugin_path);
 
-       ret = pipe(fds_stdout);
-       if (ret < 0)
+       int fds_stdout[2];
+       if (pipe(fds_stdout) < 0)
                return -1;
-       ret = pipe(fds_stderr);
-       if (ret < 0) {
+
+       int fds_stderr[2];
+       if (pipe(fds_stderr) < 0) {
                close(fds_stdout[0]);
                close(fds_stdout[1]);
                return -1;
        }
 
-       pid = fork();
+       pid_t pid = fork();
 
        if (pid < 0) {
                close(fds_stdout[0]);
@@ -300,9 +286,6 @@ start_plugin(struct plugin_cycle *cycle, const char *plugin_path)
 static void
 next_plugin(struct plugin_cycle *cycle)
 {
-       const char *plugin_path;
-       int ret = -1;
-
        assert(cycle->pid < 0);
        assert(cycle->pipe_stdout.fd < 0);
        assert(cycle->pipe_stderr.fd < 0);
@@ -311,16 +294,15 @@ next_plugin(struct plugin_cycle *cycle)
 
        if (cycle->next_plugin >= cycle->list->plugins->len) {
                /* no plugins left */
-               g_timeout_add(0, plugin_delayed_fail, cycle);
+               g_idle_add(plugin_delayed_fail, cycle);
                return;
        }
 
-       plugin_path = g_ptr_array_index(cycle->list->plugins,
-                                       cycle->next_plugin++);
-       ret = start_plugin(cycle, plugin_path);
-       if (ret < 0) {
+       const char *plugin_path = g_ptr_array_index(cycle->list->plugins,
+                                                   cycle->next_plugin++);
+       if (start_plugin(cycle, plugin_path) < 0) {
                /* system error */
-               g_timeout_add(0, plugin_delayed_fail, cycle);
+               g_idle_add(plugin_delayed_fail, cycle);
                return;
        }
 }
@@ -329,13 +311,11 @@ static char **
 make_argv(const char*const* args)
 {
        unsigned num = 0;
-       char **ret;
-
        while (args[num] != NULL)
                ++num;
        num += 2;
 
-       ret = g_new(char*, num);
+       char **ret = g_new(char *, num);
 
        /* reserve space for the program name */
        *ret++ = NULL;
@@ -379,7 +359,6 @@ plugin_fd_remove(struct plugin_pipe *p)
 {
        if (p->fd >= 0) {
                g_source_remove(p->event_id);
-               g_io_channel_unref(p->channel);
                close(p->fd);
        }
 }