From ed616f8c26b0bc289d23dfae43be867b73ceeac4 Mon Sep 17 00:00:00 2001 From: David Scott Date: Sun, 15 May 2016 16:05:18 +0100 Subject: [PATCH 1/8] 9pmount-vsock: add initial skeleton Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 214 ++++++++++++++++++ alpine/packages/9pmount-vsock/Dockerfile | 10 + alpine/packages/9pmount-vsock/Makefile | 18 ++ alpine/packages/9pmount-vsock/compat.h | 118 ++++++++++ 4 files changed, 360 insertions(+) create mode 100644 alpine/packages/9pmount-vsock/9pmount-vsock.c create mode 100644 alpine/packages/9pmount-vsock/Dockerfile create mode 100644 alpine/packages/9pmount-vsock/Makefile create mode 100644 alpine/packages/9pmount-vsock/compat.h diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c new file mode 100644 index 000000000..a4aa41b33 --- /dev/null +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -0,0 +1,214 @@ +/* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" + +int listen_flag = 0; +int connect_flag = 0; + +char *default_sid = "C378280D-DA14-42C8-A24E-0DE92A1028E2"; + +/* Helper macros for parsing/printing GUIDs */ +#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define GUID_ARGS(_g) \ + (_g).Data1, (_g).Data2, (_g).Data3, \ + (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ + (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] +#define GUID_SARGS(_g) \ + &(_g).Data1, &(_g).Data2, &(_g).Data3, \ + &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ + &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] + + +int parseguid(const char *s, GUID *g) +{ + int res; + int p0, p1, p2, p3, p4, p5, p6, p7; + + res = sscanf(s, GUID_FMT, + &g->Data1, &g->Data2, &g->Data3, + &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); + if (res != 11) + return 1; + g->Data4[0] = p0; + g->Data4[1] = p1; + g->Data4[2] = p2; + g->Data4[3] = p3; + g->Data4[4] = p4; + g->Data4[5] = p5; + g->Data4[6] = p6; + g->Data4[7] = p7; + return 0; +} + +void sockerr(const char *msg) +{ + syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); +} + +static void handle(SOCKET fd) +{ +} + +static int create_listening_socket(GUID serviceid) { + SOCKET lsock = INVALID_SOCKET; + SOCKADDR_HV sa; + int res; + + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == INVALID_SOCKET) { + sockerr("socket()"); + exit(1); + } + + sa.Family = AF_HYPERV; + sa.Reserved = 0; + sa.VmId = HV_GUID_WILDCARD; + sa.ServiceId = serviceid; + + res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == SOCKET_ERROR) { + sockerr("bind()"); + closesocket(lsock); + exit(1); + } + + res = listen(lsock, SOMAXCONN); + if (res == SOCKET_ERROR) { + sockerr("listen()"); + closesocket(lsock); + exit(1); + } + return lsock; +} + +static int connect_socket(GUID serviceid) { + SOCKET sock = INVALID_SOCKET; + SOCKADDR_HV sa; + int res; + + sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (sock == INVALID_SOCKET) { + sockerr("socket()"); + exit(1); + } + + sa.Family = AF_HYPERV; + sa.Reserved = 0; + sa.VmId = HV_GUID_PARENT; + sa.ServiceId = serviceid; + + res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == SOCKET_ERROR) { + sockerr("connect()"); + closesocket(sock); + exit(1); + } + + return sock; +} + +static int accept_socket(SOCKET lsock) { + SOCKET csock = INVALID_SOCKET; + SOCKADDR_HV sac; + socklen_t socklen = sizeof(sac); + + csock = accept(lsock, (struct sockaddr *)&sac, &socklen); + if (csock == INVALID_SOCKET) { + sockerr("accept()"); + closesocket(lsock); + exit(1); + } + + printf("Connect from: "GUID_FMT":"GUID_FMT"\n", + GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); + return csock; +} + +void usage(char *name) +{ + printf("%s usage:\n", name); + printf("\t[--serviceid ] [--listen | --connect]\n\n"); + printf("where\n"); + printf("\t--serviceid : use as the well-known service GUID\n"); + printf("\t (defaults to %s)\n", default_sid); + printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n"); + printf("\t--connect: connect to the parent partition\n"); +} + +int __cdecl main(int argc, char **argv) +{ + int res = 0; + GUID sid; + int c; + /* Defaults to a testing GUID */ + char *serviceid = default_sid; + + opterr = 0; + while (1) { + static struct option long_options[] = { + /* These options set a flag. */ + {"serviceid", required_argument, NULL, 's'}, + {"listen", no_argument, &listen_flag, 1}, + {"connect", no_argument, &connect_flag, 1}, + {0, 0, 0, 0} + }; + int option_index = 0; + + c = getopt_long (argc, argv, "s:", long_options, &option_index); + if (c == -1) break; + + switch (c) { + + case 's': + serviceid = optarg; + break; + case 0: + break; + default: + usage (argv[0]); + exit (1); + } + } + if ((listen_flag && connect_flag) || !(listen_flag || connect_flag)){ + fprintf(stderr, "Please supply either the --listen or --connect flag, but not both.\n"); + exit(1); + } + + int log_flags = LOG_CONS | LOG_NDELAY | LOG_PERROR; + + openlog(argv[0], log_flags, LOG_DAEMON); + + res = parseguid(serviceid, &sid); + if (res) { + syslog(LOG_CRIT, "Failed to parse serviceid as GUID: %s", serviceid); + usage(argv[0]); + exit(1); + } + + SOCKET sock = INVALID_SOCKET; + if (listen_flag) { + syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); + SOCKET lsocket = create_listening_socket(sid); + sock = accept_socket(lsocket); + } else { + syslog(LOG_INFO, "starting in connect mode with serviceid=%s", serviceid); + sock = connect_socket(sid); + } + + handle(sock); + exit(0); +} diff --git a/alpine/packages/9pmount-vsock/Dockerfile b/alpine/packages/9pmount-vsock/Dockerfile new file mode 100644 index 000000000..b0f9a6212 --- /dev/null +++ b/alpine/packages/9pmount-vsock/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:3.3 + +RUN apk update && apk upgrade && apk add alpine-sdk util-linux-dev linux-headers + +RUN mkdir -p /9pmount-vsock +WORKDIR /9pmount-vsock + +COPY . /9pmount-vsock + +RUN make 9pmount-vsock diff --git a/alpine/packages/9pmount-vsock/Makefile b/alpine/packages/9pmount-vsock/Makefile new file mode 100644 index 000000000..9129165a1 --- /dev/null +++ b/alpine/packages/9pmount-vsock/Makefile @@ -0,0 +1,18 @@ +.PHONY: all + +DEPS=9pmount-vsock.c compat.h + +all: Dockerfile $(DEPS) + docker build -t 9pmount-vsock:build . + docker run --rm 9pmount-vsock:build cat 9pmount-vsock > 9pmount-vsock + chmod 755 9pmount-vsock + +9pmount-vsock: 9pmount-vsock.o + gcc -Wall -Werror -o 9pmount-vsock 9pmount-vsock.o -lpthread + +9pmount-vsock.o: 9pmount-vsock.c compat.h + gcc -Wall -Werror -c 9pmount-vsock.c + +clean: + rm -f 9pmount-vsock + docker images -q 9pmount-vsock:build | xargs docker rmi -f diff --git a/alpine/packages/9pmount-vsock/compat.h b/alpine/packages/9pmount-vsock/compat.h new file mode 100644 index 000000000..02f9f7b84 --- /dev/null +++ b/alpine/packages/9pmount-vsock/compat.h @@ -0,0 +1,118 @@ +/* + * Compatibility layer between Windows and Linux + */ +#ifdef _MSC_VER +#undef UNICODE +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include + +#pragma comment (lib, "Ws2_32.lib") +#pragma comment (lib, "Mswsock.lib") +#pragma comment (lib, "AdvApi32.lib") + +#else +#include +#include +#include +#include +#endif /* !_MSC_VER */ + +#ifdef _MSC_VER +typedef int socklen_t; +#endif + +#ifndef _MSC_VER +/* Compat layer for Linux/Unix */ +typedef int SOCKET; + +#ifndef SOCKET_ERROR +#define SOCKET_ERROR -1 +#endif + +#ifndef INVALID_SOCKET +#define INVALID_SOCKET -1 +#endif + +#define closesocket(_fd) close(_fd) + +/* Shutdown flags are different too */ +#define SD_SEND SHUT_WR +#define SD_RECEIVE SHUT_RD +#define SD_BOTH SHUT_RDWR + +#define __cdecl + +/* GUID handling */ +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; + +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} + + +/* HV Socket definitions */ +#define AF_HYPERV 43 +#define HV_PROTOCOL_RAW 1 + +typedef struct _SOCKADDR_HV +{ + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; +} SOCKADDR_HV; + +DEFINE_GUID(HV_GUID_ZERO, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +DEFINE_GUID(HV_GUID_BROADCAST, + 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); +DEFINE_GUID(HV_GUID_WILDCARD, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + +DEFINE_GUID(HV_GUID_CHILDREN, + 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); +DEFINE_GUID(HV_GUID_LOOPBACK, + 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); +DEFINE_GUID(HV_GUID_PARENT, + 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); + +#endif + +/* Thread wrappers */ +#ifdef _MSC_VER +typedef HANDLE THREAD_HANDLE; + +static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) +{ + *t = CreateThread(NULL, 0, f, arg, 0, NULL); + return 0; +} + +static inline int thread_join(THREAD_HANDLE t) +{ + WaitForSingleObject(t, INFINITE); + return 0; +} + +#else +#include + +typedef pthread_t THREAD_HANDLE; + +static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) +{ + return pthread_create(t, NULL, f, arg); +} + +static inline int thread_join(THREAD_HANDLE t) +{ + return pthread_join(t, NULL); +} +#endif From 36d09be949bdc6d4e5927f06fffc729901d4861d Mon Sep 17 00:00:00 2001 From: David Scott Date: Sun, 15 May 2016 16:29:17 +0100 Subject: [PATCH 2/8] 9pmount-vsock: make a connection then execv /bin/mount The magic options are -o trans=fd,rfdno=,wfdno= Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index a4aa41b33..9f54992ea 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -16,10 +16,14 @@ #include "compat.h" -int listen_flag = 0; -int connect_flag = 0; +#define NONE 0 +#define LISTEN 1 +#define CONNECT 2 + +int mode = NONE; char *default_sid = "C378280D-DA14-42C8-A24E-0DE92A1028E2"; +char *mount = "/bin/mount"; /* Helper macros for parsing/printing GUIDs */ #define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" @@ -61,6 +65,20 @@ void sockerr(const char *msg) static void handle(SOCKET fd) { + char *options = NULL; + if (asprintf(&options, "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,rfdno=%d,wfdno=%d", fd, fd) < 0){ + syslog(LOG_CRIT, "asprintf(): %s", strerror(errno)); + exit(1); + } + char *argv[] = { + mount, + "-t", "9p", "-o", options, + "db", "/Database", + NULL + }; + execv(mount, argv); + syslog(LOG_CRIT, "failed to execute %s: %s", mount, strerror(errno)); + exit(1); } static int create_listening_socket(GUID serviceid) { @@ -141,7 +159,7 @@ static int accept_socket(SOCKET lsock) { void usage(char *name) { printf("%s usage:\n", name); - printf("\t[--serviceid ] [--listen | --connect]\n\n"); + printf("\t[--serviceid ] \n"); printf("where\n"); printf("\t--serviceid : use as the well-known service GUID\n"); printf("\t (defaults to %s)\n", default_sid); @@ -162,8 +180,6 @@ int __cdecl main(int argc, char **argv) static struct option long_options[] = { /* These options set a flag. */ {"serviceid", required_argument, NULL, 's'}, - {"listen", no_argument, &listen_flag, 1}, - {"connect", no_argument, &connect_flag, 1}, {0, 0, 0, 0} }; int option_index = 0; @@ -183,14 +199,20 @@ int __cdecl main(int argc, char **argv) exit (1); } } - if ((listen_flag && connect_flag) || !(listen_flag || connect_flag)){ - fprintf(stderr, "Please supply either the --listen or --connect flag, but not both.\n"); + if (optind < argc) { + if (strcmp(argv[optind], "listen") == 0) { + mode = LISTEN; + } else if (strcmp(argv[optind], "connect") == 0) { + mode = CONNECT; + } + optind++; + } + if (mode == NONE) { + fprintf(stderr, "Please supply either listen or connect\n"); + usage(argv[0]); exit(1); } - - int log_flags = LOG_CONS | LOG_NDELAY | LOG_PERROR; - - openlog(argv[0], log_flags, LOG_DAEMON); + openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); res = parseguid(serviceid, &sid); if (res) { @@ -200,7 +222,7 @@ int __cdecl main(int argc, char **argv) } SOCKET sock = INVALID_SOCKET; - if (listen_flag) { + if (mode == LISTEN) { syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); SOCKET lsocket = create_listening_socket(sid); sock = accept_socket(lsocket); From a772c2b7d61baef534d527a3b000fad14a4ba323 Mon Sep 17 00:00:00 2001 From: David Scott Date: Sun, 15 May 2016 17:36:19 +0100 Subject: [PATCH 3/8] 9pmount-vsock: only try to accept 1 connection The database has a reconnect loop, and we don't particularly want to accept more than one of its connections per mount. Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index 9f54992ea..395dcc92a 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -104,7 +104,7 @@ static int create_listening_socket(GUID serviceid) { exit(1); } - res = listen(lsock, SOMAXCONN); + res = listen(lsock, 1); if (res == SOCKET_ERROR) { sockerr("listen()"); closesocket(lsock); @@ -226,6 +226,7 @@ int __cdecl main(int argc, char **argv) syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); SOCKET lsocket = create_listening_socket(sid); sock = accept_socket(lsocket); + close(lsocket); } else { syslog(LOG_INFO, "starting in connect mode with serviceid=%s", serviceid); sock = connect_socket(sid); From 672d611c8fc29020450e37894386163a38e06697 Mon Sep 17 00:00:00 2001 From: David Scott Date: Sun, 15 May 2016 18:38:20 +0100 Subject: [PATCH 4/8] 9pmount-vsock: remove Win32 compatibility code There's no point having an ability to compile this code on Windows, so simplify it. Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 96 ++++---------- alpine/packages/9pmount-vsock/Makefile | 11 +- alpine/packages/9pmount-vsock/compat.h | 118 ------------------ alpine/packages/9pmount-vsock/hvsock.c | 38 ++++++ alpine/packages/9pmount-vsock/hvsock.h | 49 ++++++++ 5 files changed, 120 insertions(+), 192 deletions(-) delete mode 100644 alpine/packages/9pmount-vsock/compat.h create mode 100644 alpine/packages/9pmount-vsock/hvsock.c create mode 100644 alpine/packages/9pmount-vsock/hvsock.h diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index 395dcc92a..81a37dc04 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -14,7 +14,7 @@ #include #include -#include "compat.h" +#include "hvsock.h" #define NONE 0 #define LISTEN 1 @@ -25,50 +25,17 @@ int mode = NONE; char *default_sid = "C378280D-DA14-42C8-A24E-0DE92A1028E2"; char *mount = "/bin/mount"; -/* Helper macros for parsing/printing GUIDs */ -#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" -#define GUID_ARGS(_g) \ - (_g).Data1, (_g).Data2, (_g).Data3, \ - (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ - (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] -#define GUID_SARGS(_g) \ - &(_g).Data1, &(_g).Data2, &(_g).Data3, \ - &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ - &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] - - -int parseguid(const char *s, GUID *g) -{ - int res; - int p0, p1, p2, p3, p4, p5, p6, p7; - - res = sscanf(s, GUID_FMT, - &g->Data1, &g->Data2, &g->Data3, - &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); - if (res != 11) - return 1; - g->Data4[0] = p0; - g->Data4[1] = p1; - g->Data4[2] = p2; - g->Data4[3] = p3; - g->Data4[4] = p4; - g->Data4[5] = p5; - g->Data4[6] = p6; - g->Data4[7] = p7; - return 0; -} - -void sockerr(const char *msg) +void fatal(const char *msg) { syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); + exit(1); } -static void handle(SOCKET fd) +static void handle(int fd) { char *options = NULL; if (asprintf(&options, "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,rfdno=%d,wfdno=%d", fd, fd) < 0){ - syslog(LOG_CRIT, "asprintf(): %s", strerror(errno)); - exit(1); + fatal("asprintf()"); } char *argv[] = { mount, @@ -77,19 +44,17 @@ static void handle(SOCKET fd) NULL }; execv(mount, argv); - syslog(LOG_CRIT, "failed to execute %s: %s", mount, strerror(errno)); - exit(1); + fatal("execv()"); } static int create_listening_socket(GUID serviceid) { - SOCKET lsock = INVALID_SOCKET; + int lsock = -1; SOCKADDR_HV sa; int res; lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (lsock == INVALID_SOCKET) { - sockerr("socket()"); - exit(1); + if (lsock == -1) { + fatal("socket()"); } sa.Family = AF_HYPERV; @@ -98,30 +63,25 @@ static int create_listening_socket(GUID serviceid) { sa.ServiceId = serviceid; res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa)); - if (res == SOCKET_ERROR) { - sockerr("bind()"); - closesocket(lsock); - exit(1); + if (res == -1) { + fatal("bind()"); } res = listen(lsock, 1); - if (res == SOCKET_ERROR) { - sockerr("listen()"); - closesocket(lsock); - exit(1); + if (res == -1) { + fatal("listen()"); } return lsock; } static int connect_socket(GUID serviceid) { - SOCKET sock = INVALID_SOCKET; + int sock = -1; SOCKADDR_HV sa; int res; sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (sock == INVALID_SOCKET) { - sockerr("socket()"); - exit(1); + if (sock == -1) { + fatal("socket()"); } sa.Family = AF_HYPERV; @@ -130,28 +90,24 @@ static int connect_socket(GUID serviceid) { sa.ServiceId = serviceid; res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa)); - if (res == SOCKET_ERROR) { - sockerr("connect()"); - closesocket(sock); - exit(1); + if (res == -1) { + fatal("connect()"); } return sock; } -static int accept_socket(SOCKET lsock) { - SOCKET csock = INVALID_SOCKET; +static int accept_socket(int lsock) { + int csock = -1; SOCKADDR_HV sac; socklen_t socklen = sizeof(sac); csock = accept(lsock, (struct sockaddr *)&sac, &socklen); - if (csock == INVALID_SOCKET) { - sockerr("accept()"); - closesocket(lsock); - exit(1); + if (csock == -1) { + fatal("accept()"); } - printf("Connect from: "GUID_FMT":"GUID_FMT"\n", + syslog(LOG_INFO, "Connect from: "GUID_FMT":"GUID_FMT"\n", GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); return csock; } @@ -167,7 +123,7 @@ void usage(char *name) printf("\t--connect: connect to the parent partition\n"); } -int __cdecl main(int argc, char **argv) +int main(int argc, char **argv) { int res = 0; GUID sid; @@ -221,10 +177,10 @@ int __cdecl main(int argc, char **argv) exit(1); } - SOCKET sock = INVALID_SOCKET; + int sock = -1; if (mode == LISTEN) { syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); - SOCKET lsocket = create_listening_socket(sid); + int lsocket = create_listening_socket(sid); sock = accept_socket(lsocket); close(lsocket); } else { diff --git a/alpine/packages/9pmount-vsock/Makefile b/alpine/packages/9pmount-vsock/Makefile index 9129165a1..a01524bc0 100644 --- a/alpine/packages/9pmount-vsock/Makefile +++ b/alpine/packages/9pmount-vsock/Makefile @@ -1,18 +1,21 @@ .PHONY: all -DEPS=9pmount-vsock.c compat.h +DEPS=9pmount-vsock.c hvsock.c hvsock.h all: Dockerfile $(DEPS) docker build -t 9pmount-vsock:build . docker run --rm 9pmount-vsock:build cat 9pmount-vsock > 9pmount-vsock chmod 755 9pmount-vsock -9pmount-vsock: 9pmount-vsock.o - gcc -Wall -Werror -o 9pmount-vsock 9pmount-vsock.o -lpthread +9pmount-vsock: 9pmount-vsock.o hvsock.o + gcc -Wall -Werror -o 9pmount-vsock 9pmount-vsock.o hvsock.o -lpthread -9pmount-vsock.o: 9pmount-vsock.c compat.h +9pmount-vsock.o: 9pmount-vsock.c hvsock.h gcc -Wall -Werror -c 9pmount-vsock.c +hvsock.o: hvsock.c hvsock.h + gcc -Wall -Werror -c hvsock.c + clean: rm -f 9pmount-vsock docker images -q 9pmount-vsock:build | xargs docker rmi -f diff --git a/alpine/packages/9pmount-vsock/compat.h b/alpine/packages/9pmount-vsock/compat.h deleted file mode 100644 index 02f9f7b84..000000000 --- a/alpine/packages/9pmount-vsock/compat.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Compatibility layer between Windows and Linux - */ -#ifdef _MSC_VER -#undef UNICODE -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -#pragma comment (lib, "Ws2_32.lib") -#pragma comment (lib, "Mswsock.lib") -#pragma comment (lib, "AdvApi32.lib") - -#else -#include -#include -#include -#include -#endif /* !_MSC_VER */ - -#ifdef _MSC_VER -typedef int socklen_t; -#endif - -#ifndef _MSC_VER -/* Compat layer for Linux/Unix */ -typedef int SOCKET; - -#ifndef SOCKET_ERROR -#define SOCKET_ERROR -1 -#endif - -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif - -#define closesocket(_fd) close(_fd) - -/* Shutdown flags are different too */ -#define SD_SEND SHUT_WR -#define SD_RECEIVE SHUT_RD -#define SD_BOTH SHUT_RDWR - -#define __cdecl - -/* GUID handling */ -typedef struct _GUID { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -} GUID; - -#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} - - -/* HV Socket definitions */ -#define AF_HYPERV 43 -#define HV_PROTOCOL_RAW 1 - -typedef struct _SOCKADDR_HV -{ - unsigned short Family; - unsigned short Reserved; - GUID VmId; - GUID ServiceId; -} SOCKADDR_HV; - -DEFINE_GUID(HV_GUID_ZERO, - 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); -DEFINE_GUID(HV_GUID_BROADCAST, - 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); -DEFINE_GUID(HV_GUID_WILDCARD, - 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - -DEFINE_GUID(HV_GUID_CHILDREN, - 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); -DEFINE_GUID(HV_GUID_LOOPBACK, - 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); -DEFINE_GUID(HV_GUID_PARENT, - 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); - -#endif - -/* Thread wrappers */ -#ifdef _MSC_VER -typedef HANDLE THREAD_HANDLE; - -static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) -{ - *t = CreateThread(NULL, 0, f, arg, 0, NULL); - return 0; -} - -static inline int thread_join(THREAD_HANDLE t) -{ - WaitForSingleObject(t, INFINITE); - return 0; -} - -#else -#include - -typedef pthread_t THREAD_HANDLE; - -static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) -{ - return pthread_create(t, NULL, f, arg); -} - -static inline int thread_join(THREAD_HANDLE t) -{ - return pthread_join(t, NULL); -} -#endif diff --git a/alpine/packages/9pmount-vsock/hvsock.c b/alpine/packages/9pmount-vsock/hvsock.c new file mode 100644 index 000000000..47c924d63 --- /dev/null +++ b/alpine/packages/9pmount-vsock/hvsock.c @@ -0,0 +1,38 @@ +#include + +#include "hvsock.h" + +int parseguid(const char *s, GUID *g) +{ + int res; + int p0, p1, p2, p3, p4, p5, p6, p7; + + res = sscanf(s, GUID_FMT, + &g->Data1, &g->Data2, &g->Data3, + &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); + if (res != 11) + return 1; + g->Data4[0] = p0; + g->Data4[1] = p1; + g->Data4[2] = p2; + g->Data4[3] = p3; + g->Data4[4] = p4; + g->Data4[5] = p5; + g->Data4[6] = p6; + g->Data4[7] = p7; + return 0; +} + +DEFINE_GUID(HV_GUID_ZERO, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +DEFINE_GUID(HV_GUID_BROADCAST, + 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); +DEFINE_GUID(HV_GUID_WILDCARD, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + +DEFINE_GUID(HV_GUID_CHILDREN, + 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); +DEFINE_GUID(HV_GUID_LOOPBACK, + 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); +DEFINE_GUID(HV_GUID_PARENT, + 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); diff --git a/alpine/packages/9pmount-vsock/hvsock.h b/alpine/packages/9pmount-vsock/hvsock.h new file mode 100644 index 000000000..6e1ca6695 --- /dev/null +++ b/alpine/packages/9pmount-vsock/hvsock.h @@ -0,0 +1,49 @@ +/* AF_HYPERV definitions and utilities */ + +#include +#include +#include +#include + +/* GUID handling */ +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; + +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} + +/* Helper macros for parsing/printing GUIDs */ +#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define GUID_ARGS(_g) \ + (_g).Data1, (_g).Data2, (_g).Data3, \ + (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ + (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] +#define GUID_SARGS(_g) \ + &(_g).Data1, &(_g).Data2, &(_g).Data3, \ + &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ + &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] + +extern int parseguid(const char *s, GUID *g); + +/* HV Socket definitions */ +#define AF_HYPERV 43 +#define HV_PROTOCOL_RAW 1 + +typedef struct _SOCKADDR_HV +{ + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; +} SOCKADDR_HV; + +extern const GUID HV_GUID_ZERO; +extern const GUID HV_GUID_BROADCAST; +extern const GUID HV_GUID_WILDCARD; +extern const GUID HV_GUID_CHILDREN; +extern const GUID HV_GUID_LOOPBACK; +extern const GUID HV_GUID_PARENT; From a295aec7854dab53dac9ce9e621a67c4e8c45dde Mon Sep 17 00:00:00 2001 From: David Scott Date: Sat, 21 May 2016 11:55:30 +0100 Subject: [PATCH 5/8] 9pmount-vsock: require and arguments for the 9P mount The program can now be used to mount more filesystems than the database one. Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index 81a37dc04..98772c2fe 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -31,7 +31,7 @@ void fatal(const char *msg) exit(1); } -static void handle(int fd) +static void handle(int fd, char *tag, char *path) { char *options = NULL; if (asprintf(&options, "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,rfdno=%d,wfdno=%d", fd, fd) < 0){ @@ -40,7 +40,7 @@ static void handle(int fd) char *argv[] = { mount, "-t", "9p", "-o", options, - "db", "/Database", + tag, path, NULL }; execv(mount, argv); @@ -114,8 +114,9 @@ static int accept_socket(int lsock) { void usage(char *name) { - printf("%s usage:\n", name); - printf("\t[--serviceid ] \n"); + printf("%s: mount a 9P filesystem from an hvsock connection\n", name); + printf("usage:\n"); + printf("\t[--serviceid ] \n"); printf("where\n"); printf("\t--serviceid : use as the well-known service GUID\n"); printf("\t (defaults to %s)\n", default_sid); @@ -130,6 +131,8 @@ int main(int argc, char **argv) int c; /* Defaults to a testing GUID */ char *serviceid = default_sid; + char *tag = NULL; + char *path = NULL; opterr = 0; while (1) { @@ -168,15 +171,30 @@ int main(int argc, char **argv) usage(argv[0]); exit(1); } - openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); - + if (optind < argc) { + tag = argv[optind++]; + } + if (optind < argc) { + path = argv[optind++]; + } + if (!tag) { + fprintf(stderr, "Please supply a tag name\n"); + usage(argv[0]); + exit(1); + } + if (!path) { + fprintf(stderr, "Please supply a path\n"); + usage(argv[0]); + exit(1); + } res = parseguid(serviceid, &sid); if (res) { - syslog(LOG_CRIT, "Failed to parse serviceid as GUID: %s", serviceid); + fprintf(stderr, "Failed to parse serviceid as GUID: %s\n", serviceid); usage(argv[0]); exit(1); } + openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); int sock = -1; if (mode == LISTEN) { syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); @@ -188,6 +206,6 @@ int main(int argc, char **argv) sock = connect_socket(sid); } - handle(sock); + handle(sock, tag, path); exit(0); } From 2f3b1cce021976a73ae065c3c9e8feefa5be44ff Mon Sep 17 00:00:00 2001 From: David Scott Date: Sat, 21 May 2016 12:09:54 +0100 Subject: [PATCH 6/8] 9pmount-vsock: retry the mount if it fails The client on the host may time-out the connection attempt after we have accepted it. If the mount fails, sleep for 1s and try again. Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/9pmount-vsock.c | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index 98772c2fe..dd0d9219d 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "hvsock.h" @@ -31,7 +32,7 @@ void fatal(const char *msg) exit(1); } -static void handle(int fd, char *tag, char *path) +static int handle(int fd, char *tag, char *path) { char *options = NULL; if (asprintf(&options, "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,rfdno=%d,wfdno=%d", fd, fd) < 0){ @@ -43,8 +44,17 @@ static void handle(int fd, char *tag, char *path) tag, path, NULL }; - execv(mount, argv); - fatal("execv()"); + pid_t pid = fork(); + if (pid == 0) { + execv(mount, argv); + fatal("execv()"); + } + int status; + if (waitpid(pid, &status, 0) == -1) { + syslog(LOG_CRIT, "waitpid failed: %d. %s", errno, strerror(errno)); + exit(1); + } + return WEXITSTATUS(status); } static int create_listening_socket(GUID serviceid) { @@ -195,17 +205,25 @@ int main(int argc, char **argv) } openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); - int sock = -1; - if (mode == LISTEN) { - syslog(LOG_INFO, "starting in listening mode with serviceid=%s", serviceid); - int lsocket = create_listening_socket(sid); - sock = accept_socket(lsocket); - close(lsocket); - } else { - syslog(LOG_INFO, "starting in connect mode with serviceid=%s", serviceid); - sock = connect_socket(sid); + for (;;) { + int sock = -1; + if (mode == LISTEN) { + syslog(LOG_INFO, "starting in listening mode with serviceid=%s, tag=%s, path=%s", serviceid, tag, path); + int lsocket = create_listening_socket(sid); + sock = accept_socket(lsocket); + close(lsocket); + } else { + syslog(LOG_INFO, "starting in connect mode with serviceid=%s, tag=%s, path=%s", serviceid, tag, path); + sock = connect_socket(sid); + } + int r = handle(sock, tag, path); + close(sock); + if (r == 0) { + syslog(LOG_INFO, "mount successful for serviceid=%s tag=%s path=%s", serviceid, tag, path); + exit(0); + } + /* This can happen if the client times out the connection after we accept it */ + syslog(LOG_CRIT, "mount failed with %d for serviceid=%s tag=%s path=%s", r, serviceid, tag, path); + sleep(1); /* retry */ } - - handle(sock, tag, path); - exit(0); } From af556bdc2322cb66c50923b275557fca161b380d Mon Sep 17 00:00:00 2001 From: David Scott Date: Sun, 15 May 2016 18:17:55 +0100 Subject: [PATCH 7/8] 9pmount-vsock: add to /sbin This patch adds the binary to /sbin but does not hook it up. Signed-off-by: David Scott --- alpine/Dockerfile | 1 + alpine/packages/Makefile | 2 ++ 2 files changed, 3 insertions(+) diff --git a/alpine/Dockerfile b/alpine/Dockerfile index ed52e428a..962c82b8c 100644 --- a/alpine/Dockerfile +++ b/alpine/Dockerfile @@ -72,6 +72,7 @@ COPY packages/vsudd/etc /etc COPY packages/mobyconfig/mobyconfig /usr/bin COPY packages/gummiboot/gummiboot.tar.gz /usr/share/src/ COPY packages/oom/etc /etc +COPY packages/9pmount-vsock/9pmount-vsock /sbin RUN \ rc-update add swap boot && \ diff --git a/alpine/packages/Makefile b/alpine/packages/Makefile index 1b9aaffe3..dc5f13a00 100644 --- a/alpine/packages/Makefile +++ b/alpine/packages/Makefile @@ -9,6 +9,7 @@ all: $(MAKE) -C vsudd OS=linux $(MAKE) -C llmnrd OS=linux $(MAKE) -C gummiboot OS=linux + $(MAKE) -C 9pmount-vsock OS=linux arm: $(MAKE) -C transfused OS=linux ARCH=arm @@ -31,3 +32,4 @@ clean: $(MAKE) -C vsudd clean $(MAKE) -C llmnrd clean $(MAKE) -C gummiboot clean + $(MAKE) -C 9pmount-vsock clean From 537efa03be171291453383981b5134bb7743b501 Mon Sep 17 00:00:00 2001 From: David Scott Date: Sat, 21 May 2016 21:42:52 +0100 Subject: [PATCH 8/8] 9pmount-vsock: add .gitignore Signed-off-by: David Scott --- alpine/packages/9pmount-vsock/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 alpine/packages/9pmount-vsock/.gitignore diff --git a/alpine/packages/9pmount-vsock/.gitignore b/alpine/packages/9pmount-vsock/.gitignore new file mode 100644 index 000000000..96331e6d1 --- /dev/null +++ b/alpine/packages/9pmount-vsock/.gitignore @@ -0,0 +1 @@ +9pmount-vsock