Reimplemented the communication with the FS shell for Unixish systems (now
including also Haiku) using FIFOs instead of Unix sockets. Advantages: * Multiple FS shells can run concurrently, since they no longer need a unique address. * Killing/aborting the build_haiku_image script will automatically tear down the FS shell as well, so there shouldn't be any stray FS shell processes anymore. Hopefully also fixes #5498. So far only tested under Haiku. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40097 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -72,6 +72,48 @@ if [ $isCD ]; then
|
|||||||
mkdir=mkdir
|
mkdir=mkdir
|
||||||
rm=rm
|
rm=rm
|
||||||
elif [ $isImage ]; then
|
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=:
|
sPrefix=:
|
||||||
tPrefix=/myfs/
|
tPrefix=/myfs/
|
||||||
cd="$fsShellCommand cd"
|
cd="$fsShellCommand cd"
|
||||||
@@ -227,8 +269,16 @@ if [ $isImage ]; then
|
|||||||
"$imageLabel" "block_size 2048"
|
"$imageLabel" "block_size 2048"
|
||||||
$makebootable $imageOffsetFlags "$imagePath"
|
$makebootable $imageOffsetFlags "$imagePath"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$bfsShell -n $imageOffsetFlags "$imagePath" > /dev/null &
|
$bfsShell -n $imageOffsetFlags "$imagePath" > /dev/null &
|
||||||
sleep 1
|
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
|
# bail out, if mounting fails
|
||||||
$cd .
|
$cd .
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -23,13 +23,14 @@ DEFINES += HAIKU_BUILD_COMPATIBILITY_H ;
|
|||||||
local fsShellCommandSources ;
|
local fsShellCommandSources ;
|
||||||
local externalCommandsSources ;
|
local externalCommandsSources ;
|
||||||
local fsShellCommandLibs ;
|
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 ;
|
fsShellCommandSources = fs_shell_command_beos.cpp ;
|
||||||
externalCommandsSources = external_commands_beos.cpp ;
|
externalCommandsSources = external_commands_beos.cpp ;
|
||||||
} else {
|
} else {
|
||||||
|
# Unix or Haiku -- use FIFOs for communication
|
||||||
fsShellCommandSources = fs_shell_command_unix.cpp ;
|
fsShellCommandSources = fs_shell_command_unix.cpp ;
|
||||||
externalCommandsSources = external_commands_unix.cpp ;
|
externalCommandsSources = external_commands_unix.cpp ;
|
||||||
fsShellCommandLibs = $(HOST_NETWORK_LIBS) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local kernelEmulationSources =
|
local kernelEmulationSources =
|
||||||
|
|||||||
@@ -1,180 +1,75 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2007, Ingo Weinhold, [email protected].de.
|
* Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "external_commands.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#include "external_commands.h"
|
|
||||||
#include "fs_shell_command_unix.h"
|
|
||||||
|
|
||||||
|
|
||||||
static int sClientConnection = -1;
|
static FILE*
|
||||||
|
get_input()
|
||||||
|
|
||||||
static int
|
|
||||||
get_command_socket()
|
|
||||||
{
|
{
|
||||||
static int fd = -1;
|
static FILE* sInput = fdopen(3, "r");
|
||||||
static bool initialized = false;
|
return sInput;
|
||||||
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 int
|
static FILE*
|
||||||
get_client_connection()
|
get_output()
|
||||||
{
|
{
|
||||||
if (sClientConnection >= 0)
|
static FILE* sOutput = fdopen(4, "w");
|
||||||
return sClientConnection;
|
return sOutput;
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FSShell::get_external_command(char *input, int len)
|
FSShell::get_external_command(char* buffer, int size)
|
||||||
{
|
{
|
||||||
do {
|
// get the input stream
|
||||||
// get a connection
|
FILE* in = get_input();
|
||||||
int connection = get_client_connection();
|
if (in == NULL) {
|
||||||
if (connection < 0)
|
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;
|
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
|
void
|
||||||
FSShell::reply_to_external_command(int result)
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// prepare the reply
|
if (fprintf(out, "%d\n", result) < 0 || fflush(out) == EOF) {
|
||||||
external_command_reply reply;
|
fprintf(stderr, "Error: Failed to write command reply to output reply: "
|
||||||
reply.error = result;
|
"%s\n", strerror(errno));
|
||||||
|
}
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FSShell::external_command_cleanup()
|
FSShell::external_command_cleanup()
|
||||||
{
|
{
|
||||||
unlink(kFSShellCommandSocketAddress);
|
// The file will be closed automatically when the team exits.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ main(int argc, const char *const *argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "--uses-fifos") == 0)
|
||||||
|
exit(gUsesFifos ? 0 : 1);
|
||||||
|
|
||||||
// prepare the command string
|
// prepare the command string
|
||||||
char command[102400];
|
char command[102400];
|
||||||
prepare_command_string(argv + 1, argc - 1, command, sizeof(command));
|
prepare_command_string(argv + 1, argc - 1, command, sizeof(command));
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#define _FSSH_FS_SHELL_COMMAND_H
|
#define _FSSH_FS_SHELL_COMMAND_H
|
||||||
|
|
||||||
|
|
||||||
|
extern bool gUsesFifos;
|
||||||
|
|
||||||
|
|
||||||
bool send_external_command(const char* command, int* result);
|
bool send_external_command(const char* command, int* result);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#include "fs_shell_command.h"
|
#include "fs_shell_command.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool gUsesFifos = false;
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
send_external_command(const char *command, int *result)
|
send_external_command(const char *command, int *result)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,103 +1,64 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2007, Ingo Weinhold, [email protected].de.
|
* Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs_shell_command_unix.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#include "fs_shell_command.h"
|
#include "fs_shell_command.h"
|
||||||
|
|
||||||
|
|
||||||
static bool
|
bool gUsesFifos = true;
|
||||||
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
|
bool
|
||||||
send_external_command(const char *command, int *result)
|
send_external_command(const char* command, int* result)
|
||||||
{
|
{
|
||||||
external_command_message message;
|
// open the pipe to the FS shell
|
||||||
message.command_length = strlen(command);
|
FILE* out = fdopen(4, "w");
|
||||||
|
if (out == NULL) {
|
||||||
// create a socket
|
fprintf(stderr, "Error: Failed to open command output: %s\n",
|
||||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
fprintf(stderr, "Error: Failed to open unix socket: %s\n",
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect to the fs_shell
|
// open the pipe from the FS shell
|
||||||
sockaddr_un addr;
|
FILE* in = fdopen(3, "r");
|
||||||
addr.sun_family = AF_UNIX;
|
if (in == NULL) {
|
||||||
strcpy(addr.sun_path, kFSShellCommandSocketAddress);
|
fprintf(stderr, "Error: Failed to open command reply input: %s\n",
|
||||||
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",
|
|
||||||
strerror(errno));
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the reply
|
// write the command
|
||||||
external_command_reply reply;
|
if (fputs(command, out) == EOF || fputc('\n', out) == EOF
|
||||||
int toRead = sizeof(reply);
|
|| fflush(out) == EOF) {
|
||||||
char *replyBuffer = (char*)&reply;
|
fprintf(stderr, "Error: Failed to write command to FS shell: %s\n",
|
||||||
while (toRead > 0) {
|
strerror(errno));
|
||||||
int bytesRead = read(fd, replyBuffer, toRead);
|
return false;
|
||||||
if (bytesRead < 0) {
|
}
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
// read the reply
|
||||||
} else {
|
char buffer[16];
|
||||||
fprintf(stderr, "Error: Failed to read reply from fs_shell: "
|
if (fgets(buffer, sizeof(buffer), in) == NULL) {
|
||||||
"%s\n", strerror(errno));
|
fprintf(stderr, "Error: Failed to get command reply: %s\n",
|
||||||
close(fd);
|
strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// parse the number
|
||||||
if (bytesRead == 0) {
|
char* end;
|
||||||
fprintf(stderr, "Error: Unexpected end of fs_shell reply. Was "
|
*result = strtol(buffer, &end, 10);
|
||||||
"still expecting %d bytes\n", toRead);
|
if (end == buffer) {
|
||||||
close(fd);
|
fprintf(stderr, "Error: Read non-number command reply from FS shell: "
|
||||||
return false;
|
"\"%s\"\n", buffer);
|
||||||
}
|
return false;
|
||||||
|
|
||||||
replyBuffer += bytesRead;
|
|
||||||
toRead -= bytesRead;
|
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
|
|
||||||
*result = reply.error;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2005-2007, Ingo Weinhold, [email protected].
|
|
||||||
* 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
|
|
||||||
Reference in New Issue
Block a user