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:
Ingo Weinhold 2005-03-06 13:39:17 +00:00
parent 58183b99ff
commit 0adb8b09ca
6 changed files with 358 additions and 59 deletions

View File

@ -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__

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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