]> code.delx.au - pulseaudio/blobdiff - src/utils/pacmd.c
use cloexec wrappers wherever applicable
[pulseaudio] / src / utils / pacmd.c
index 2c89c8d95581a031dff95067a21d451040fe1e76..ef58e9ce317858b6cca912e19bf17f87bf880e25 100644 (file)
@@ -5,7 +5,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
@@ -25,7 +25,7 @@
 
 #include <assert.h>
 #include <signal.h>
-#include <sys/select.h>
+#include <sys/poll.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include <errno.h>
 #include <pulse/xmalloc.h>
 #include <pulse/i18n.h>
 
+#include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/pid.h>
 
 int main(int argc, char*argv[]) {
+
+    enum {
+        WATCH_STDIN,
+        WATCH_STDOUT,
+        WATCH_SOCKET,
+        N_WATCH
+    };
+
     pid_t pid ;
     int fd = -1;
     int ret = 1, i;
     struct sockaddr_un sa;
-    char ibuf[256], obuf[256];
+    char ibuf[PIPE_BUF], obuf[PIPE_BUF];
     size_t ibuf_index, ibuf_length, obuf_index, obuf_length;
-    fd_set ifds, ofds;
     char *cli;
+    pa_bool_t ibuf_eof, obuf_eof, ibuf_closed, obuf_closed;
+    struct pollfd pollfd[N_WATCH];
 
     setlocale(LC_ALL, "");
     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
 
     if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) {
-        pa_log("No PulseAudio daemon running");
+        pa_log(_("No PulseAudio daemon running, or not running as session daemon."));
         goto fail;
     }
 
-    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+    if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log(_("socket(PF_UNIX, SOCK_STREAM, 0): %s"), strerror(errno));
         goto fail;
     }
 
-    memset(&sa, 0, sizeof(sa));
+    pa_zero(sa);
     sa.sun_family = AF_UNIX;
 
     if (!(cli = pa_runtime_path("cli")))
@@ -99,99 +109,143 @@ int main(int argc, char*argv[]) {
     }
 
     ibuf_index = ibuf_length = obuf_index = obuf_length = 0;
+    ibuf_eof = obuf_eof = ibuf_closed = obuf_closed = FALSE;
+
+    if (argc > 1) {
+        for (i = 1; i < argc; i++) {
+            size_t k;
+
+            k = PA_MIN(sizeof(ibuf) - ibuf_length, strlen(argv[i]));
+            memcpy(ibuf + ibuf_length, argv[i], k);
+            ibuf_length += k;
+
+            if (ibuf_length < sizeof(ibuf)) {
+                ibuf[ibuf_length] = i < argc-1 ? ' ' : '\n';
+                ibuf_length++;
+            }
+        }
 
+        ibuf_eof = TRUE;
+    }
 
-    FD_ZERO(&ifds);
-    FD_SET(0, &ifds);
-    FD_SET(fd, &ifds);
+    pa_zero(pollfd);
 
-    FD_ZERO(&ofds);
+    pollfd[WATCH_STDIN].fd = STDIN_FILENO;
+    pollfd[WATCH_STDOUT].fd = STDOUT_FILENO;
+    pollfd[WATCH_SOCKET].fd = fd;
 
     for (;;) {
-        if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) {
-            pa_log(_("select(): %s"), strerror(errno));
-            goto fail;
-        }
+        if (ibuf_eof &&
+            obuf_eof &&
+            ibuf_length <= 0 &&
+            obuf_length <= 0)
+            break;
 
