1/*
2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <string.h>
9#include <unistd.h>
10#include <sys/socket.h>
11#include <sys/un.h>
12
13#include "fs_shell_command.h"
14#include "fs_shell_command_unix.h"
15
16int
17send_external_command(const char *command, int *result)
18{
19	external_command_message message;
20	strncpy(message.command, command, sizeof(message.command));
21
22	// create a socket
23	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
24	if (fd < 0)
25		return errno;
26
27	// connect to the fs_shell
28	sockaddr_un addr;
29	addr.sun_family = AF_UNIX;
30	strcpy(addr.sun_path, kFSShellCommandSocketAddress);
31	int addrLen = addr.sun_path + strlen(addr.sun_path) + 1 - (char*)&addr;
32	if (connect(fd, (sockaddr*)&addr, addrLen) < 0) {
33		close(fd);
34		return errno;
35	}
36
37	// send the command message
38	int toWrite = sizeof(message);
39	const char *messageBuffer = (char*)&message;
40	ssize_t bytesWritten;
41	do {
42		bytesWritten = write(fd, messageBuffer, toWrite);
43		if (bytesWritten > 0) {
44			messageBuffer += bytesWritten;
45			toWrite -= bytesWritten;
46		}
47	} while (toWrite > 0 && !(bytesWritten < 0 && errno != EINTR));
48
49	// close connection on error
50	if (bytesWritten < 0) {
51		fprintf(stderr, "Writing to fs_shell failed: %s\n", strerror(errno));
52		close(fd);
53		return errno;
54	}
55
56	// read the reply
57	external_command_reply reply;
58	int toRead = sizeof(reply);
59	char *replyBuffer = (char*)&reply;
60	while (toRead > 0) {
61		int bytesRead = read(fd, replyBuffer, toRead);
62		if (bytesRead < 0) {
63			if (errno == EINTR) {
64				continue;
65			} else {
66				fprintf(stderr, "Failed to read reply from fs_shell: %s\n",
67					strerror(errno));
68				close(fd);
69				return errno;
70			}
71		}
72
73		if (bytesRead == 0) {
74			fprintf(stderr, "Unexpected end of fs_shell reply. Was still "
75				"expecting %d bytes\n", toRead);
76			return EPIPE;
77		}
78
79		replyBuffer += bytesRead;
80		toRead -= bytesRead;
81	}
82
83	*result = reply.error;
84	return 0;
85}
86
87