diff --git a/build/scripts/build_haiku_image b/build/scripts/build_haiku_image index 709ea13def..0b341d6421 100755 --- a/build/scripts/build_haiku_image +++ b/build/scripts/build_haiku_image @@ -72,6 +72,48 @@ if [ $isCD ]; then mkdir=mkdir rm=rm elif [ $isImage ]; then + # If FIFOs are used for the communication with the FS shell, prepare them. + if $fsShellCommand --uses-fifos; then + fifoBasePath=/tmp/build_haiku_image-$$-fifo + toFSShellFifo=${fifoBasePath}-to-shell + fromFSShellFifo=${fifoBasePath}-from-shell + + rm -f $toFSShellFifo $fromFSShellFifo + mkfifo $toFSShellFifo $fromFSShellFifo + + # Open the FIFOs such that they are ready for the fsShellCommand. This + # also makes sure that they remain open until this script exits. When we + # exit while the FS shell is still running and waiting for commands, + # closing of our file descriptors will break the pipes and the FS shell + # will exit, too. + exec 3<$fromFSShellFifo 4>$toFSShellFifo 5<$toFSShellFifo \ + 6>$fromFSShellFifo + + # Remove the FIFO files again -- we have the open FDs, so they can + # still be used and this makes sure they won't hang around any further. + rm -f $toFSShellFifo $fromFSShellFifo + + # Remap the fsShellCommand and bfsShell such that they don't inherit the + # wrong FDs. For both fsShellCommand and bfsShell FD 3 is the input from + # the respectively other program, FD 4 is the output to it. + actualFSShellCommand="$fsShellCommand" + actualBFSShell="$bfsShell" + + fsShellCommandWrapper() + { + $actualFSShellCommand 5>&- 6>&- "$@" + } + + bfsShellWrapper() + { + $actualBFSShell 3>&5 4<&6 "$@" + } + + fsShellCommand=fsShellCommandWrapper + bfsShell=bfsShellWrapper + fi + + # set up the other commands sPrefix=: tPrefix=/myfs/ cd="$fsShellCommand cd" @@ -227,8 +269,16 @@ if [ $isImage ]; then "$imageLabel" "block_size 2048" $makebootable $imageOffsetFlags "$imagePath" fi + $bfsShell -n $imageOffsetFlags "$imagePath" > /dev/null & sleep 1 + + # Close FDs 5 and 6. Those represent the pipe ends that are used by the + # FS shell. Closing them in the shell process makes sure an unexpected death + # of the FS shell causes writing to/reading from the other ends to fail + # immediately. + exec 5>&- 6>&- + # bail out, if mounting fails $cd . fi diff --git a/src/tools/fs_shell/Jamfile b/src/tools/fs_shell/Jamfile index ba4b2568cf..b5823b9885 100644 --- a/src/tools/fs_shell/Jamfile +++ b/src/tools/fs_shell/Jamfile @@ -23,13 +23,14 @@ DEFINES += HAIKU_BUILD_COMPATIBILITY_H ; local fsShellCommandSources ; local externalCommandsSources ; local fsShellCommandLibs ; -if $(HOST_PLATFORM_BEOS_COMPATIBLE) { +if $(HOST_PLATFORM_BEOS_COMPATIBLE) && $(HOST_PLATFORM) != haiku_host { + # BeOS compatible, but not Haiku -- use BeOS ports for communication fsShellCommandSources = fs_shell_command_beos.cpp ; externalCommandsSources = external_commands_beos.cpp ; } else { + # Unix or Haiku -- use FIFOs for communication fsShellCommandSources = fs_shell_command_unix.cpp ; externalCommandsSources = external_commands_unix.cpp ; - fsShellCommandLibs = $(HOST_NETWORK_LIBS) ; } local kernelEmulationSources = diff --git a/src/tools/fs_shell/external_commands_unix.cpp b/src/tools/fs_shell/external_commands_unix.cpp index cc8dc185af..47f94ab3f8 100644 --- a/src/tools/fs_shell/external_commands_unix.cpp +++ b/src/tools/fs_shell/external_commands_unix.cpp @@ -1,180 +1,75 @@ /* - * Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ + +#include "external_commands.h" + #include #include #include -#include -#include -#include - -#include "external_commands.h" -#include "fs_shell_command_unix.h" -static int sClientConnection = -1; - - -static int -get_command_socket() +static FILE* +get_input() { - 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; - } - - initialized = true; - } - - return fd; + static FILE* sInput = fdopen(3, "r"); + return sInput; } -static int -get_client_connection() +static FILE* +get_output() { - 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; - } -} - - -static bool -read_data(int fd, void* _buffer, size_t toRead) -{ - char* buffer = (char*)_buffer; - - ssize_t bytesRead = 0; - while (toRead > 0 && !(bytesRead < 0 && errno != EINTR)) { - bytesRead = read(fd, buffer, toRead); - if (bytesRead == 0) - break; - if (bytesRead > 0) { - buffer += bytesRead; - toRead -= bytesRead; - } - } - - return (toRead == 0); + static FILE* sOutput = fdopen(4, "w"); + return sOutput; } bool -FSShell::get_external_command(char *input, int len) +FSShell::get_external_command(char* buffer, int size) { - do { - // get a connection - int connection = get_client_connection(); - if (connection < 0) + // get the input stream + FILE* in = get_input(); + if (in == NULL) { + fprintf(stderr, "Error: Failed to open command input: %s\n", + strerror(errno)); + return false; + } + + while (true) { + // read a command line + if (fgets(buffer, size, in) != NULL) + return true; + + // when interrupted, try again + if (errno != EINTR) return false; - - // read command message - external_command_message message; - if (!read_data(connection, &message, sizeof(message))) { - // that usually means the connection was closed - close_client_connection(); - continue; - } - - // check command length - if (message.command_length >= (unsigned)len) { - fprintf(stderr, "Error: Command too long!\n"); - close_client_connection(); - continue; - } - - // read the command - if (!read_data(connection, input, message.command_length)) { - fprintf(stderr, "Error: Reading from connection failed: " - "%s\n", strerror(errno)); - close_client_connection(); - continue; - } - - // null-terminate - input[message.command_length] = '\0'; - - return true; - - } while (true); + } } void FSShell::reply_to_external_command(int result) { - if (sClientConnection < 0) + // get the output stream + FILE* out = get_output(); + if (out == NULL) { + fprintf(stderr, "Error: Failed to open command output: %s\n", + strerror(errno)); 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(); + if (fprintf(out, "%d\n", result) < 0 || fflush(out) == EOF) { + fprintf(stderr, "Error: Failed to write command reply to output reply: " + "%s\n", strerror(errno)); + } } void FSShell::external_command_cleanup() { - unlink(kFSShellCommandSocketAddress); + // The file will be closed automatically when the team exits. } diff --git a/src/tools/fs_shell/fs_shell_command.cpp b/src/tools/fs_shell/fs_shell_command.cpp index 297dacfa59..e7c27d527c 100644 --- a/src/tools/fs_shell/fs_shell_command.cpp +++ b/src/tools/fs_shell/fs_shell_command.cpp @@ -54,6 +54,9 @@ main(int argc, const char *const *argv) exit(1); } + if (strcmp(argv[1], "--uses-fifos") == 0) + exit(gUsesFifos ? 0 : 1); + // prepare the command string char command[102400]; prepare_command_string(argv + 1, argc - 1, command, sizeof(command)); diff --git a/src/tools/fs_shell/fs_shell_command.h b/src/tools/fs_shell/fs_shell_command.h index e702d50700..1a81f313f3 100644 --- a/src/tools/fs_shell/fs_shell_command.h +++ b/src/tools/fs_shell/fs_shell_command.h @@ -6,6 +6,9 @@ #define _FSSH_FS_SHELL_COMMAND_H +extern bool gUsesFifos; + + bool send_external_command(const char* command, int* result); diff --git a/src/tools/fs_shell/fs_shell_command_beos.cpp b/src/tools/fs_shell/fs_shell_command_beos.cpp index e72184f5a8..5247d99385 100644 --- a/src/tools/fs_shell/fs_shell_command_beos.cpp +++ b/src/tools/fs_shell/fs_shell_command_beos.cpp @@ -13,6 +13,9 @@ #include "fs_shell_command.h" +bool gUsesFifos = false; + + bool send_external_command(const char *command, int *result) { diff --git a/src/tools/fs_shell/fs_shell_command_unix.cpp b/src/tools/fs_shell/fs_shell_command_unix.cpp index 8ba60bfc67..779d7a87cb 100644 --- a/src/tools/fs_shell/fs_shell_command_unix.cpp +++ b/src/tools/fs_shell/fs_shell_command_unix.cpp @@ -1,103 +1,64 @@ /* - * Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. + * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#include "fs_shell_command_unix.h" #include #include +#include #include -#include -#include -#include #include "fs_shell_command.h" -static bool -write_data(int fd, const void* _buffer, size_t toWrite) -{ - const char* buffer = (const char*)_buffer; - - ssize_t bytesWritten; - do { - bytesWritten = write(fd, buffer, toWrite); - if (bytesWritten > 0) { - buffer += bytesWritten; - toWrite -= bytesWritten; - } - } while (toWrite > 0 && !(bytesWritten < 0 && errno != EINTR)); - - return (bytesWritten >= 0); -} +bool gUsesFifos = true; bool -send_external_command(const char *command, int *result) +send_external_command(const char* command, int* result) { - external_command_message message; - message.command_length = strlen(command); - - // create a socket - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - fprintf(stderr, "Error: Failed to open unix socket: %s\n", + // open the pipe to the FS shell + FILE* out = fdopen(4, "w"); + if (out == NULL) { + fprintf(stderr, "Error: Failed to open command output: %s\n", strerror(errno)); return false; } - // 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) { - fprintf(stderr, "Error: Failed to open connection to FS shell: %s\n", + // open the pipe from the FS shell + FILE* in = fdopen(3, "r"); + if (in == NULL) { + fprintf(stderr, "Error: Failed to open command reply input: %s\n", strerror(errno)); - close(fd); - return false; - } - - // send the command message and the command - if (!write_data(fd, &message, sizeof(message)) - || !write_data(fd, command, message.command_length)) { - fprintf(stderr, "Error: Writing to fs_shell failed: %s\n", - strerror(errno)); - close(fd); return false; } - // 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, "Error: Failed to read reply from fs_shell: " - "%s\n", strerror(errno)); - close(fd); - return false; - } - } - - if (bytesRead == 0) { - fprintf(stderr, "Error: Unexpected end of fs_shell reply. Was " - "still expecting %d bytes\n", toRead); - close(fd); - return false; - } - - replyBuffer += bytesRead; - toRead -= bytesRead; + // write the command + if (fputs(command, out) == EOF || fputc('\n', out) == EOF + || fflush(out) == EOF) { + fprintf(stderr, "Error: Failed to write command to FS shell: %s\n", + strerror(errno)); + return false; + } + + // read the reply + char buffer[16]; + if (fgets(buffer, sizeof(buffer), in) == NULL) { + fprintf(stderr, "Error: Failed to get command reply: %s\n", + strerror(errno)); + return false; + } + + // parse the number + char* end; + *result = strtol(buffer, &end, 10); + if (end == buffer) { + fprintf(stderr, "Error: Read non-number command reply from FS shell: " + "\"%s\"\n", buffer); + return false; } - close(fd); - *result = reply.error; return true; } diff --git a/src/tools/fs_shell/fs_shell_command_unix.h b/src/tools/fs_shell/fs_shell_command_unix.h deleted file mode 100644 index e60203a828..0000000000 --- a/src/tools/fs_shell/fs_shell_command_unix.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. - * Distributed under the terms of the MIT License. - */ -#ifndef _FSSH_FS_SHELL_COMMAND_UNIX_H -#define _FSSH_FS_SHELL_COMMAND_UNIX_H - - -static const char *kFSShellCommandSocketAddress = "/tmp/fs_shell_commands"; - -struct external_command_message { - unsigned command_length; -}; - -struct external_command_reply { - int error; -}; - - -#endif // _FSSH_FS_SHELL_COMMAND_UNIX_H