From 0adb8b09caf730a378d4f95516237321fb81993d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 6 Mar 2005 13:39:17 +0000 Subject: [PATCH] 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 --- .../fs_shell/external_commands.cpp | 156 +++++++++++++++++- .../fs_shell/fs_shell_command.cpp | 75 +++++++++ .../file_systems/fs_shell/fs_shell_command.h | 18 ++ .../fs_shell/fs_shell_command_beos.cpp | 64 +------ .../fs_shell/fs_shell_command_unix.cpp | 86 ++++++++++ .../fs_shell/fs_shell_command_unix.h | 18 ++ 6 files changed, 358 insertions(+), 59 deletions(-) create mode 100644 src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.cpp create mode 100644 src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.h create mode 100644 src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.cpp create mode 100644 src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.h diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/external_commands.cpp b/src/tests/add-ons/kernel/file_systems/fs_shell/external_commands.cpp index 4781fb9ba9..db72db400d 100644 --- a/src/tests/add-ons/kernel/file_systems/fs_shell/external_commands.cpp +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/external_commands.cpp @@ -99,20 +99,170 @@ reply_to_external_command(int result) } } + #else // ! __BEOS__ + +#include +#include +#include +#include +#include +#include + +#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__ diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.cpp b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.cpp new file mode 100644 index 0000000000..e75922ab37 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include + +#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; +} + diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.h b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.h new file mode 100644 index 0000000000..368297d67b --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command.h @@ -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 diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_beos.cpp b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_beos.cpp index c097fe920c..8ed39c1fe1 100644 --- a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_beos.cpp +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_beos.cpp @@ -8,62 +8,20 @@ #include +#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; } diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.cpp b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.cpp new file mode 100644 index 0000000000..ae0412e093 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.h b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.h new file mode 100644 index 0000000000..1851f68249 --- /dev/null +++ b/src/tests/add-ons/kernel/file_systems/fs_shell/fs_shell_command_unix.h @@ -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