* Quieted down success output.

* Added non-interactive (external commands) support. The BeOS
  implementation needs some more work; well, the whole FS shell will
  probably have build issues on BeOS ATM.
* Added reasonably complete argument processing in main(). Options are
  similar to the old FS shell.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20894 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-04-28 23:47:03 +00:00
parent 81d40ece27
commit f6233d2330
11 changed files with 746 additions and 45 deletions
+18
View File
@@ -11,6 +11,18 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers build os support ] : true ;
UsePrivateHeaders fs_shell ;
UsePrivateHeaders shared ;
# platform specific sources
local fsShellCommandSources ;
local externalCommandsSources ;
if $(HOST_PLATFORM_BEOS_COMPATIBLE) {
fsShellCommandSources = fs_shell_command_beos.cpp ;
externalCommandsSources = external_commands_beos.cpp ;
} else {
fsShellCommandSources = fs_shell_command_unix.cpp ;
externalCommandsSources = external_commands_unix.cpp ;
}
BuildPlatformStaticLibrary <build2>fs_shell.a :
atomic.cpp
block_cache.cpp
@@ -39,5 +51,11 @@ BuildPlatformStaticLibrary <build2>fs_shell.a :
unistd.cpp
vfs.cpp
$(externalCommandsSources)
fssh.cpp
;
BuildPlatformMain <build2>fs_shell_command
: fs_shell_command.cpp $(fsShellCommandSources)
: $(HOST_LIBSUPC++) ;
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _FSSH_EXTERNAL_COMMANDS_H
#define _FSSH_EXTERNAL_COMMANDS_H
namespace FSShell {
bool get_external_command(char* input, int len);
void reply_to_external_command(int result);
void external_command_cleanup();
} // namespace FSShell
#endif // _FSSH_EXTERNAL_COMMANDS_H
@@ -0,0 +1,103 @@
/*
* Copyright 2005, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <stdio.h>
#include <string.h>
#include <OS.h>
#include "external_commands.h"
#include "fs_shell_command_beos.h"
static port_id sReplyPort = -1;
static port_id
get_command_port()
{
static port_id port = -1;
static bool initialized = false;
if (!initialized) {
port = create_port(10, kFSShellCommandPort);
initialized = true;
}
return port;
}
bool
get_external_command(char *input, int len)
{
// get/create the port
port_id port = get_command_port();
if (port < 0) {
fprintf(stderr, "Failed to create command port: %s\n", strerror(port));
return false;
}
while (true) {
// read a message
external_command_message message;
ssize_t bytesRead;
do {
int32 code;
bytesRead = read_port(port, &code, &message, sizeof(message));
} while (bytesRead == B_INTERRUPTED);
if (bytesRead < 0) {
fprintf(stderr, "Reading from port failed: %s\n",
strerror(bytesRead));
return false;
}
// get the len of the command
int commandLen = (char*)&message + bytesRead - message.command;
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
sReplyPort = message.reply_port;
return true;
}
}
void
reply_to_external_command(int result)
{
if (sReplyPort >= 0) {
// prepare the message
external_command_reply reply;
reply.error = result;
// send the reply
status_t error;
do {
error = write_port(sReplyPort, 0, &reply, sizeof(reply));
} while (error == B_INTERRUPTED);
sReplyPort = -1;
if (error != B_OK) {
fprintf(stderr, "Failed to send command result to reply port: %s\n",
strerror(error));
}
}
}
void
external_command_cleanup()
{
// The port will be deleted automatically when the team exits.
}
@@ -0,0 +1,180 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* 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 "external_commands.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;
}
initialized = true;
}
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;
}
}
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
FSShell::get_external_command(char *input, int len)
{
do {
// get a connection
int connection = get_client_connection();
if (connection < 0)
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)
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();
}
void
FSShell::external_command_cleanup()
{
unlink(kFSShellCommandSocketAddress);
}
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "fs_shell_command.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
add_char(char *&buffer, int &bufferSize, char c)
{
if (bufferSize <= 0) {
fprintf(stderr, "Error: 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, "Error: No command given.\n");
exit(1);
}
// prepare the command string
char command[102400];
prepare_command_string(argv + 1, argc - 1, command, sizeof(command));
// send the command
int result;
if (!send_external_command(command, &result))
exit(1);
// evaluate result
if (result != 0) {
fprintf(stderr, "Error: Command failed: %s\n", strerror(result));
fprintf(stderr, "Error: Command was:\n %s\n", command);
exit(1);
}
return 0;
}
+13
View File
@@ -0,0 +1,13 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _FSSH_FS_SHELL_COMMAND_H
#define _FSSH_FS_SHELL_COMMAND_H
bool send_external_command(const char* command, int* result);
#endif // _FSSH_FS_SHELL_COMMAND_H
@@ -0,0 +1,66 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "fs_shell_command_beos.h"
#include <stdio.h>
#include <string.h>
#include <OS.h>
#include "fs_shell_command.h"
bool
send_external_command(const char *command, int *result)
{
external_command_message message;
strncpy(message.command, command, sizeof(message.command));
// find the command port
port_id commandPort = find_port(kFSShellCommandPort);
if (commandPort < 0) {
fprintf(stderr, "Error: Couldn't find fs_shell command port.\n");
return false;
}
// create a reply port
port_id replyPort = create_port(1, "fs shell reply port");
if (replyPort < 0) {
fprintf(stderr, "Error: Failed to create a reply port: %s\n",
strerror(replyPort));
return false;
}
message.reply_port = replyPort;
// send the command message
status_t error;
do {
error = write_port(commandPort, 0, &message, sizeof(message));
} while (error == B_INTERRUPTED);
if (error != B_OK) {
fprintf(stderr, "Error: Failed to send command: %s\n", strerror(error));
return false;
}
// wait for the reply
external_command_reply reply;
ssize_t bytesRead;
do {
int32 code;
bytesRead = read_port(replyPort, &code, &reply, sizeof(reply));
} while (bytesRead == B_INTERRUPTED);
if (bytesRead < 0) {
fprintf(stderr, "Error: Failed to read reply from fs_shell: %s\n",
strerror(bytesRead));
return false;
}
*result = reply.error;
return true;
}
@@ -0,0 +1,20 @@
/*
* Copyright 2005, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef FS_SHELL_COMMAND_BEOS_H
#define FS_SHELL_COMMAND_BEOS_H
static const char *kFSShellCommandPort = "fs shell command port";
struct external_command_message {
port_id reply_port;
char command[20480];
// TODO: Increase command size and transmit only as much as necessary.
};
struct external_command_reply {
int error;
};
#endif // FS_SHELL_COMMAND_BEOS_H
@@ -0,0 +1,101 @@
/*
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "fs_shell_command_unix.h"
#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"
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
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",
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",
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);
return false;
}
replyBuffer += bytesRead;
toRead -= bytesRead;
}
*result = reply.error;
return true;
}
@@ -0,0 +1,21 @@
/*
* 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
+128 -45
View File
@@ -15,6 +15,7 @@
#include <vector>
#include "command_cp.h"
#include "external_commands.h"
#include "fd.h"
#include "fssh_dirent.h"
#include "fssh_errno.h"
@@ -38,6 +39,10 @@ extern fssh_file_system_module_info gRootFileSystem;
const char* kMountPoint = "/myfs";
// command line args
static int sArgc;
static const char* const* sArgv;
static fssh_status_t
init_kernel()
@@ -49,8 +54,7 @@ init_kernel()
if (error != FSSH_B_OK) {
fprintf(stderr, "module_init() failed: %s\n", fssh_strerror(error));
return error;
} else
printf("module_init() succeeded!\n");
}
// register built-in modules, i.e. the rootfs and the client FS
register_builtin_module(&gRootFileSystem.info);
@@ -62,8 +66,7 @@ init_kernel()
if (error != FSSH_B_OK) {
fprintf(stderr, "initializing VFS failed: %s\n", fssh_strerror(error));
return error;
} else
printf("VFS initialized successfully!\n");
}
// init kernel IO context
gKernelIOContext = (io_context*)vfs_new_io_context(NULL);
@@ -77,16 +80,14 @@ init_kernel()
if (rootDev < 0) {
fprintf(stderr, "mounting rootfs failed: %s\n", fssh_strerror(rootDev));
return rootDev;
} else
printf("mounted rootfs successfully!\n");
}
// set cwd to "/"
error = _kern_setcwd(-1, "/");
if (error != FSSH_B_OK) {
fprintf(stderr, "setting cwd failed: %s\n", fssh_strerror(error));
return error;
} else
printf("set cwd successfully!\n");
}
// create mount point for the client FS
error = _kern_create_dir(-1, kMountPoint, 0775);
@@ -94,8 +95,7 @@ init_kernel()
fprintf(stderr, "creating mount point failed: %s\n",
fssh_strerror(error));
return error;
} else
printf("mount point created successfully!\n");
}
return FSSH_B_OK;
}
@@ -1036,15 +1036,20 @@ read_command_line(char* buffer, int bufferSize)
static void
input_loop()
input_loop(bool interactive)
{
static const int kInputBufferSize = 100 * 1024;
char* inputBuffer = new char[kInputBufferSize];
for (;;) {
// read command line
if (!read_command_line(inputBuffer, kInputBufferSize))
break;
if (interactive) {
if (!read_command_line(inputBuffer, kInputBufferSize))
break;
} else {
if (!get_external_command(inputBuffer, kInputBufferSize))
break;
}
// construct argv vector
ArgVector argVector;
@@ -1062,14 +1067,79 @@ input_loop()
}
int result = command->Do(argc, argv);
if (result == COMMAND_RESULT_EXIT)
if (result == COMMAND_RESULT_EXIT) {
reply_to_external_command(0);
break;
}
reply_to_external_command(fssh_to_host_error(result));
}
if (!interactive)
external_command_cleanup();
delete[] inputBuffer;
}
static int
standard_session(const char* device, const char* fsName, bool interactive)
{
// mount FS
fssh_dev_t fsDev = _kern_mount(kMountPoint, device, fsName, 0, NULL, 0);
if (fsDev < 0) {
fprintf(stderr, "Error: Mounting FS failed: %s\n",
fssh_strerror(fsDev));
return 1;
}
// register commands
register_commands();
// process commands
input_loop(interactive);
// unmount FS
_kern_setcwd(-1, "/"); // avoid a "busy" vnode
fssh_status_t error = _kern_unmount(kMountPoint, 0);
if (error != FSSH_B_OK) {
fprintf(stderr, "Error: Unmounting FS failed: %s\n",
fssh_strerror(error));
return 1;
}
return 0;
}
static int
initialization_session(const char* device, const char* fsName,
const char* initParameters)
{
fprintf(stderr, "initialization not implemented yet\n");
return 1;
}
static void
print_usage(bool error)
{
fprintf((error ? stderr : stdout),
"Usage: %s [-n] <device>\n"
" %s --initialize [-n] <device> [ <init parameters> ]\n",
sArgv[0], sArgv[0]
);
}
static void
print_usage_and_exit(bool error)
{
print_usage(error);
exit(error ? 1 : 0);
}
} // namespace FSShell
@@ -1079,16 +1149,46 @@ using namespace FSShell;
int
main(int argc, const char* const* argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: ...\n");
return 1;
sArgc = argc;
sArgv = argv;
// process arguments
bool interactive = true;
bool initialize = false;
const char* device = NULL;
const char* initParameters = NULL;
// eat options
int argi = 1;
while (argi < argc && argv[argi][0] == '-') {
const char* arg = argv[argi++];
if (strcmp(arg, "--help") == 0) {
print_usage_and_exit(false);
} else if (strcmp(arg, "--initialize") == 0) {
initialize = true;
} else if (strcmp(arg, "-n") == 0) {
interactive = false;
} else {
print_usage_and_exit(true);
}
}
const char* device = argv[1];
// get device
if (argi >= argc)
print_usage_and_exit(true);
device = argv[argi++];
// get init parameters
if (initialize && argi < argc)
initParameters = argv[argi++];
// if more parameters are excess
if (argi < argc)
print_usage_and_exit(true);
// get FS module
if (!modules[0]) {
fprintf(stderr, "Couldn't find FS module!\n");
fprintf(stderr, "Error: Couldn't find FS module!\n");
return 1;
}
const char* fsName = modules[0]->name;
@@ -1098,34 +1198,17 @@ main(int argc, const char* const* argv)
// init kernel
error = init_kernel();
if (error != FSSH_B_OK) {
fprintf(stderr, "initializing kernel failed: %s\n",
fprintf(stderr, "Error: Initializing kernel failed: %s\n",
fssh_strerror(error));
return error;
} else
printf("kernel initialized successfully!\n");
}
// mount FS
fssh_dev_t fsDev = _kern_mount(kMountPoint, device, fsName, 0, NULL, 0);
if (fsDev < 0) {
fprintf(stderr, "mounting FS failed: %s\n", fssh_strerror(fsDev));
return 1;
} else
printf("mounted FS successfully!\n");
// start the action
int result;
if (initialize)
result = initialization_session(device, fsName, initParameters);
else
result = standard_session(device, fsName, interactive);
// register commands
register_commands();
// process commands
input_loop();
// unmount FS
_kern_setcwd(-1, "/"); // avoid a "busy" vnode
error = _kern_unmount(kMountPoint, 0);
if (error != FSSH_B_OK) {
fprintf(stderr, "unmounting FS failed: %s\n", fssh_strerror(error));
return error;
} else
printf("FS unmounted successfully!\n");
return 0;
return result;
}