Implemented fs_shell scripting under UNIX using UNIX sockets. Refactored
the platform independent code out of fs_shell_command_beos.cpp. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11600 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -99,20 +99,170 @@ reply_to_external_command(int result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else // ! __BEOS__
|
#else // ! __BEOS__
|
||||||
|
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include "fs_shell_command_unix.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int sClientConnection = -1;
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_command_socket()
|
||||||
|
{
|
||||||
|
static int fd = -1;
|
||||||
|
static bool initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
// get the listener socket
|
||||||
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// bind it to the port
|
||||||
|
sockaddr_un addr;
|
||||||
|
unlink(kFSShellCommandSocketAddress);
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(addr.sun_path, kFSShellCommandSocketAddress);
|
||||||
|
int addrLen = addr.sun_path + strlen(addr.sun_path) + 1 - (char*)&addr;
|
||||||
|
if (bind(fd, (sockaddr*)&addr, addrLen) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start listening
|
||||||
|
if (listen(fd, 1) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_client_connection()
|
||||||
|
{
|
||||||
|
if (sClientConnection >= 0)
|
||||||
|
return sClientConnection;
|
||||||
|
|
||||||
|
// get the listener socket
|
||||||
|
int commandFD = get_command_socket();
|
||||||
|
if (commandFD < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// accept a connection
|
||||||
|
do {
|
||||||
|
sockaddr_un addr;
|
||||||
|
socklen_t addrLen = sizeof(addr);
|
||||||
|
sClientConnection = accept(commandFD, (sockaddr*)&addr, &addrLen);
|
||||||
|
} while (sClientConnection < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
return sClientConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
close_client_connection()
|
||||||
|
{
|
||||||
|
if (sClientConnection >= 0) {
|
||||||
|
close(sClientConnection);
|
||||||
|
sClientConnection = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
get_external_command(const char *prompt, char *input, int len)
|
get_external_command(const char *prompt, char *input, int len)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
do {
|
||||||
return 0;
|
// get a connection
|
||||||
|
int connection = get_client_connection();
|
||||||
|
if (connection < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// read until we have a full command
|
||||||
|
external_command_message message;
|
||||||
|
int toRead = sizeof(message);
|
||||||
|
char *buffer = (char*)&message;
|
||||||
|
while (toRead > 0) {
|
||||||
|
int bytesRead = read(connection, buffer, toRead);
|
||||||
|
if (bytesRead < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Reading from connection failed: %s\n", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection closed?
|
||||||
|
if (bytesRead == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer += bytesRead;
|
||||||
|
toRead -= bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection may be broken: discard it
|
||||||
|
if (toRead > 0) {
|
||||||
|
close_client_connection();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the len of the command
|
||||||
|
int commandLen = strnlen(message.command, sizeof(message.command)) + 1;
|
||||||
|
if (commandLen <= 1) {
|
||||||
|
fprintf(stderr, "No command given.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (commandLen > len) {
|
||||||
|
fprintf(stderr, "Command too long. Ignored.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the command
|
||||||
|
memcpy(input, message.command, commandLen);
|
||||||
|
input[len - 1] = '\0'; // always NULL-terminate
|
||||||
|
return input;
|
||||||
|
|
||||||
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
reply_to_external_command(int result)
|
reply_to_external_command(int result)
|
||||||
{
|
{
|
||||||
// TODO: Implement!
|
if (sClientConnection < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// prepare the reply
|
||||||
|
external_command_reply reply;
|
||||||
|
reply.error = result;
|
||||||
|
|
||||||
|
// send the reply
|
||||||
|
int toWrite = sizeof(reply);
|
||||||
|
char *replyBuffer = (char*)&reply;
|
||||||
|
ssize_t bytesWritten;
|
||||||
|
do {
|
||||||
|
bytesWritten = write(sClientConnection, replyBuffer, toWrite);
|
||||||
|
if (bytesWritten > 0) {
|
||||||
|
replyBuffer += bytesWritten;
|
||||||
|
toWrite -= bytesWritten;
|
||||||
|
}
|
||||||
|
} while (toWrite > 0 && !(bytesWritten < 0 && errno != EINTR));
|
||||||
|
|
||||||
|
// connection may be broken: discard it
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
close_client_connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ! __BEOS__
|
#endif // ! __BEOS__
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fs_shell_command.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_char(char *&buffer, int &bufferSize, char c)
|
||||||
|
{
|
||||||
|
if (bufferSize <= 0) {
|
||||||
|
fprintf(stderr, "Command line too long\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*buffer = c;
|
||||||
|
buffer++;
|
||||||
|
bufferSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepare_command_string(const char *const *argv, int argc, char *buffer,
|
||||||
|
int bufferSize)
|
||||||
|
{
|
||||||
|
for (int argi = 0; argi < argc; argi++) {
|
||||||
|
const char *arg = argv[argi];
|
||||||
|
|
||||||
|
if (argi > 0)
|
||||||
|
add_char(buffer, bufferSize, ' ');
|
||||||
|
|
||||||
|
while (*arg) {
|
||||||
|
if (strchr("", *arg))
|
||||||
|
add_char(buffer, bufferSize, '\\');
|
||||||
|
add_char(buffer, bufferSize, *arg);
|
||||||
|
arg++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_char(buffer, bufferSize, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char *const *argv)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "No command given.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare the command string
|
||||||
|
char command[1024];
|
||||||
|
prepare_command_string(argv + 1, argc - 1, command, sizeof(command));
|
||||||
|
|
||||||
|
// send the command
|
||||||
|
int result;
|
||||||
|
int error = send_external_command(command, &result);
|
||||||
|
if (error != 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
// evaluate result
|
||||||
|
if (result != 0) {
|
||||||
|
fprintf(stderr, "Command failed: %s\n", strerror(result));
|
||||||
|
fprintf(stderr, "Command was:\n %s\n", command);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef FS_SHELL_COMMAND_H
|
||||||
|
#define FS_SHELL_COMMAND_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int send_external_command(const char *command, int *result);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FS_SHELL_COMMAND_H
|
||||||
@@ -8,62 +8,20 @@
|
|||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include "fs_shell_command.h"
|
||||||
#include "fs_shell_command_beos.h"
|
#include "fs_shell_command_beos.h"
|
||||||
|
|
||||||
static void
|
|
||||||
add_char(char *&buffer, int &bufferSize, char c)
|
|
||||||
{
|
|
||||||
if (bufferSize <= 0) {
|
|
||||||
fprintf(stderr, "Command line too long\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
*buffer = c;
|
|
||||||
buffer++;
|
|
||||||
bufferSize--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
prepare_command_string(const char *const *argv, int argc, char *buffer,
|
|
||||||
int bufferSize)
|
|
||||||
{
|
|
||||||
for (int argi = 0; argi < argc; argi++) {
|
|
||||||
const char *arg = argv[argi];
|
|
||||||
|
|
||||||
if (argi > 0)
|
|
||||||
add_char(buffer, bufferSize, ' ');
|
|
||||||
|
|
||||||
while (*arg) {
|
|
||||||
if (strchr("", *arg))
|
|
||||||
add_char(buffer, bufferSize, '\\');
|
|
||||||
add_char(buffer, bufferSize, *arg);
|
|
||||||
arg++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_char(buffer, bufferSize, '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char *const *argv)
|
send_external_command(const char *command, int *result)
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "No command given.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare the command string
|
|
||||||
external_command_message message;
|
external_command_message message;
|
||||||
prepare_command_string(argv + 1, argc - 1, message.command,
|
strncpy(message.command, command, sizeof(message.command));
|
||||||
sizeof(message.command));
|
|
||||||
|
|
||||||
// find the command port
|
// find the command port
|
||||||
port_id commandPort = find_port(kFSShellCommandPort);
|
port_id commandPort = find_port(kFSShellCommandPort);
|
||||||
if (commandPort < 0) {
|
if (commandPort < 0) {
|
||||||
fprintf(stderr, "Couldn't find fs_shell command port.\n");
|
fprintf(stderr, "Couldn't find fs_shell command port.\n");
|
||||||
exit(1);
|
return commandPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a reply port
|
// create a reply port
|
||||||
@@ -71,7 +29,7 @@ main(int argc, const char *const *argv)
|
|||||||
if (replyPort < 0) {
|
if (replyPort < 0) {
|
||||||
fprintf(stderr, "Failed to create a reply port: %s\n",
|
fprintf(stderr, "Failed to create a reply port: %s\n",
|
||||||
strerror(replyPort));
|
strerror(replyPort));
|
||||||
exit(1);
|
return replyPort;
|
||||||
}
|
}
|
||||||
message.reply_port = replyPort;
|
message.reply_port = replyPort;
|
||||||
|
|
||||||
@@ -83,7 +41,7 @@ main(int argc, const char *const *argv)
|
|||||||
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "Failed to send command: %s\n", strerror(error));
|
fprintf(stderr, "Failed to send command: %s\n", strerror(error));
|
||||||
exit(1);
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the reply
|
// wait for the reply
|
||||||
@@ -97,16 +55,10 @@ main(int argc, const char *const *argv)
|
|||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
fprintf(stderr, "Failed to read reply from fs_shell: %s\n",
|
fprintf(stderr, "Failed to read reply from fs_shell: %s\n",
|
||||||
strerror(bytesRead));
|
strerror(bytesRead));
|
||||||
exit(1);
|
return bytesRead;
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate result
|
|
||||||
if (reply.error != B_OK) {
|
|
||||||
fprintf(stderr, "Command failed: %s\n", strerror(reply.error));
|
|
||||||
fprintf(stderr, "Command was:\n %s\n", message.command);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*result = reply.error;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include "fs_shell_command.h"
|
||||||
|
#include "fs_shell_command_unix.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
send_external_command(const char *command, int *result)
|
||||||
|
{
|
||||||
|
external_command_message message;
|
||||||
|
strncpy(message.command, command, sizeof(message.command));
|
||||||
|
|
||||||
|
// create a socket
|
||||||
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
// connect to the fs_shell
|
||||||
|
sockaddr_un addr;
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(addr.sun_path, kFSShellCommandSocketAddress);
|
||||||
|
int addrLen = addr.sun_path + strlen(addr.sun_path) + 1 - (char*)&addr;
|
||||||
|
if (connect(fd, (sockaddr*)&addr, addrLen) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the command message
|
||||||
|
int toWrite = sizeof(message);
|
||||||
|
const char *messageBuffer = (char*)&message;
|
||||||
|
ssize_t bytesWritten;
|
||||||
|
do {
|
||||||
|
bytesWritten = write(fd, messageBuffer, toWrite);
|
||||||
|
if (bytesWritten > 0) {
|
||||||
|
messageBuffer += bytesWritten;
|
||||||
|
toWrite -= bytesWritten;
|
||||||
|
}
|
||||||
|
} while (toWrite > 0 && !(bytesWritten < 0 && errno != EINTR));
|
||||||
|
|
||||||
|
// close connection on error
|
||||||
|
if (bytesWritten < 0) {
|
||||||
|
fprintf(stderr, "Writing to fs_shell failed: %s\n", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the reply
|
||||||
|
external_command_reply reply;
|
||||||
|
int toRead = sizeof(reply);
|
||||||
|
char *replyBuffer = (char*)&reply;
|
||||||
|
while (toRead > 0) {
|
||||||
|
int bytesRead = read(fd, replyBuffer, toRead);
|
||||||
|
if (bytesRead < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to read reply from fs_shell: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesRead == 0) {
|
||||||
|
fprintf(stderr, "Unexpected end of fs_shell reply. Was still "
|
||||||
|
"expecting %d bytes\n", toRead);
|
||||||
|
return EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
replyBuffer += bytesRead;
|
||||||
|
toRead -= bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = reply.error;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef FS_SHELL_COMMAND_UNIX_H
|
||||||
|
#define FS_SHELL_COMMAND_UNIX_H
|
||||||
|
|
||||||
|
static const char *kFSShellCommandSocketAddress = "/tmp/fs_shell_commands";
|
||||||
|
|
||||||
|
struct external_command_message {
|
||||||
|
char command[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct external_command_reply {
|
||||||
|
int error;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FS_SHELL_COMMAND_UNIX_H
|
||||||
Reference in New Issue
Block a user