-        if (FD_ISSET(0, &ifds)) {
-            ssize_t r;
-            assert(!ibuf_length);
+        pollfd[WATCH_STDIN].events = pollfd[WATCH_STDOUT].events = pollfd[WATCH_SOCKET].events = 0;
 
-            if ((r = read(0, ibuf, sizeof(ibuf))) <= 0) {
-                if (r == 0)
-                    break;
+        if (obuf_length > 0)
+            pollfd[WATCH_STDOUT].events |= POLLOUT;
+        else if (!obuf_eof)
+            pollfd[WATCH_SOCKET].events |= POLLIN;
 
-                pa_log(_("read(): %s"), strerror(errno));
-                goto fail;
-            }
+        if (ibuf_length > 0)
+            pollfd[WATCH_SOCKET].events |= POLLOUT;
+        else if (!ibuf_eof)
+            pollfd[WATCH_STDIN].events |= POLLIN;
 
-            ibuf_length = (size_t) r;
-            ibuf_index = 0;
-        }
+        if (poll(pollfd, N_WATCH, -1) < 0) {
 
-        if (FD_ISSET(fd, &ifds)) {
-            ssize_t r;
-            assert(!obuf_length);
+            if (errno == EINTR)
+                continue;
 
-            if ((r = read(fd, obuf, sizeof(obuf))) <= 0) {
-                if (r == 0)
-                    break;
+            pa_log(_("poll(): %s"), strerror(errno));
+            goto fail;
+        }
 
-                pa_log(_("read(): %s"), strerror(errno));
-                goto fail;
+        if (pollfd[WATCH_STDIN].revents & POLLIN) {
+            ssize_t r;
+            pa_assert(!ibuf_length);
+
+            if ((r = pa_read(STDIN_FILENO, ibuf, sizeof(ibuf), NULL)) <= 0) {
+                if (r < 0) {
+                    pa_log(_("read(): %s"), strerror(errno));
+                    goto fail;
+                }
+
+                ibuf_eof = TRUE;
+            } else {
+                ibuf_length = (size_t) r;
+                ibuf_index = 0;
             }
+        }
 
-            obuf_length = (size_t) r;
-            obuf_index = 0;
+        if (pollfd[WATCH_SOCKET].revents & POLLIN) {
+            ssize_t r;
+            pa_assert(!obuf_length);
+
+            if ((r = pa_read(fd, obuf, sizeof(obuf), NULL)) <= 0) {
+                if (r < 0) {
+                    pa_log(_("read(): %s"), strerror(errno));
+                    goto fail;
+                }
+
+                obuf_eof = TRUE;
+            } else {
+                obuf_length = (size_t) r;
+                obuf_index = 0;
+            }
         }
 
-        if (FD_ISSET(1, &ofds)) {
+        if (pollfd[WATCH_STDOUT].revents & POLLHUP) {
+            obuf_eof = TRUE;
+            obuf_length = 0;
+        } else if (pollfd[WATCH_STDOUT].revents & POLLOUT) {
             ssize_t r;
-            assert(obuf_length);
+            pa_assert(obuf_length);
 
-            if ((r = write(1, obuf + obuf_index, obuf_length)) < 0) {
+            if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, NULL)) < 0) {
                 pa_log(_("write(): %s"), strerror(errno));
                 goto fail;
             }
 
             obuf_length -= (size_t) r;
             obuf_index += obuf_index;
-
         }
 
-        if (FD_ISSET(fd, &ofds)) {
+        if (pollfd[WATCH_SOCKET].revents & POLLHUP) {
+            ibuf_eof = TRUE;
+            ibuf_length = 0;
+        } if (pollfd[WATCH_SOCKET].revents & POLLOUT) {
             ssize_t r;
-            assert(ibuf_length);
+            pa_assert(ibuf_length);
 
-            if ((r = write(fd, ibuf + ibuf_index, ibuf_length)) < 0) {
+            if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, NULL)) < 0) {
                 pa_log(_("write(): %s"), strerror(errno));
                 goto fail;
             }
 
             ibuf_length -= (size_t) r;
             ibuf_index += obuf_index;
-
         }
 
-        FD_ZERO(&ifds);
-        FD_ZERO(&ofds);
-
-        if (obuf_length <= 0)
-            FD_SET(fd, &ifds);
-        else
-            FD_SET(1, &ofds);
+        if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) {
+            pa_close(STDIN_FILENO);
+            shutdown(fd, SHUT_WR);
+            ibuf_closed = TRUE;
+        }
 
-        if (ibuf_length <= 0)
-            FD_SET(0, &ifds);
-        else
-            FD_SET(fd, &ofds);
+        if (obuf_length <= 0 && obuf_eof && !obuf_closed) {
+            shutdown(fd, SHUT_RD);
+            pa_close(STDOUT_FILENO);
+            obuf_closed = TRUE;
+        }
     }
 
     ret = 0;
 
 fail:
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
 
     return ret;
 }