Added getopt_long command-line handling.
All parameters now have switches. The one gotcha is the parameter which was overloaded - s_length_or_filename to params_readwrite - is only pretending to be a length at the moment. If you pass a filename it'll still work, but the help messages don't mention that. I'll split the parameter into two in a later commit.
This commit is contained in:
449
src/flexnbd.c
449
src/flexnbd.c
@@ -32,75 +32,79 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
void syntax()
|
#include <getopt.h>
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
|
||||||
|
void exit_err( char *msg )
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf( stderr, msg );
|
||||||
"Syntax: flexnbd serve <listen IP address> <port> <file> \\\n"
|
exit( 1 );
|
||||||
" [full path to control socket] \\\n"
|
|
||||||
" [allowed connection addresses ...]\n"
|
|
||||||
" flexnbd read <IP address> <port> <offset> <length> > data\n"
|
|
||||||
" flexnbd write <IP address> <port> <offset> <length> < data\n"
|
|
||||||
" flexnbd write <IP address> <port> <offset> <file to write>\n"
|
|
||||||
" flexnbd acl <control socket> [allowed connection addresses ...]\n"
|
|
||||||
" flexnbd mirror <control socket> <dst IP address> <dst port>\n"
|
|
||||||
" [bytes per second] [proxy|nothing|exit]"
|
|
||||||
" flexnbd status <control socket>\n"
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void params_serve(
|
void params_serve(
|
||||||
struct mode_serve_params* out,
|
struct mode_serve_params* out,
|
||||||
char* s_ip_address,
|
char* s_ip_address,
|
||||||
char* s_port,
|
char* s_port,
|
||||||
char* s_file,
|
char* s_file,
|
||||||
|
char *s_ctrl_sock,
|
||||||
int acl_entries,
|
int acl_entries,
|
||||||
char** s_acl_entries /* first may actually be path to control socket */
|
char** s_acl_entries
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int parsed;
|
int parsed;
|
||||||
|
|
||||||
out->tcp_backlog = 10; /* does this need to be settable? */
|
out->tcp_backlog = 10; /* does this need to be settable? */
|
||||||
|
|
||||||
if (s_ip_address == NULL)
|
if (s_ip_address == NULL)
|
||||||
SERVER_ERROR("No IP address supplied");
|
SERVER_ERROR("No IP address supplied");
|
||||||
if (s_port == NULL)
|
if (s_port == NULL)
|
||||||
SERVER_ERROR("No port number supplied");
|
SERVER_ERROR("No port number supplied");
|
||||||
if (s_file == NULL)
|
if (s_file == NULL)
|
||||||
SERVER_ERROR("No filename supplied");
|
SERVER_ERROR("No filename supplied");
|
||||||
|
|
||||||
if (parse_ip_to_sockaddr(&out->bind_to.generic, s_ip_address) == 0)
|
if (parse_ip_to_sockaddr(&out->bind_to.generic, s_ip_address) == 0)
|
||||||
SERVER_ERROR("Couldn't parse server address '%s' (use 0 if "
|
SERVER_ERROR("Couldn't parse server address '%s' (use 0 if "
|
||||||
"you want to bind to all IPs)", s_ip_address);
|
"you want to bind to all IPs)", s_ip_address);
|
||||||
|
|
||||||
out->control_socket_name = NULL;
|
/* control_socket_name is optional. It just won't get created if
|
||||||
|
* we pass NULL. */
|
||||||
if (acl_entries > 0 && s_acl_entries[0][0] == '/') {
|
out->control_socket_name = s_ctrl_sock;
|
||||||
out->control_socket_name = s_acl_entries[0];
|
|
||||||
s_acl_entries++;
|
|
||||||
acl_entries--;
|
|
||||||
}
|
|
||||||
|
|
||||||
out->acl_entries = acl_entries;
|
out->acl_entries = acl_entries;
|
||||||
parsed = parse_acl(&out->acl, acl_entries, s_acl_entries);
|
parsed = parse_acl(&out->acl, acl_entries, s_acl_entries);
|
||||||
if (parsed != acl_entries)
|
if (parsed != acl_entries)
|
||||||
SERVER_ERROR("Bad ACL entry '%s'", s_acl_entries[parsed]);
|
SERVER_ERROR("Bad ACL entry '%s'", s_acl_entries[parsed]);
|
||||||
|
|
||||||
out->bind_to.v4.sin_port = atoi(s_port);
|
out->bind_to.v4.sin_port = atoi(s_port);
|
||||||
if (out->bind_to.v4.sin_port < 0 || out->bind_to.v4.sin_port > 65535)
|
if (out->bind_to.v4.sin_port < 0 || out->bind_to.v4.sin_port > 65535)
|
||||||
SERVER_ERROR("Port number must be >= 0 and <= 65535");
|
SERVER_ERROR("Port number must be >= 0 and <= 65535");
|
||||||
out->bind_to.v4.sin_port = htobe16(out->bind_to.v4.sin_port);
|
out->bind_to.v4.sin_port = htobe16(out->bind_to.v4.sin_port);
|
||||||
|
|
||||||
out->filename = s_file;
|
out->filename = s_file;
|
||||||
out->filename_incomplete = xmalloc(strlen(s_file)+11);
|
out->filename_incomplete = xmalloc(strlen(s_file)+11);
|
||||||
strcpy(out->filename_incomplete, s_file);
|
strcpy(out->filename_incomplete, s_file);
|
||||||
strcpy(out->filename_incomplete + strlen(s_file), ".INCOMPLETE");
|
strcpy(out->filename_incomplete + strlen(s_file), ".INCOMPLETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Separate this function.
|
||||||
|
* It should be:
|
||||||
|
* params_read( struct mode_readwrite_params* out,
|
||||||
|
* char *s_ip_address,
|
||||||
|
* char *s_port,
|
||||||
|
* char *s_from,
|
||||||
|
* char *s_length )
|
||||||
|
* params_write( struct mode_readwrite_params* out,
|
||||||
|
* char *s_ip_address,
|
||||||
|
* char *s_port,
|
||||||
|
* char *s_from,
|
||||||
|
* char *s_length,
|
||||||
|
* char *s_filename )
|
||||||
|
*/
|
||||||
void params_readwrite(
|
void params_readwrite(
|
||||||
int write_not_read,
|
int write_not_read,
|
||||||
struct mode_readwrite_params* out,
|
struct mode_readwrite_params* out,
|
||||||
char* s_ip_address,
|
char* s_ip_address,
|
||||||
char* s_port,
|
char* s_port,
|
||||||
char* s_from,
|
char* s_from,
|
||||||
char* s_length_or_filename
|
char* s_length_or_filename
|
||||||
@@ -114,11 +118,11 @@ void params_readwrite(
|
|||||||
SERVER_ERROR("No from supplied");
|
SERVER_ERROR("No from supplied");
|
||||||
if (s_length_or_filename == NULL)
|
if (s_length_or_filename == NULL)
|
||||||
SERVER_ERROR("No length supplied");
|
SERVER_ERROR("No length supplied");
|
||||||
|
|
||||||
if (parse_ip_to_sockaddr(&out->connect_to.generic, s_ip_address) == 0)
|
if (parse_ip_to_sockaddr(&out->connect_to.generic, s_ip_address) == 0)
|
||||||
SERVER_ERROR("Couldn't parse connection address '%s'",
|
SERVER_ERROR("Couldn't parse connection address '%s'",
|
||||||
s_ip_address);
|
s_ip_address);
|
||||||
|
|
||||||
/* FIXME: duplicated from above */
|
/* FIXME: duplicated from above */
|
||||||
out->connect_to.v4.sin_port = atoi(s_port);
|
out->connect_to.v4.sin_port = atoi(s_port);
|
||||||
if (out->connect_to.v4.sin_port < 0 || out->connect_to.v4.sin_port > 65535)
|
if (out->connect_to.v4.sin_port < 0 || out->connect_to.v4.sin_port > 65535)
|
||||||
@@ -126,7 +130,7 @@ void params_readwrite(
|
|||||||
out->connect_to.v4.sin_port = htobe16(out->connect_to.v4.sin_port);
|
out->connect_to.v4.sin_port = htobe16(out->connect_to.v4.sin_port);
|
||||||
|
|
||||||
out->from = atol(s_from);
|
out->from = atol(s_from);
|
||||||
|
|
||||||
if (write_not_read) {
|
if (write_not_read) {
|
||||||
if (s_length_or_filename[0]-48 < 10) {
|
if (s_length_or_filename[0]-48 < 10) {
|
||||||
out->len = atol(s_length_or_filename);
|
out->len = atol(s_length_or_filename);
|
||||||
@@ -157,66 +161,351 @@ void do_read(struct mode_readwrite_params* params);
|
|||||||
void do_write(struct mode_readwrite_params* params);
|
void do_write(struct mode_readwrite_params* params);
|
||||||
void do_remote_command(char* command, char* mode, int argc, char** argv);
|
void do_remote_command(char* command, char* mode, int argc, char** argv);
|
||||||
|
|
||||||
union mode_params {
|
void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char **sock )
|
||||||
|
{
|
||||||
|
switch(c){
|
||||||
|
case 'h':
|
||||||
|
fprintf(stdout, serve_help_text );
|
||||||
|
exit( 0 );
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
*ip_addr = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
*ip_port = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
*file = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
*sock = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit_err( serve_help_text );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **from, char **size)
|
||||||
|
{
|
||||||
|
switch(c){
|
||||||
|
case 'h':
|
||||||
|
fprintf(stdout, read_help_text );
|
||||||
|
exit( 0 );
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
*ip_addr = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
*ip_port = optarg;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
*from = optarg;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
*size = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit_err( read_help_text );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_sock_param( int c, char **sock, char *help_text )
|
||||||
|
{
|
||||||
|
switch(c){
|
||||||
|
case 'h':
|
||||||
|
fprintf( stdout, help_text );
|
||||||
|
exit( 0 );
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
*sock = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit_err( help_text );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_acl_param( int c, char **sock )
|
||||||
|
{
|
||||||
|
read_sock_param( c, sock, acl_help_text );
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_mirror_param( int c, char **sock, char **ip_addr, char **ip_port )
|
||||||
|
{
|
||||||
|
switch( c ){
|
||||||
|
case 'h':
|
||||||
|
fprintf( stdout, mirror_help_text );
|
||||||
|
exit( 0 );
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
*sock = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
*ip_addr = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
*ip_port = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit_err( mirror_help_text );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_status_param( int c, char **sock )
|
||||||
|
{
|
||||||
|
read_sock_param( c, sock, status_help_text );
|
||||||
|
}
|
||||||
|
|
||||||
|
int mode_serve( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *ip_addr = NULL;
|
||||||
|
char *ip_port = NULL;
|
||||||
|
char *file = NULL;
|
||||||
|
char *sock = NULL;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
struct mode_serve_params serve;
|
struct mode_serve_params serve;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long(argc, argv, serve_short_options, serve_options, NULL);
|
||||||
|
if ( c == -1 ) break;
|
||||||
|
read_serve_param( c, &ip_addr, &ip_port, &file, &sock );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == ip_addr || NULL == ip_port ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "both --addr and --port are required.\n" );
|
||||||
|
}
|
||||||
|
if ( NULL == file ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "--file is required\n" );
|
||||||
|
}
|
||||||
|
if ( err ) { exit_err( serve_help_text ); }
|
||||||
|
|
||||||
|
memset( &serve, 0, sizeof( serve ) );
|
||||||
|
params_serve( &serve, ip_addr, ip_port, file, sock, argc - optind, argv + optind );
|
||||||
|
do_serve( &serve );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mode_read( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *ip_addr = NULL;
|
||||||
|
char *ip_port = NULL;
|
||||||
|
char *from = NULL;
|
||||||
|
char *size = NULL;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
struct mode_readwrite_params readwrite;
|
struct mode_readwrite_params readwrite;
|
||||||
};
|
|
||||||
|
while (1){
|
||||||
|
c = getopt_long(argc, argv, read_short_options, read_options, NULL);
|
||||||
|
if ( c == -1 ) break;
|
||||||
|
read_readwrite_param( c, &ip_addr, &ip_port, &from, &size );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == ip_addr || NULL == ip_port ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "both --addr and --port are required.\n" );
|
||||||
|
}
|
||||||
|
if ( NULL == from || NULL == size ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "both --from and --size are required.\n" );
|
||||||
|
}
|
||||||
|
if ( err ) { exit_err( read_help_text ); }
|
||||||
|
|
||||||
|
memset( &readwrite, 0, sizeof( readwrite ) );
|
||||||
|
params_readwrite( 0, &readwrite, ip_addr, ip_port, from, size );
|
||||||
|
do_read( &readwrite );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mode_write( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *ip_addr = NULL;
|
||||||
|
char *ip_port = NULL;
|
||||||
|
char *from = NULL;
|
||||||
|
char *size = NULL;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
struct mode_readwrite_params readwrite;
|
||||||
|
|
||||||
|
while (1){
|
||||||
|
c = getopt_long(argc, argv, write_short_options, write_options, NULL);
|
||||||
|
if ( c == -1 ) break;
|
||||||
|
read_readwrite_param( c, &ip_addr, &ip_port, &from, &size );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == ip_addr || NULL == ip_port ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "both --addr and --port are required.\n" );
|
||||||
|
}
|
||||||
|
if ( NULL == from || NULL == size ) {
|
||||||
|
err = 1;
|
||||||
|
fprintf( stderr, "both --from and --size are required.\n" );
|
||||||
|
}
|
||||||
|
if ( err ) { exit_err( write_help_text ); }
|
||||||
|
|
||||||
|
memset( &readwrite, 0, sizeof( readwrite ) );
|
||||||
|
params_readwrite( 1, &readwrite, ip_addr, ip_port, from, size );
|
||||||
|
do_write( &readwrite );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mode_acl( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *sock = NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long( argc, argv, acl_short_options, acl_options, NULL );
|
||||||
|
if ( c == -1 ) break;
|
||||||
|
read_acl_param( c, &sock );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == sock ){
|
||||||
|
fprintf( stderr, "--sock is required.\n" );
|
||||||
|
exit_err( acl_help_text );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't use the CMD_ACL macro here, "acl" is the remote command
|
||||||
|
* name, not the cli option
|
||||||
|
*/
|
||||||
|
do_remote_command( "acl", sock, argc - optind, argv + optind );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mode_mirror( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *sock = NULL;
|
||||||
|
char *remote_argv[3] = {0};
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long( argc, argv, mirror_short_options, mirror_options, NULL);
|
||||||
|
if ( -1 == c ) break;
|
||||||
|
read_mirror_param( c, &sock, &remote_argv[0], &remote_argv[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == sock ){
|
||||||
|
fprintf( stderr, "--sock is required.\n" );
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
if ( NULL == remote_argv[0] || NULL == remote_argv[1] ) {
|
||||||
|
fprintf( stderr, "both --addr and --port are required.\n");
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
if ( err ) { exit_err( mirror_help_text ); }
|
||||||
|
|
||||||
|
do_remote_command( "mirror", sock, 2, remote_argv );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mode_status( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *sock = NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long( argc, argv, status_short_options, status_options, NULL );
|
||||||
|
if ( -1 == c ) break;
|
||||||
|
read_status_param( c, &sock );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL == sock ){
|
||||||
|
fprintf( stderr, "--sock is required.\n" );
|
||||||
|
exit_err( acl_help_text );
|
||||||
|
}
|
||||||
|
|
||||||
|
do_remote_command( "status", sock, argc - optind, argv + optind );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mode_help( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
char *cmd;
|
||||||
|
char *help_text;
|
||||||
|
|
||||||
|
if ( argc < 1 ){
|
||||||
|
help_text = help_help_text;
|
||||||
|
} else {
|
||||||
|
cmd = argv[0];
|
||||||
|
if (IS_CMD( CMD_SERVE, cmd ) ) {
|
||||||
|
help_text = serve_help_text;
|
||||||
|
} else if ( IS_CMD( CMD_READ, cmd ) ) {
|
||||||
|
help_text = read_help_text;
|
||||||
|
} else if ( IS_CMD( CMD_WRITE, cmd ) ) {
|
||||||
|
help_text = write_help_text;
|
||||||
|
} else if ( IS_CMD( CMD_ACL, cmd ) ) {
|
||||||
|
help_text = acl_help_text;
|
||||||
|
} else if ( IS_CMD( CMD_MIRROR, cmd ) ) {
|
||||||
|
help_text = mirror_help_text;
|
||||||
|
} else if ( IS_CMD( CMD_STATUS, cmd ) ) {
|
||||||
|
help_text = status_help_text;
|
||||||
|
} else { exit_err( help_help_text ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( stdout, help_text );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mode(char* mode, int argc, char **argv)
|
void mode(char* mode, int argc, char **argv)
|
||||||
{
|
{
|
||||||
union mode_params params;
|
if ( IS_CMD( CMD_SERVE, mode ) ) {
|
||||||
memset(¶ms, 0, sizeof(params));
|
mode_serve( argc, argv );
|
||||||
|
|
||||||
if (strcmp(mode, "serve") == 0) {
|
|
||||||
if (argc >= 3) {
|
|
||||||
params_serve(¶ms.serve, argv[0], argv[1], argv[2], argc-3, argv+3);
|
|
||||||
do_serve(¶ms.serve);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
syntax();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (strcmp(mode, "read") == 0 ) {
|
else if ( IS_CMD( CMD_READ, mode ) ) {
|
||||||
if (argc == 4) {
|
mode_read( argc, argv );
|
||||||
params_readwrite(0, ¶ms.readwrite, argv[0], argv[1], argv[2], argv[3]);
|
|
||||||
do_read(¶ms.readwrite);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
syntax();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (strcmp(mode, "write") == 0 ) {
|
else if ( IS_CMD( CMD_WRITE, mode ) ) {
|
||||||
if (argc == 4) {
|
mode_write( argc, argv );
|
||||||
params_readwrite(1, ¶ms.readwrite, argv[0], argv[1], argv[2], argv[3]);
|
|
||||||
do_write(¶ms.readwrite);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
syntax();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (strcmp(mode, "acl") == 0 || strcmp(mode, "mirror") == 0 || strcmp(mode, "status") == 0) {
|
else if ( IS_CMD( CMD_ACL, mode ) ) {
|
||||||
if (argc >= 1) {
|
mode_acl( argc, argv );
|
||||||
do_remote_command(mode, argv[0], argc-1, argv+1);
|
}
|
||||||
}
|
else if ( IS_CMD( CMD_MIRROR, mode ) ) {
|
||||||
else {
|
mode_mirror( argc, argv );
|
||||||
syntax();
|
}
|
||||||
}
|
else if ( IS_CMD( CMD_STATUS, mode ) ) {
|
||||||
|
mode_status( argc, argv );
|
||||||
|
}
|
||||||
|
else if ( IS_CMD( CMD_HELP, mode ) ) {
|
||||||
|
mode_help( argc-1, argv+1 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
syntax();
|
mode_help( argc-1, argv+1 );
|
||||||
|
exit( 1 );
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
|
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
|
||||||
error_init();
|
error_init();
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2) {
|
||||||
syntax();
|
exit_err( help_help_text );
|
||||||
mode(argv[1], argc-2, argv+2); /* never returns */
|
}
|
||||||
|
mode(argv[1], argc-1, argv+1); /* never returns */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
126
src/options.h
Normal file
126
src/options.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#define GETOPT_ARG(x,s) {(x), 1, 0, (s)}
|
||||||
|
#define GETOPT_FLAG(x,v) {(x), 0, 0, (v)}
|
||||||
|
|
||||||
|
#define OPT_HELP "help"
|
||||||
|
#define OPT_ADDR "addr"
|
||||||
|
#define OPT_PORT "port"
|
||||||
|
#define OPT_FILE "file"
|
||||||
|
#define OPT_SOCK "sock"
|
||||||
|
#define OPT_FROM "from"
|
||||||
|
#define OPT_SIZE "size"
|
||||||
|
|
||||||
|
#define CMD_SERVE "serve"
|
||||||
|
#define CMD_READ "read"
|
||||||
|
#define CMD_WRITE "write"
|
||||||
|
#define CMD_ACL "acl"
|
||||||
|
#define CMD_MIRROR "mirror"
|
||||||
|
#define CMD_STATUS "status"
|
||||||
|
#define CMD_HELP "help"
|
||||||
|
#define LEN_CMD_MAX 6
|
||||||
|
|
||||||
|
#define PATH_LEN_MAX 1024
|
||||||
|
#define ADDR_LEN_MAX 64
|
||||||
|
|
||||||
|
|
||||||
|
#define IS_CMD(x,c) (strncmp((x),(c),(LEN_CMD_MAX)) == 0)
|
||||||
|
|
||||||
|
static struct option serve_options[] = {
|
||||||
|
GETOPT_FLAG( OPT_HELP, 'h' ),
|
||||||
|
GETOPT_ARG( OPT_ADDR, 'l' ),
|
||||||
|
GETOPT_ARG( OPT_PORT, 'p' ),
|
||||||
|
GETOPT_ARG( OPT_FILE, 'f' ),
|
||||||
|
GETOPT_ARG( OPT_SOCK, 's' ),
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static char serve_short_options[] = "hl:p:f:s:";
|
||||||
|
static char serve_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_SERVE " <options> [<acl address>*]\n\n"
|
||||||
|
"Serve FILE from ADDR:PORT, with an optional control socket at SOCK.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_ADDR ",-l <ADDR>\tThe address to serve on.\n"
|
||||||
|
"\t--" OPT_PORT ",-p <PORT>\tThe port to serve on.\n"
|
||||||
|
"\t--" OPT_FILE ",-f <FILE>\tThe file to serve.\n"
|
||||||
|
"\t--" OPT_SOCK ",-s <SOCK>\tPath to the control socket to open.\n";
|
||||||
|
|
||||||
|
static struct option read_options[] = {
|
||||||
|
GETOPT_FLAG( OPT_HELP, 'h' ),
|
||||||
|
GETOPT_ARG( OPT_ADDR, 'l' ),
|
||||||
|
GETOPT_ARG( OPT_PORT, 'p' ),
|
||||||
|
GETOPT_ARG( OPT_FROM, 'F' ),
|
||||||
|
GETOPT_ARG( OPT_SIZE, 'S' ),
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static char read_short_options[] = "hl:p:F:S:";
|
||||||
|
static char read_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_READ " <options>\n\n"
|
||||||
|
"Read SIZE bytes from a server at ADDR:PORT to stdout, starting at OFFSET.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_ADDR ",-l <ADDR>\tThe address to read from.\n"
|
||||||
|
"\t--" OPT_PORT ",-p <PORT>\tThe port to read from.\n"
|
||||||
|
"\t--" OPT_FROM ",-F <OFFSET>\tByte offset to read from.\n"
|
||||||
|
"\t--" OPT_SIZE ",-S <SIZE>\tBytes to read.\n";
|
||||||
|
|
||||||
|
|
||||||
|
static struct option *write_options = read_options;
|
||||||
|
static char *write_short_options = read_short_options;
|
||||||
|
static char write_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_WRITE" <options>\n\n"
|
||||||
|
"Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_ADDR ",-l <ADDR>\tThe address to write to.\n"
|
||||||
|
"\t--" OPT_PORT ",-p <PORT>\tThe port to write to.\n"
|
||||||
|
"\t--" OPT_FROM ",-F <OFFSET>\tByte offset to write from.\n"
|
||||||
|
"\t--" OPT_SIZE ",-S <SIZE>\tBytes to write.\n";
|
||||||
|
|
||||||
|
struct option acl_options[] = {
|
||||||
|
GETOPT_FLAG( OPT_HELP, 'h' ),
|
||||||
|
GETOPT_ARG( OPT_SOCK, 's' ),
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static char acl_short_options[] = "hs:";
|
||||||
|
static char acl_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_ACL " <options> [<acl address>+]\n\n"
|
||||||
|
"Set the access control list for a server with control socket SOCK.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_SOCK ",-s <SOCK>\tPath to the control socket.\n";
|
||||||
|
|
||||||
|
struct option mirror_options[] = {
|
||||||
|
GETOPT_FLAG( OPT_HELP, 'h' ),
|
||||||
|
GETOPT_ARG( OPT_SOCK, 's' ),
|
||||||
|
GETOPT_ARG( OPT_ADDR, 'l' ),
|
||||||
|
GETOPT_ARG( OPT_PORT, 'p' ),
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static char mirror_short_options[] = "hs:l:p:";
|
||||||
|
static char mirror_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_MIRROR " <options>\n\n"
|
||||||
|
"Start mirroring from the server with control socket SOCK to one at ADDR:PORT.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_SOCK ",-s <SOCK>\tPath to the control socket.\n"
|
||||||
|
"\t--" OPT_ADDR ",-l <ADDR>\tThe address to mirror to.\n"
|
||||||
|
"\t--" OPT_PORT ",-p <PORT>\tThe port to mirror to.\n";
|
||||||
|
|
||||||
|
|
||||||
|
struct option status_options[] = {
|
||||||
|
GETOPT_FLAG( OPT_HELP, 'h' ),
|
||||||
|
GETOPT_ARG( OPT_SOCK, 's' ),
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
static char status_short_options[] = "hs:";
|
||||||
|
static char status_help_text[] =
|
||||||
|
"Usage: flexnbd " CMD_STATUS " <options>\n\n"
|
||||||
|
"Get the status for a server with control socket SOCK.\n\n"
|
||||||
|
"\t--" OPT_HELP ",-h\tThis text.\n"
|
||||||
|
"\t--" OPT_SOCK ",-s <SOCK>\tPath to the control socket.\n";
|
||||||
|
|
||||||
|
static char help_help_text[] =
|
||||||
|
"Usage: flexnbd <cmd> [cmd options]\n\n"
|
||||||
|
"Commands:\n"
|
||||||
|
"\tflexnbd serve\n"
|
||||||
|
"\tflexnbd read\n"
|
||||||
|
"\tflexnbd write\n"
|
||||||
|
"\tflexnbd acl\n"
|
||||||
|
"\tflexnbd mirror\n"
|
||||||
|
"\tflexnbd status\n"
|
||||||
|
"\tflexnbd help\n\n"
|
||||||
|
"See flexnbd help <cmd> for further info\n";
|
@@ -15,7 +15,13 @@ class FlexNBD
|
|||||||
|
|
||||||
def serve(ip, port, file, *acl)
|
def serve(ip, port, file, *acl)
|
||||||
@pid = fork do
|
@pid = fork do
|
||||||
exec("#{@bin} serve #{ip} #{port} #{file} #{ctrl} #{acl.join(' ')}")
|
cmd ="#{@bin} serve "\
|
||||||
|
"--addr #{ip} "\
|
||||||
|
"--port #{port} "\
|
||||||
|
"--file #{file} "\
|
||||||
|
"--sock #{ctrl} "\
|
||||||
|
"#{acl.join(' ')}"
|
||||||
|
exec(cmd)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -25,14 +31,22 @@ class FlexNBD
|
|||||||
end
|
end
|
||||||
|
|
||||||
def read(offset, length)
|
def read(offset, length)
|
||||||
IO.popen("#{@bin} read #{ip} #{port} #{offset} #{length}","r") do |fh|
|
IO.popen("#{@bin} read "\
|
||||||
|
"--addr #{ip} "\
|
||||||
|
"--port #{port} "\
|
||||||
|
"--from #{offset} "\
|
||||||
|
"--size #{length}","r") do |fh|
|
||||||
return fh.read
|
return fh.read
|
||||||
end
|
end
|
||||||
raise "read failed" unless $?.success?
|
raise "read failed" unless $?.success?
|
||||||
end
|
end
|
||||||
|
|
||||||
def write(offset, data)
|
def write(offset, data)
|
||||||
IO.popen("#{@bin} write #{ip} #{port} #{offset} #{data.length}","w") do |fh|
|
IO.popen("#{@bin} write "\
|
||||||
|
"--addr #{ip} "\
|
||||||
|
"--port #{port} "\
|
||||||
|
"--from #{offset} "\
|
||||||
|
"--size #{data.length}","w") do |fh|
|
||||||
fh.write(data)
|
fh.write(data)
|
||||||
end
|
end
|
||||||
raise "write failed" unless $?.success?
|
raise "write failed" unless $?.success?
|
||||||
|
Reference in New Issue
Block a user