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:
parent
58183b99ff
commit
0adb8b09ca
@ -99,20 +99,170 @@ reply_to_external_command(int result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#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 *
|
||||
get_external_command(const char *prompt, char *input, int len)
|
||||
{
|
||||
// TODO: Implement!
|
||||
return 0;
|
||||
do {
|
||||
// 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
|
||||
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__
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
||||
* 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 "fs_shell_command.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
|
||||
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;
|
||||
prepare_command_string(argv + 1, argc - 1, message.command,
|
||||
sizeof(message.command));
|
||||
strncpy(message.command, command, sizeof(message.command));
|
||||
|
||||
// find the command port
|
||||
port_id commandPort = find_port(kFSShellCommandPort);
|
||||
if (commandPort < 0) {
|
||||
fprintf(stderr, "Couldn't find fs_shell command port.\n");
|
||||
exit(1);
|
||||
return commandPort;
|
||||
}
|
||||
|
||||
// create a reply port
|
||||
@ -71,7 +29,7 @@ main(int argc, const char *const *argv)
|
||||
if (replyPort < 0) {
|
||||
fprintf(stderr, "Failed to create a reply port: %s\n",
|
||||
strerror(replyPort));
|
||||
exit(1);
|
||||
return replyPort;
|
||||
}
|
||||
message.reply_port = replyPort;
|
||||
|
||||
@ -83,7 +41,7 @@ main(int argc, const char *const *argv)
|
||||
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to send command: %s\n", strerror(error));
|
||||
exit(1);
|
||||
return error;
|
||||
}
|
||||
|
||||
// wait for the reply
|
||||
@ -97,16 +55,10 @@ main(int argc, const char *const *argv)
|
||||
if (bytesRead < 0) {
|
||||
fprintf(stderr, "Failed to read reply from fs_shell: %s\n",
|
||||
strerror(bytesRead));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 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);
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
*result = reply.error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
||||
* 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
|
Loading…
Reference in New Issue
Block a user