aboutsummaryrefslogtreecommitdiffstats
path: root/src/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client.c')
-rw-r--r--src/client.c85
1 files changed, 80 insertions, 5 deletions
diff --git a/src/client.c b/src/client.c
index 739509a..fb569fd 100644
--- a/src/client.c
+++ b/src/client.c
@@ -20,7 +20,13 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "client.h"
+#include "common.h"
#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/wait.h>
@@ -35,18 +41,87 @@ extern char *argv0;
* Send a command to satd. Start satd if it is not running.
*
* @param cmd Command type.
- * @param n The length of the message, 0 if `msg` is
- * `NULL` or NUL-terminated.
+ * @param n The length of the message, 0 if
+ * `msg` is `NULL` or NUL-terminated.
* @param msg The message to send.
- * @return Zero on success.
+ * @return 0 on success, -1 on error.
*
* @throws 0 Error at the daemon-side.
*/
int
send_command(enum command cmd, size_t n, const char *restrict msg)
{
- return 0; /* TODO send_command */
- (void) cmd, (void) n, (void) msg;
+ struct sockaddr_un address;
+ int fd = -1, start = 1, status, goterr = 0;
+ char *dir;
+ pid_t pid;
+ int saved_errno;
+ ssize_t r;
+ char cmd_ = (char)cmd;
+
+ /* Get socket address. */
+ dir = getenv("XDG_RUNTIME_DIR"), dir = (dir ? dir : "/run");
+ if (strlen(dir) + sizeof("/satd.socket") > sizeof(address.sun_path))
+ t ((errno = ENAMETOOLONG));
+ stpcpy(stpcpy(address.sun_path, dir), "/satd.socket");
+ address.sun_family = AF_UNIX;
+
+ /* Any daemon listening? */
+ fd = open(address.sun_path, O_RDONLY);
+ if (fd == -1) {
+ t (errno != ENOENT);
+ } else {
+ if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
+ t (errno != EWOULDBLOCK);
+ start = 0;
+ }
+ flock(fd, LOCK_UN);
+ close(fd), fd = -1;
+ }
+
+ /* Start daemon if not running. */
+ if (start) {
+ switch ((pid = fork())) {
+ case -1:
+ goto fail;
+ case 0:
+ execl(BINDIR "/satd", BINDIR "/satd", NULL);
+ perror(argv0);
+ exit(1);
+ default:
+ t (waitpid(pid, &status, 0) != pid);
+ t (errno = 0, status);
+ break;
+ }
+ }
+
+ /* Create socket. */
+ t ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1);
+ t (connect(fd, (struct sockaddr *)&address, sizeof(address)) == -1);
+
+ /* Send message. */
+ t (write(fd, &cmd_, sizeof(cmd_)) < (ssize_t)sizeof(cmd_));
+ while (n) {
+ r = write(fd, msg, n);
+ t (r <= 0);
+ msg += (size_t)r;
+ n -= (size_t)r;
+ }
+ t (shutdown(fd, SHUT_WR)); /* Very important. */
+
+ /* TODO Receive. */
+
+ shutdown(fd, SHUT_RD);
+ close(fd);
+ errno = 0;
+ return -goterr;
+
+fail:
+ saved_errno = (goterr ? 0 : errno);
+ if (fd >= 0)
+ close(fd);
+ errno = saved_errno;
+ return -1;
}