run qemu-nbd as an inetd service has some benefits * more scriptable, such as serve multiple images to different clients on one ip/port * access control using tcpd
simple usage: #!/bin/sh # qemu-nbd wrapper, select image file according to client ip address IMG_FILE=`sed -n "s/$REMOTE_HOST //p" /path/to/image_list.txt` qemu-nbd -i 10 $IMG_FILE 10<&0- 1>/tmp/log 2>/tmp/log2 #end #xinetd.conf service nbd { flags = REUSE socket_type = stream wait = no user = some_user server = /path/to/qemu-nbd-wrapper.sh log_on_failure += USERID disable = no } Signed-off-by: Jun Sheng <chaoseter...@gmail.com> --- qemu-nbd.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 5cd6c6d..f4af4c7 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -49,6 +49,7 @@ static NBDExport *exp; static int verbose; static char *srcpath; static char *sockpath; +static int inetd_fd = -1; static int persistent = 0; static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state; static int shared = 1; @@ -66,6 +67,7 @@ static void usage(const char *name) "Connection properties:\n" " -p, --port=PORT port to listen on (default `%d')\n" " -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n" +" -i, --inetd=FD run as an inetd services on FD\n" " -k, --socket=PATH path to the unix socket\n" " (default '"SOCKET_PATH"')\n" " -e, --shared=NUM device can be shared by NUM clients (default '1')\n" @@ -363,7 +365,13 @@ static void nbd_accept(void *opaque) struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); - int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + int fd; + if (inetd_fd < 0) { + fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + } else { + fd = server_fd; + } + if (fd < 0) { perror("accept"); return; @@ -396,10 +404,11 @@ int main(int argc, char **argv) off_t fd_size; QemuOpts *sn_opts = NULL; const char *sn_id_or_name = NULL; - const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:"; + const char *sopt = "hVi:b:o:p:rsnP:c:dvk:e:f:tl:"; struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, + { "inetd", 1, NULL, 'i'}, { "bind", 1, NULL, 'b' }, { "port", 1, NULL, 'p' }, { "socket", 1, NULL, 'k' }, @@ -508,6 +517,16 @@ int main(int argc, char **argv) "without setting discard operation to unmap"); } break; + case 'i': + inetd_fd = qemu_parse_fd(optarg); + if (inetd_fd < 0) { + errx(EXIT_FAILURE, "Invalid inet fd `%s'", optarg); + } + if (inetd_fd <= STDERR_FILENO) { + errx(EXIT_FAILURE, "Inet fd out of range `%s'," + " should be in [3, 65535]", optarg); + } + break; case 'b': bindto = optarg; break; @@ -732,10 +751,14 @@ int main(int argc, char **argv) exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed); - if (sockpath) { - fd = unix_socket_incoming(sockpath); + if (inetd_fd < 0) { + if (sockpath) { + fd = unix_socket_incoming(sockpath); + } else { + fd = tcp_socket_incoming(bindto, port); + } } else { - fd = tcp_socket_incoming(bindto, port); + fd = inetd_fd; } if (fd < 0) { @@ -754,9 +777,12 @@ int main(int argc, char **argv) /* Shut up GCC warnings. */ memset(&client_thread, 0, sizeof(client_thread)); } - - qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, - (void *)(uintptr_t)fd); + if (inetd_fd < 0) { + qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, + (void *)(uintptr_t)fd); + } else { + nbd_accept((void *)(uintptr_t)fd); + } /* now when the initialization is (almost) complete, chdir("/") * to free any busy filesystems */ -- 2.1.2