diff --git a/alpine/packages/9pmount-vsock/9pmount-vsock.c b/alpine/packages/9pmount-vsock/9pmount-vsock.c index 72856641a..4ecebb24a 100644 --- a/alpine/packages/9pmount-vsock/9pmount-vsock.c +++ b/alpine/packages/9pmount-vsock/9pmount-vsock.c @@ -1,6 +1,3 @@ -/* - */ - #include #include #include @@ -28,202 +25,224 @@ char *mount = "/bin/mount"; void fatal(const char *msg) { - syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); - exit(1); + syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); + exit(1); } static int handle(int fd, char *tag, char *path) { - char *options = NULL; - if (asprintf(&options, "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,msize=4096,rfdno=%d,wfdno=%d", fd, fd) < 0){ - fatal("asprintf()"); - } - char *argv[] = { - mount, - "-t", "9p", "-o", options, - tag, path, - NULL - }; - 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); + char *options = NULL; + int status; + pid_t pid; + int res; + + res = asprintf(&options, + "trans=fd,dfltuid=1001,dfltgid=50,version=9p2000,msize=4096,rfdno=%d,wfdno=%d", + fd, fd); + if (res < 0) + fatal("asprintf()"); + + char *argv[] = { + mount, + "-t", "9p", "-o", options, + tag, path, + NULL + }; + + pid = fork(); + if (pid == 0) { + execv(mount, argv); + fatal("execv()"); + } + + res = waitpid(pid, &status, 0); + if (res == -1) { + syslog(LOG_CRIT, + "waitpid failed: %d. %s", errno, strerror(errno)); + exit(1); + } + return WEXITSTATUS(status); } -static int create_listening_socket(GUID serviceid) { - int lsock = -1; - SOCKADDR_HV sa; - int res; +static int create_listening_socket(GUID serviceid) +{ + SOCKADDR_HV sa; + int lsock; + int res; - lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (lsock == -1) { - fatal("socket()"); - } + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == -1) + fatal("socket()"); - sa.Family = AF_HYPERV; - sa.Reserved = 0; - sa.VmId = HV_GUID_WILDCARD; - sa.ServiceId = serviceid; + 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 == -1) { - fatal("bind()"); - } + res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == -1) + fatal("bind()"); - res = listen(lsock, 1); - if (res == -1) { - fatal("listen()"); - } - return lsock; + res = listen(lsock, 1); + if (res == -1) + fatal("listen()"); + + return lsock; } -static int connect_socket(GUID serviceid) { - int sock = -1; - SOCKADDR_HV sa; - int res; +static int connect_socket(GUID serviceid) +{ + SOCKADDR_HV sa; + int sock; + int res; - sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (sock == -1) { - fatal("socket()"); - } + sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (sock == -1) + fatal("socket()"); - sa.Family = AF_HYPERV; - sa.Reserved = 0; - sa.VmId = HV_GUID_PARENT; - sa.ServiceId = serviceid; + 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 == -1) { - fatal("connect()"); - } + res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == -1) + fatal("connect()"); - return sock; + return sock; } -static int accept_socket(int lsock) { - int csock = -1; - SOCKADDR_HV sac; - socklen_t socklen = sizeof(sac); +static int accept_socket(int lsock) +{ + SOCKADDR_HV sac; + socklen_t socklen = sizeof(sac); + int csock; - csock = accept(lsock, (struct sockaddr *)&sac, &socklen); - if (csock == -1) { - fatal("accept()"); - } + csock = accept(lsock, (struct sockaddr *)&sac, &socklen); + if (csock == -1) + fatal("accept()"); - syslog(LOG_INFO, "Connect from: "GUID_FMT":"GUID_FMT"\n", - GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); - return csock; + syslog(LOG_INFO, "Connect from: " GUID_FMT ":" GUID_FMT "\n", + GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); + + return csock; } void usage(char *name) { - 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); - printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n"); - printf("\t--connect: connect to the parent partition\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); + printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n"); + printf("\t--connect: connect to the parent partition\n"); } int main(int argc, char **argv) { - int res = 0; - GUID sid; - int c; - /* Defaults to a testing GUID */ - char *serviceid = default_sid; - char *tag = NULL; - char *path = NULL; + int res = 0; + GUID sid; + int c; + /* Defaults to a testing GUID */ + char *serviceid = default_sid; + char *tag = NULL; + char *path = NULL; - opterr = 0; - while (1) { - static struct option long_options[] = { - /* These options set a flag. */ - {"serviceid", required_argument, NULL, 's'}, - {0, 0, 0, 0} - }; - int option_index = 0; + opterr = 0; + while (1) { + static struct option long_options[] = { + /* These options set a flag. */ + {"serviceid", required_argument, NULL, 's'}, + {0, 0, 0, 0} + }; + int option_index = 0; - c = getopt_long (argc, argv, "s:", long_options, &option_index); - if (c == -1) break; + c = getopt_long(argc, argv, "s:", long_options, &option_index); + if (c == -1) + break; - switch (c) { + switch (c) { + case 's': + serviceid = optarg; + break; + case 0: + break; + default: + usage(argv[0]); + exit(1); + } + } - case 's': - serviceid = optarg; - break; - case 0: - break; - default: - usage (argv[0]); - exit (1); - } - } - 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); - } - 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) { - fprintf(stderr, "Failed to parse serviceid as GUID: %s\n", serviceid); - usage(argv[0]); - exit(1); - } + 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); + } - openlog(argv[0], LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); - 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 */ - } + 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) { + 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); + for (;;) { + int lsocket; + int sock; + int r; + + if (mode == LISTEN) { + syslog(LOG_INFO, "starting in listening mode with serviceid=%s, tag=%s, path=%s", serviceid, tag, path); + 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); + } + + 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 */ + } } diff --git a/alpine/packages/9pmount-vsock/hvsock.c b/alpine/packages/9pmount-vsock/hvsock.c index 47c924d63..94e23a292 100644 --- a/alpine/packages/9pmount-vsock/hvsock.c +++ b/alpine/packages/9pmount-vsock/hvsock.c @@ -4,23 +4,23 @@ int parseguid(const char *s, GUID *g) { - int res; - int p0, p1, p2, p3, p4, p5, p6, p7; + 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; + 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, @@ -29,7 +29,6 @@ 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, diff --git a/alpine/packages/9pmount-vsock/hvsock.h b/alpine/packages/9pmount-vsock/hvsock.h index 6e1ca6695..1f532c2eb 100644 --- a/alpine/packages/9pmount-vsock/hvsock.h +++ b/alpine/packages/9pmount-vsock/hvsock.h @@ -7,10 +7,10 @@ /* GUID handling */ typedef struct _GUID { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + 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) \ @@ -33,12 +33,11 @@ extern int parseguid(const char *s, GUID *g); #define AF_HYPERV 43 #define HV_PROTOCOL_RAW 1 -typedef struct _SOCKADDR_HV -{ - unsigned short Family; - unsigned short Reserved; - GUID VmId; - GUID ServiceId; +typedef struct _SOCKADDR_HV { + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; } SOCKADDR_HV; extern const GUID HV_GUID_ZERO; diff --git a/alpine/packages/tap-vsockd/hvsock.c b/alpine/packages/tap-vsockd/hvsock.c index 47c924d63..59251bab2 100644 --- a/alpine/packages/tap-vsockd/hvsock.c +++ b/alpine/packages/tap-vsockd/hvsock.c @@ -4,23 +4,25 @@ int parseguid(const char *s, GUID *g) { - int res; - int p0, p1, p2, p3, p4, p5, p6, p7; + 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; + 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, @@ -28,7 +30,7 @@ DEFINE_GUID(HV_GUID_ZERO, 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); +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); diff --git a/alpine/packages/tap-vsockd/hvsock.h b/alpine/packages/tap-vsockd/hvsock.h index 6e1ca6695..bf680a7a2 100644 --- a/alpine/packages/tap-vsockd/hvsock.h +++ b/alpine/packages/tap-vsockd/hvsock.h @@ -7,10 +7,10 @@ /* GUID handling */ typedef struct _GUID { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + 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) \ @@ -33,12 +33,11 @@ extern int parseguid(const char *s, GUID *g); #define AF_HYPERV 43 #define HV_PROTOCOL_RAW 1 -typedef struct _SOCKADDR_HV -{ - unsigned short Family; - unsigned short Reserved; - GUID VmId; - GUID ServiceId; +typedef struct _SOCKADDR_HV { + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; } SOCKADDR_HV; extern const GUID HV_GUID_ZERO; diff --git a/alpine/packages/tap-vsockd/protocol.c b/alpine/packages/tap-vsockd/protocol.c index 22a143a58..6604e65ec 100644 --- a/alpine/packages/tap-vsockd/protocol.c +++ b/alpine/packages/tap-vsockd/protocol.c @@ -10,162 +10,222 @@ #include "protocol.h" /* Version 0 of the protocol used this */ -char expected_hello_old[5] = { 'V', 'M', 'N', 'E', 'T' }; +char expected_hello_old[5] = {'V', 'M', 'N', 'E', 'T'}; /* Version 1 and later of the protocol used this */ -char expected_hello[5] = { 'V', 'M', 'N', '3', 'T' }; +char expected_hello[5] = {'V', 'M', 'N', '3', 'T'}; -int really_read(int fd, uint8_t *buffer, size_t total){ - size_t remaining = total; - ssize_t n; - while (remaining > 0){ - n = read(fd, buffer, remaining); - if (n == 0){ - syslog(LOG_CRIT, "EOF reading from socket: closing\n"); - goto err; - } - if (n < 0){ - syslog(LOG_CRIT, "Failure reading from socket: closing: %s", strerror(errno)); - goto err; - } - remaining -= (size_t)n; - buffer = buffer + n; - } - return 0; -err: - /* On error: stop reading from the socket and trigger a clean shutdown */ - shutdown(fd, SHUT_RD); - return -1; -} - -int really_write(int fd, uint8_t *buffer, size_t total){ +int really_read(int fd, uint8_t *buffer, size_t total) +{ size_t remaining = total; - ssize_t n; - while (remaining > 0){ - n = write(fd, buffer, remaining); - if (n == 0){ - syslog(LOG_CRIT, "EOF writing to socket: closing"); - goto err; - } - if (n < 0){ - syslog(LOG_CRIT, "Failure writing to socket: closing: %s", strerror(errno)); - goto err; - } - remaining -= (size_t) n; - buffer = buffer + n; - } - return 0; + ssize_t n; + + while (remaining > 0) { + n = read(fd, buffer, remaining); + if (n == 0) { + syslog(LOG_CRIT, "EOF reading from socket: closing\n"); + goto err; + } + if (n < 0) { + syslog(LOG_CRIT, + "Failure reading from socket: closing: %s", + strerror(errno)); + goto err; + } + remaining -= (size_t) n; + buffer = buffer + n; + } + return 0; err: - /* On error: stop listening to the socket */ - shutdown(fd, SHUT_WR); - return -1; + /* + * On error: stop reading from the socket and trigger a clean + * shutdown + */ + shutdown(fd, SHUT_RD); + return -1; } -struct init_message *create_init_message(){ - struct init_message *m = (struct init_message*) malloc(sizeof(struct init_message)); - bzero(m, sizeof(struct init_message)); - memcpy(&m->hello[0], &expected_hello[0], sizeof(m->hello)); - m->version = CURRENT_VERSION; - memset(&m->commit[0], 0, sizeof(m->commit)); - return m; +int really_write(int fd, uint8_t *buffer, size_t total) +{ + size_t remaining = total; + ssize_t n; + + while (remaining > 0) { + n = write(fd, buffer, remaining); + if (n == 0) { + syslog(LOG_CRIT, "EOF writing to socket: closing"); + goto err; + } + if (n < 0) { + syslog(LOG_CRIT, + "Failure writing to socket: closing: %s", + strerror(errno)); + goto err; + } + remaining -= (size_t) n; + buffer = buffer + n; + } + return 0; +err: + /* On error: stop listening to the socket */ + shutdown(fd, SHUT_WR); + return -1; } -char *print_init_message(struct init_message *m) { - char tmp[41]; - memcpy(&tmp[0], &m->commit[0], 40); - tmp[40] = '\000'; - char *buffer = (char*) malloc(80); - int n = snprintf(buffer, 80, "version %d, commit %s", m->version, tmp); - if (n < 0) { - perror("Failed to format init_message"); - exit(1); - } - return buffer; +struct init_message *create_init_message() +{ + struct init_message *m; + + m = malloc(sizeof(struct init_message)); + if (!m) + return NULL; + + bzero(m, sizeof(struct init_message)); + memcpy(&m->hello[0], &expected_hello[0], sizeof(m->hello)); + m->version = CURRENT_VERSION; + memset(&m->commit[0], 0, sizeof(m->commit)); + + return m; } -int read_init_message(int fd, struct init_message *ci) { - bzero(ci, sizeof(struct init_message)); - if (really_read(fd, (uint8_t*) &ci->hello[0], sizeof(ci->hello)) == -1){ - syslog(LOG_CRIT, "Failed to read hello from client"); - return -1; - } - if (memcmp(&ci->hello[0], &expected_hello_old[0], sizeof(expected_hello_old)) == 0) { - ci->version = 0; - return 0; - } - if (memcmp(&ci->hello[0], &expected_hello[0], sizeof(expected_hello)) != 0) { - syslog(LOG_CRIT, "Failed to read header magic from client"); - return -1; - } - if (really_read(fd, (uint8_t*) &ci->version, sizeof(ci->version)) == -1){ - syslog(LOG_CRIT, "Failed to read header version from client"); - return -1; - } - if (really_read(fd, (uint8_t*) &ci->commit[0], sizeof(ci->commit)) == -1){ - syslog(LOG_CRIT, "Failed to read header hash from client"); - return -1; - } - return 0; +char *print_init_message(struct init_message *m) +{ + char tmp[41]; + + memcpy(&tmp[0], &m->commit[0], 40); + tmp[40] = '\000'; + char *buffer; + int n; + + buffer = malloc(80); + if (!buffer) + return NULL; + + n = snprintf(buffer, 80, "version %d, commit %s", m->version, tmp); + if (n < 0) { + perror("Failed to format init_message"); + exit(1); + } + return buffer; } -int write_init_message(int fd, struct init_message *ci) { - if (really_write(fd, (uint8_t*) &ci->hello[0], sizeof(ci->hello)) == -1){ - syslog(LOG_CRIT, "Failed to write hello to client"); - return -1; - } - if (ci->version > 0) { - if (really_write(fd, (uint8_t*) &ci->version, sizeof(ci->version)) == -1){ - syslog(LOG_CRIT, "Failed to write version to client"); - return -1; - } - if (really_write(fd, (uint8_t*) &ci->commit[0], sizeof(ci->commit)) == -1){ - syslog(LOG_CRIT, "Failed to write header hash to client"); - return -1; - } - } - return 0; +int read_init_message(int fd, struct init_message *ci) +{ + int res; + + bzero(ci, sizeof(struct init_message)); + + res = really_read(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello)); + if (res == -1) { + syslog(LOG_CRIT, "Failed to read hello from client"); + return -1; + } + + res = memcmp(&ci->hello[0], + &expected_hello_old[0], sizeof(expected_hello_old)); + if (res == 0) { + ci->version = 0; + return 0; + } + + res = memcmp(&ci->hello[0], + &expected_hello[0], sizeof(expected_hello)); + if (res != 0) { + syslog(LOG_CRIT, "Failed to read header magic from client"); + return -1; + } + + res = really_read(fd, (uint8_t *)&ci->version, sizeof(ci->version)); + if (res == -1) { + syslog(LOG_CRIT, "Failed to read header version from client"); + return -1; + } + + res = really_read(fd, (uint8_t *)&ci->commit[0], sizeof(ci->commit)); + if (res == -1) { + syslog(LOG_CRIT, "Failed to read header hash from client"); + return -1; + } + + return 0; } -int read_vif_info(int fd, struct vif_info *vif) { - uint8_t buffer[10]; - if (really_read(fd, &buffer[0], sizeof(buffer)) == -1){ - syslog(LOG_CRIT, "Failed to read vif info from client"); - return -1; - } - vif->mtu = (size_t) (buffer[0] | (buffer[1] << 8)); - vif->max_packet_size = (size_t) (buffer[2] | (buffer[3] << 8)); - memcpy(vif->mac, &buffer[4], 6); - return 0; +int write_init_message(int fd, struct init_message *ci) +{ + int res; + + res = really_write(fd, (uint8_t *)&ci->hello[0], sizeof(ci->hello)); + if (res == -1) { + syslog(LOG_CRIT, "Failed to write hello to client"); + return -1; + } + if (ci->version > 0) { + res = really_write(fd, (uint8_t *)&ci->version, + sizeof(ci->version)); + if (res == -1) { + syslog(LOG_CRIT, "Failed to write version to client"); + return -1; + } + res = really_write(fd, (uint8_t *)&ci->commit[0], + sizeof(ci->commit)); + if (res == -1) { + syslog(LOG_CRIT, + "Failed to write header hash to client"); + return -1; + } + } + return 0; +} + +int read_vif_info(int fd, struct vif_info *vif) +{ + uint8_t buffer[10]; + + if (really_read(fd, &buffer[0], sizeof(buffer)) == -1) { + syslog(LOG_CRIT, "Failed to read vif info from client"); + return -1; + } + + vif->mtu = (size_t)(buffer[0] | (buffer[1] << 8)); + vif->max_packet_size = (size_t)(buffer[2] | (buffer[3] << 8)); + memcpy(vif->mac, &buffer[4], 6); + return 0; } -int write_vif_info(int fd, struct vif_info *vif) { - uint8_t buffer[10]; - buffer[0] = (uint8_t) ((vif->mtu >> 0) & 0xff); - buffer[1] = (uint8_t) ((vif->mtu >> 8) & 0xff); - buffer[2] = (uint8_t) ((vif->max_packet_size >> 0) & 0xff); - buffer[3] = (uint8_t) ((vif->max_packet_size >> 8) & 0xff); - memcpy(&buffer[0] + 4, &(vif->mac)[0], 6); - if (really_write(fd, &buffer[0], sizeof(buffer)) == -1){ - syslog(LOG_CRIT, "Failed to write vif into to client"); - return -1; - } - return 0; +int write_vif_info(int fd, struct vif_info *vif) +{ + uint8_t buffer[10]; + + buffer[0] = (uint8_t) ((vif->mtu >> 0) & 0xff); + buffer[1] = (uint8_t) ((vif->mtu >> 8) & 0xff); + buffer[2] = (uint8_t) ((vif->max_packet_size >> 0) & 0xff); + buffer[3] = (uint8_t) ((vif->max_packet_size >> 8) & 0xff); + memcpy(&buffer[0] + 4, &(vif->mac)[0], 6); + + if (really_write(fd, &buffer[0], sizeof(buffer)) == -1) { + syslog(LOG_CRIT, "Failed to write vif into to client"); + return -1; + } + return 0; } -int write_command(int fd, enum command *c) { - uint8_t command = *c; - if (really_write(fd, (uint8_t*) &command, sizeof(command)) == -1){ - syslog(LOG_CRIT, "Failed to write command to client"); - return -1; - } - return 0; +int write_command(int fd, enum command *c) +{ + uint8_t command = *c; + + if (really_write(fd, (uint8_t *)&command, sizeof(command)) == -1) { + syslog(LOG_CRIT, "Failed to write command to client"); + return -1; + } + return 0; } -int write_ethernet_args(int fd, struct ethernet_args *args){ - if (really_write(fd, (uint8_t*) &args->uuid_string[0], 36) == -1){ - syslog(LOG_CRIT, "Failed to write ethernet args to client"); - return -1; - } - return 0; +int write_ethernet_args(int fd, struct ethernet_args *args) +{ + if (really_write(fd, (uint8_t *)&args->uuid_string[0], 36) == -1) { + syslog(LOG_CRIT, "Failed to write ethernet args to client"); + return -1; + } + return 0; } diff --git a/alpine/packages/tap-vsockd/protocol.h b/alpine/packages/tap-vsockd/protocol.h index 1ce330086..05097b4e2 100644 --- a/alpine/packages/tap-vsockd/protocol.h +++ b/alpine/packages/tap-vsockd/protocol.h @@ -7,14 +7,17 @@ /* Client -> Server init_message */ /* Server -> Client init_message */ struct init_message { - char hello[5]; - uint8_t _padding[3]; - uint32_t version; - char commit[40]; /* git sha of the compiled commit */ + char hello[5]; + uint8_t _padding[3]; + uint32_t version; + char commit[40]; /* git sha of the compiled commit */ }; -/* This should be bumped whenever we add something (like a feature or a bugfix) - and we wish the UI to be able to detect when to trigger a reinstall. */ +/* + * This should be bumped whenever we add something (like a feature or a + * bugfix) and we wish the UI to be able to detect when to trigger a + * reinstall. + */ #define CURRENT_VERSION 13 extern struct init_message *create_init_message(void); @@ -24,24 +27,24 @@ extern char *print_init_message(struct init_message *m); /* Client -> Server command */ enum command { - ethernet = 1, + ethernet = 1, }; extern int write_command(int fd, enum command *c); /* Client -> Server command arguments */ struct ethernet_args { - char uuid_string[36]; + char uuid_string[36]; }; extern int write_ethernet_args(int fd, struct ethernet_args *args); /* Server -> Client: details of a vif */ struct vif_info { - uint8_t mac[6]; - short _padding; - size_t max_packet_size; - size_t mtu; + uint8_t mac[6]; + short _padding; + size_t max_packet_size; + size_t mtu; }; extern int read_vif_info(int fd, struct vif_info *vif); diff --git a/alpine/packages/tap-vsockd/tap-vsockd.c b/alpine/packages/tap-vsockd/tap-vsockd.c index e678c72e3..03a89ff05 100644 --- a/alpine/packages/tap-vsockd/tap-vsockd.c +++ b/alpine/packages/tap-vsockd/tap-vsockd.c @@ -1,6 +1,3 @@ -/* - */ - #include #include #include @@ -25,421 +22,470 @@ #include #include - #include "hvsock.h" #include "protocol.h" -int daemon_flag = 0; -int listen_flag = 0; -int connect_flag = 0; +int daemon_flag; +int listen_flag; +int connect_flag; char *default_sid = "30D48B34-7D27-4B0B-AAAF-BBBED334DD59"; void fatal(const char *msg) { - syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); - exit(1); + syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); + exit(1); } -int alloc_tap(const char *dev) { - int fd; - struct ifreq ifr; - const char *clonedev = "/dev/net/tun"; - if ((fd = open(clonedev, O_RDWR)) == -1) { - fatal("Failed to open /dev/net/tun"); - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - if (ioctl(fd, TUNSETIFF, (void*) &ifr) < 0) { - fatal("TUNSETIFF failed"); - } - int persist = 1; - if (ioctl(fd, TUNSETPERSIST, persist) < 0) { - fatal("TUNSETPERSIST failed"); - } - syslog(LOG_INFO, "successfully created TAP device %s", dev); - return fd; +int alloc_tap(const char *dev) +{ + const char *clonedev = "/dev/net/tun"; + struct ifreq ifr; + int persist = 1; + int fd; + + fd = open(clonedev, O_RDWR); + if (fd == -1) + fatal("Failed to open /dev/net/tun"); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) + fatal("TUNSETIFF failed"); + + if (ioctl(fd, TUNSETPERSIST, persist) < 0) + fatal("TUNSETPERSIST failed"); + + syslog(LOG_INFO, "successfully created TAP device %s", dev); + return fd; } -void set_macaddr(const char *dev, uint8_t *mac) { - int fd; - struct ifreq ifq; +void set_macaddr(const char *dev, uint8_t *mac) +{ + struct ifreq ifq; + int fd; - fd = socket(PF_INET, SOCK_DGRAM, 0); - strcpy(ifq.ifr_name, dev); - memcpy(&ifq.ifr_hwaddr.sa_data[0], mac, 6); - ifq.ifr_hwaddr.sa_family = ARPHRD_ETHER; + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd == -1) + fatal("Could not get socket to set MAC address"); + strcpy(ifq.ifr_name, dev); + memcpy(&ifq.ifr_hwaddr.sa_data[0], mac, 6); + ifq.ifr_hwaddr.sa_family = ARPHRD_ETHER; - if (ioctl(fd, SIOCSIFHWADDR, &ifq) == -1) { - fatal("SIOCSIFHWADDR failed"); - } + if (ioctl(fd, SIOCSIFHWADDR, &ifq) == -1) + fatal("SIOCSIFHWADDR failed"); - close(fd); + close(fd); } /* Negotiate a vmnet connection, returns 0 on success and 1 on error. */ int negotiate(int fd, struct vif_info *vif) { - /* Negotiate with com.docker.slirp */ - struct init_message *me = create_init_message(); - if (write_init_message(fd, me) == -1) { - goto err; - } - struct init_message you; - if (read_init_message(fd, &you) == -1) { - goto err; - } - char *txt = print_init_message(&you); - syslog(LOG_INFO, "Server reports %s", txt); - free(txt); - enum command command = ethernet; - if (write_command(fd, &command) == -1) { - goto err; - } - struct ethernet_args args; - /* We don't need a uuid */ - memset(&args.uuid_string[0], 0, sizeof(args.uuid_string)); - if (write_ethernet_args(fd, &args) == -1) { - goto err; - } - if (read_vif_info(fd, vif) == -1) { - goto err; - } - return 0; + enum command command = ethernet; + struct init_message *me; + struct ethernet_args args; + struct init_message you; + char *txt; + + me = create_init_message(); + if (!me) + goto err; + + if (write_init_message(fd, me) == -1) + goto err; + + if (read_init_message(fd, &you) == -1) + goto err; + + txt = print_init_message(&you); + if (!txt) + goto err; + + syslog(LOG_INFO, "Server reports %s", txt); + free(txt); + + if (write_command(fd, &command) == -1) + goto err; + + /* We don't need a uuid */ + memset(&args.uuid_string[0], 0, sizeof(args.uuid_string)); + if (write_ethernet_args(fd, &args) == -1) + goto err; + + if (read_vif_info(fd, vif) == -1) + goto err; + + return 0; err: - syslog(LOG_CRIT, "Failed to negotiate vmnet connection"); - return 1; + syslog(LOG_CRIT, "Failed to negotiate vmnet connection"); + return 1; } /* Argument passed to proxy threads */ struct connection { - int fd; /* Hyper-V socket with vmnet protocol */ - int tapfd; /* TAP device with ethernet frames */ - struct vif_info vif; /* Contains VIF MAC, MTU etc, received from server */ + int fd; /* Hyper-V socket with vmnet protocol */ + int tapfd; /* TAP device with ethernet frames */ + struct vif_info vif; /* Contains MAC, MTU etc, received from server */ }; -static void* vmnet_to_tap(void *arg) +static void *vmnet_to_tap(void *arg) { - int length, n; - struct connection *connection = (struct connection*) arg; - uint8_t header[2]; - uint8_t buffer[2048]; + struct connection *connection = (struct connection *)arg; + uint8_t buffer[2048]; + uint8_t header[2]; + int length, n; - for (;;) { - if (really_read(connection->fd, &header[0], 2) == -1){ - fatal("Failed to read a packet header from host"); - } - length = (header[0] & 0xff) | ((header[1] & 0xff) << 8); - if (length > sizeof(buffer)) { - syslog(LOG_CRIT, "Received an over-large packet: %d > %ld", length, sizeof(buffer)); - exit(1); - } - if (really_read(connection->fd, &buffer[0], length) == -1){ - syslog(LOG_CRIT, "Failed to read packet contents from host"); - exit(1); - } - n = write(connection->tapfd, &buffer[0], length); - if (n != length) { - syslog(LOG_CRIT, "Failed to write %d bytes to tap device (wrote %d)", length, n); - exit(1); - } - } + for (;;) { + if (really_read(connection->fd, &header[0], 2) == -1) + fatal("Failed to read a packet header from host"); + + length = (header[0] & 0xff) | ((header[1] & 0xff) << 8); + if (length > sizeof(buffer)) { + syslog(LOG_CRIT, + "Received an over-large packet: %d > %ld", + length, sizeof(buffer)); + exit(1); + } + + if (really_read(connection->fd, &buffer[0], length) == -1) { + syslog(LOG_CRIT, + "Failed to read packet contents from host"); + exit(1); + } + + n = write(connection->tapfd, &buffer[0], length); + if (n != length) { + syslog(LOG_CRIT, + "Failed to write %d bytes to tap device (wrote %d)", length, n); + exit(1); + } + } } -static void* tap_to_vmnet(void *arg) +static void *tap_to_vmnet(void *arg) { - int length; - struct connection *connection = (struct connection*) arg; - uint8_t header[2]; - uint8_t buffer[2048]; + struct connection *connection = (struct connection *)arg; + uint8_t buffer[2048]; + uint8_t header[2]; + int length; - for (;;) { - length = read(connection->tapfd, &buffer[0], sizeof(buffer)); - if (length == -1) { - if (errno == ENXIO) { - fatal("tap device has gone down"); - } - syslog(LOG_WARNING, "ignoring error %d", errno); - /* This is what mirage-net-unix does. Is it a good idea really? */ - continue; - } - header[0] = (length >> 0) & 0xff; - header[1] = (length >> 8) & 0xff; - if (really_write(connection->fd, &header[0], 2) == -1){ - fatal("Failed to write packet header"); - } - if (really_write(connection->fd, &buffer[0], length) == -1) { - fatal("Failed to write packet body"); - } - } - return NULL; + for (;;) { + length = read(connection->tapfd, &buffer[0], sizeof(buffer)); + if (length == -1) { + if (errno == ENXIO) + fatal("tap device has gone down"); + + syslog(LOG_WARNING, "ignoring error %d", errno); + /* + * This is what mirage-net-unix does. Is it a good + * idea really? + */ + continue; + } + + header[0] = (length >> 0) & 0xff; + header[1] = (length >> 8) & 0xff; + if (really_write(connection->fd, &header[0], 2) == -1) + fatal("Failed to write packet header"); + + if (really_write(connection->fd, &buffer[0], length) == -1) + fatal("Failed to write packet body"); + } + + return NULL; } -/* Handle a connection by exchanging ethernet frames forever. +/* + * Handle a connection by exchanging ethernet frames forever. */ static void handle(struct connection *connection) { - pthread_t v2t, t2v; + pthread_t v2t, t2v; - if (pthread_create(&v2t, NULL, vmnet_to_tap, connection) != 0){ - fatal("Failed to create the vmnet_to_tap thread"); - } - if (pthread_create(&t2v, NULL, tap_to_vmnet, connection) != 0){ - fatal("Failed to create the tap_to_vmnet thread"); - } - if (pthread_join(v2t, NULL) != 0){ - fatal("Failed to join the vmnet_to_tap thread"); - } - if (pthread_join(t2v, NULL) != 0){ - fatal("Failed to join the tap_to_vmnet thread"); - } + if (pthread_create(&v2t, NULL, vmnet_to_tap, connection) != 0) + fatal("Failed to create the vmnet_to_tap thread"); + + if (pthread_create(&t2v, NULL, tap_to_vmnet, connection) != 0) + fatal("Failed to create the tap_to_vmnet thread"); + + if (pthread_join(v2t, NULL) != 0) + fatal("Failed to join the vmnet_to_tap thread"); + + if (pthread_join(t2v, NULL) != 0) + fatal("Failed to join the tap_to_vmnet thread"); } -static int create_listening_socket(GUID serviceid) { - int lsock = -1; - SOCKADDR_HV sa; - int res; +static int create_listening_socket(GUID serviceid) +{ + SOCKADDR_HV sa; + int lsock; + int res; - lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (lsock == -1) { - fatal("socket()"); - } + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == -1) + fatal("socket()"); - sa.Family = AF_HYPERV; - sa.Reserved = 0; - sa.VmId = HV_GUID_WILDCARD; - sa.ServiceId = serviceid; + 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 == -1) { - fatal("bind()"); - } + res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == -1) + fatal("bind()"); - res = listen(lsock, SOMAXCONN); - if (res == -1) { - fatal("listen()"); - } - return lsock; + res = listen(lsock, SOMAXCONN); + if (res == -1) + fatal("listen()"); + + return lsock; } -static int connect_socket(GUID serviceid) { - int sock = -1; - SOCKADDR_HV sa; - int res; +static int connect_socket(GUID serviceid) +{ + SOCKADDR_HV sa; + int sock; + int res; - sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (sock == -1) { - fatal("socket()"); - } + sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (sock == -1) + fatal("socket()"); - sa.Family = AF_HYPERV; - sa.Reserved = 0; - sa.VmId = HV_GUID_PARENT; - sa.ServiceId = serviceid; + 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 == -1) { - fatal("connect()"); - } + res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa)); + if (res == -1) + fatal("connect()"); - return sock; + return sock; } -static int accept_socket(int lsock) { - int csock = -1; - SOCKADDR_HV sac; - socklen_t socklen = sizeof(sac); +static int accept_socket(int lsock) +{ + SOCKADDR_HV sac; + socklen_t socklen = sizeof(sac); + int csock; - csock = accept(lsock, (struct sockaddr *)&sac, &socklen); - if (csock == -1) { - fatal("accept()"); - } + csock = accept(lsock, (struct sockaddr *)&sac, &socklen); + if (csock == -1) + fatal("accept()"); - syslog(LOG_INFO, "Connect from: "GUID_FMT":"GUID_FMT"\n", - GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); - return csock; + syslog(LOG_INFO, "Connect from: " GUID_FMT ":" GUID_FMT "\n", + GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); + + return csock; } -void write_pidfile(const char *pidfile) { - pid_t pid = getpid(); - char * pid_s; - FILE *file; - int len; +void write_pidfile(const char *pidfile) +{ + pid_t pid = getpid(); + char *pid_s; + FILE *file; + int len; - if (asprintf(&pid_s, "%lld", (long long) pid) == -1) { - fatal("Failed to allocate pidfile string"); - } - len = strlen(pid_s); - file = fopen(pidfile, "w"); - if (file == NULL) { - syslog(LOG_CRIT, "Failed to open pidfile %s", pidfile); - exit(1); - } + if (asprintf(&pid_s, "%lld", (long long)pid) == -1) + fatal("Failed to allocate pidfile string"); - if (fwrite(pid_s, 1, len, file) != len) { - fatal("Failed to write pid to pidfile"); - } - fclose(file); - free(pid_s); + len = strlen(pid_s); + file = fopen(pidfile, "w"); + if (file == NULL) { + syslog(LOG_CRIT, "Failed to open pidfile %s", pidfile); + exit(1); + } + + if (fwrite(pid_s, 1, len, file) != len) + fatal("Failed to write pid to pidfile"); + + fclose(file); + free(pid_s); } -void daemonize(const char *pidfile){ - pid_t pid = fork (); - if (pid == -1) { - fatal("Failed to fork()"); - } - else if (pid != 0) - exit(0); - if (setsid () == -1) { - fatal("Failed to setsid()"); - } - if (chdir ("/") == -1) { - fatal("Failed to chdir()"); - } - int null = open("/dev/null", O_RDWR); - dup2(null, STDIN_FILENO); - dup2(null, STDOUT_FILENO); - dup2(null, STDERR_FILENO); - close(null); - if (pidfile) write_pidfile(pidfile); +void daemonize(const char *pidfile) +{ + pid_t pid; + int null; + + pid = fork(); + if (pid == -1) + fatal("Failed to fork()"); + else if (pid != 0) + exit(0); + + if (setsid() == -1) + fatal("Failed to setsid()"); + + if (chdir("/") == -1) + fatal("Failed to chdir()"); + + null = open("/dev/null", O_RDWR); + if (null == -1) + fatal("Failed to open /dev/null"); + dup2(null, STDIN_FILENO); + dup2(null, STDOUT_FILENO); + dup2(null, STDERR_FILENO); + close(null); + + if (pidfile) + write_pidfile(pidfile); } void usage(char *name) { - printf("%s usage:\n", name); - printf("\t[--daemon] [--tap ] [--serviceid ] [--pid ]\n"); - printf("\t[--listen | --connect]\n\n"); - printf("where\n"); - printf("\t--daemonize: run as a background daemon\n"); - printf("\t--tap : create a tap device with the given name\n"); - printf("\t (defaults to eth1)\n"); - printf("\t--serviceid : use as the well-known service GUID\n"); - printf("\t (defaults to %s)\n", default_sid); - printf("\t--pid : write a pid to the given file\n"); - printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n"); - printf("\t--connect: connect to the parent partition\n"); + printf("%s usage:\n", name); + printf("\t[--daemon] [--tap ] [--serviceid ] [--pid ]\n"); + printf("\t[--listen | --connect]\n\n"); + printf("where\n"); + printf("\t--daemonize: run as a background daemon\n"); + printf("\t--tap : create a tap device with the given name\n"); + printf("\t (defaults to eth1)\n"); + printf("\t--serviceid : use as the well-known service GUID\n"); + printf("\t (defaults to %s)\n", default_sid); + printf("\t--pid : write a pid to the given file\n"); + printf("\t--listen: listen forever for incoming AF_HVSOCK connections\n"); + printf("\t--connect: connect to the parent partition\n"); } int main(int argc, char **argv) { - int res = 0; - GUID sid; - int c; - /* Defaults to a testing GUID */ - char *serviceid = default_sid; - char *tap = "eth1"; - char *pidfile = NULL; + char *serviceid = default_sid; + struct connection connection; + char *tap = "eth1"; + char *pidfile = NULL; + int lsocket = -1; + int sock = -1; + int res = 0; + int status; + pid_t child; + int tapfd; + GUID sid; + int c; - opterr = 0; - while (1) { - static struct option long_options[] = { - /* These options set a flag. */ - {"daemon", no_argument, &daemon_flag, 1}, - {"serviceid", required_argument, NULL, 's'}, - {"tap", required_argument, NULL, 't'}, - {"pidfile", required_argument, NULL, 'p'}, - {"listen", no_argument, &listen_flag, 1}, - {"connect", no_argument, &connect_flag, 1}, - {0, 0, 0, 0} - }; - int option_index = 0; + int option_index; + int log_flags = LOG_CONS | LOG_NDELAY; + static struct option long_options[] = { + /* These options set a flag. */ + {"daemon", no_argument, &daemon_flag, 1}, + {"serviceid", required_argument, NULL, 's'}, + {"tap", required_argument, NULL, 't'}, + {"pidfile", required_argument, NULL, 'p'}, + {"listen", no_argument, &listen_flag, 1}, + {"connect", no_argument, &connect_flag, 1}, + {0, 0, 0, 0} + }; - c = getopt_long (argc, argv, "ds:t:p:", long_options, &option_index); - if (c == -1) break; + opterr = 0; + while (1) { + option_index = 0; - switch (c) { - case 'd': - daemon_flag = 1; - break; - case 's': - serviceid = optarg; - break; - case 't': - tap = optarg; - break; - case 'p': - pidfile = 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); - } - if (daemon_flag && !pidfile){ - fprintf(stderr, "For daemon mode, please supply a --pidfile argument.\n"); - exit(1); - } - res = parseguid(serviceid, &sid); - if (res) { - fprintf(stderr, "Failed to parse serviceid as GUID: %s\n", serviceid); - usage(argv[0]); - exit(1); - } + c = getopt_long(argc, argv, "ds:t:p:", + long_options, &option_index); + if (c == -1) + break; - int log_flags = LOG_CONS | LOG_NDELAY; - if (!daemon_flag) { - log_flags |= LOG_PERROR; - } - openlog(argv[0], log_flags, LOG_DAEMON); + switch (c) { + case 'd': + daemon_flag = 1; + break; + case 's': + serviceid = optarg; + break; + case 't': + tap = optarg; + break; + case 'p': + pidfile = optarg; + break; + case 0: + break; + default: + usage(argv[0]); + exit(1); + } + } - int tapfd = alloc_tap(tap); + 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); + } - struct connection connection; - connection.tapfd = tapfd; + if (daemon_flag && !pidfile) { + fprintf(stderr, "For daemon mode, please supply a --pidfile argument.\n"); + exit(1); + } - int sock = -1; - int lsocket = -1; - if (listen_flag) { - syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap); - lsocket = create_listening_socket(sid); - } else { - syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap); - } + res = parseguid(serviceid, &sid); + if (res) { + fprintf(stderr, "Failed to parse serviceid as GUID: %s\n", serviceid); + usage(argv[0]); + exit(1); + } - for (;;) { - if (sock != -1) { - close(sock); - sock = -1; - } - if (listen_flag) { - sock = accept_socket(lsocket); - } else { - sock = connect_socket(sid); - } + if (!daemon_flag) + log_flags |= LOG_PERROR; - connection.fd = sock; - if (negotiate(sock, &connection.vif) != 0) { - sleep(1); - continue; - } - syslog(LOG_INFO, "VMNET VIF has MAC %02x:%02x:%02x:%02x:%02x:%02x", - connection.vif.mac[0], connection.vif.mac[1], connection.vif.mac[2], - connection.vif.mac[3], connection.vif.mac[4], connection.vif.mac[5] - ); - set_macaddr(tap, &connection.vif.mac[0]); + openlog(argv[0], log_flags, LOG_DAEMON); - /* Daemonize after we've made our first reliable connection */ - if (daemon_flag) { - daemon_flag = 0; - daemonize(pidfile); - } - /* Run the multithreaded part in a subprocess. On error the process will - exit() which tears down all the threads */ - pid_t child = fork(); - if (child == 0) { - handle(&connection); - /* should never happen but just in case of a logic bug in handle */ - exit(1); - } - int status; - while (waitpid(child, &status, 0) == -1) { } - } + tapfd = alloc_tap(tap); + connection.tapfd = tapfd; + + if (listen_flag) { + syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap); + lsocket = create_listening_socket(sid); + } else { + syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap); + } + + for (;;) { + if (sock != -1) { + close(sock); + sock = -1; + } + + if (listen_flag) + sock = accept_socket(lsocket); + else + sock = connect_socket(sid); + + connection.fd = sock; + if (negotiate(sock, &connection.vif) != 0) { + sleep(1); + continue; + } + + syslog(LOG_INFO, "VMNET VIF has MAC %02x:%02x:%02x:%02x:%02x:%02x", + connection.vif.mac[0], connection.vif.mac[1], connection.vif.mac[2], + connection.vif.mac[3], connection.vif.mac[4], connection.vif.mac[5] + ); + set_macaddr(tap, &connection.vif.mac[0]); + + /* Daemonize after we've made our first reliable connection */ + if (daemon_flag) { + daemon_flag = 0; + daemonize(pidfile); + } + + /* + * Run the multithreaded part in a subprocess. On error the + * process will exit() which tears down all the threads + */ + child = fork(); + if (child == 0) { + handle(&connection); + /* + * should never happen but just in case of a logic + * bug in handle + */ + exit(1); + } + + for (;;) { + if (waitpid(child, &status, 0) != -1) + break; + } + } } diff --git a/alpine/packages/transfused/transfused.c b/alpine/packages/transfused/transfused.c index a6c8982dc..bc722101b 100644 --- a/alpine/packages/transfused/transfused.c +++ b/alpine/packages/transfused/transfused.c @@ -25,1050 +25,1162 @@ #include "transfused_log.h" #include "transfused_vsock.h" -char * default_fusermount = DEFAULT_FUSERMOUNT; -char * default_socket = DEFAULT_SOCKET; -char * default_server = DEFAULT_SERVER; -char * usage = - "usage: transfused [-p pidfile] [-d server] [-s socket] [-f fusermount]\n" - " [-l logfile]\n" - " -p pidfile\tthe path at which to write the pid of the process\n" - " -d " DEFAULT_SERVER "\tthe server address to use ('v:addr:port')\n" - " -s " DEFAULT_SOCKET "\tthe socket address to use ('v:addr:port')\n" - " -f " DEFAULT_FUSERMOUNT "\tthe fusermount executable to use\n" - " -l logfile\tthe log file to use before uplink\n" - ; +char *default_fusermount = DEFAULT_FUSERMOUNT; +char *default_socket = DEFAULT_SOCKET; +char *default_server = DEFAULT_SERVER; +char *usage = +"usage: transfused [-p pidfile] [-d server] [-s socket] [-f fusermount]\n" +" [-l logfile]\n" +" -p pidfile\tthe path at which to write the pid of the process\n" +" -d " DEFAULT_SERVER "\tthe server address to use ('v:addr:port')\n" +" -s " DEFAULT_SOCKET "\tthe socket address to use ('v:addr:port')\n" +" -f " DEFAULT_FUSERMOUNT "\tthe fusermount executable to use\n" +" -l logfile\tthe log file to use before uplink\n"; -int debug = 0; +int debug; pthread_attr_t detached; typedef struct { - connection_t * connection; - int from; - int to; + connection_t *connection; + int from; + int to; } copy_thread_state; #include -pid_t gettid() { - return syscall(SYS_gettid); -} - -void * must_malloc(char *const descr, size_t size) { - void * ptr; - - ptr = malloc(size); - if (size != 0 && ptr == NULL) die(1, NULL, descr, ""); - - return ptr; -} - -void cond_init(char *const descr, pthread_cond_t * cond, - const pthread_condattr_t *restrict attr) { - if ((errno = pthread_cond_init(cond, attr))) - die(1, NULL, "", "cond init %s: ", descr); -} - -void lock_init(char *const descr, pthread_mutex_t * mutex, - const pthread_mutexattr_t *restrict attr) { - if ((errno = pthread_mutex_init(mutex, attr))) - die(1, NULL, "", "lock init %s: ", descr); -} - -void lock(char *const descr, pthread_mutex_t * mutex) { - if ((errno = pthread_mutex_lock(mutex))) - die(1, NULL, "", "lock %s: ", descr); -} - -void unlock(char *const descr, pthread_mutex_t * mutex) { - if ((errno = pthread_mutex_unlock(mutex))) - die(1, NULL, "", "unlock %s: ", descr); -} - -int bind_socket(const char * socket) { - int sock; - - if (socket[0] == 0) - die(2, NULL, NULL, "Socket family required"); - - if (socket[1] != ':') - die(2, NULL, NULL, "Socket address required"); - - switch (socket[0]) { - case 'v': - sock = bind_vsock(socket + 2); - break; - default: - die(2, NULL, NULL, "Unknown socket family '%c'", socket[0]); - } - - return sock; -} - -int connect_socket(const char * socket) { - int sock; - - if (socket[0] == 0) - die(2, NULL, NULL, "Socket family required"); - if (socket[1] != ':') - die(2, NULL, NULL, "Scoket address required"); - - switch (socket[0]) { - case 'v': - sock = connect_vsock(socket + 2); - break; - default: - die(2, NULL, NULL, "Unknown socket family '%c'", socket[0]); - } - - return sock; -} - -char ** read_opts(connection_t * conn, char * buf) { - int read_count; - int optc = 1; - char ** optv; - size_t mount_len; - - // TODO: deal with socket read conditions e.g. EAGAIN - read_count = read(conn->sock, buf, EVENT_BUFSZ - 1); - if (read_count < 0) die(1, conn->params, "read_opts error reading", ""); - - // TODO: protocol should deal with short read - buf[read_count] = 0x0; - - for (int i = 0; i < read_count; i++) { - if (buf[i] == 0x0) optc++; - } - - optv = (char **) must_malloc("read_opts optv", (optc + 1) * sizeof(void *)); - optv[0] = buf; - optv[optc] = 0x0; - - int j = 1; - for (int i = 0; i < read_count && j < optc; i++) { - if (buf[i] == 0x0) { - optv[j] = buf + i + 1; - j++; - } - } - - mount_len = strnlen(optv[optc - 1], 4096) + 1; - conn->mount_point = must_malloc("mount point string", mount_len); - strncpy(conn->mount_point, optv[optc - 1], mount_len - 1); - conn->mount_point[mount_len - 1] = '\0'; - - return optv; -} - -uint64_t message_id(uint64_t * message) { - return message[1]; -} - -int read_message -(char * descr, parameters * params, int fd, char * buf, size_t max_read) +pid_t gettid(void) { - int read_count; - size_t nbyte; - uint32_t len; - - // TODO: socket read conditions e.g. EAGAIN - read_count = read(fd, buf, 4); - if (read_count != 4) { - if (read_count < 0) - die(1, params, "", "read %s: error reading: ", descr); - if (read_count == 0) - die(1, params, NULL, "read %s: EOF reading length", descr); - die(1, params, NULL, "read %s: short read length %d", descr, read_count); - } - len = *((uint32_t *) buf); - if (len > max_read) - die(1, params, NULL, "read %s: message size %d exceeds buffer capacity %d", - len, max_read); - - nbyte = (size_t) (len - 4); - buf += 4; - - do { - // TODO: socket read conditions e.g. EAGAIN - read_count = read(fd, buf, nbyte); - if (read_count < 0) die(1, params, "", "read %s: error reading: ", descr); - if (read_count == 0) die(1, params, NULL, "read %s: EOF reading", descr); - nbyte -= read_count; - buf += read_count; - } while (nbyte != 0); - - return (int) len; + return syscall(SYS_gettid); } -void copy_into_fuse(copy_thread_state * copy_state) { - int from = copy_state->from; - int to = copy_state->to; - char * descr = copy_state->connection->mount_point; - int read_count, write_count; - void * buf; - parameters * params = copy_state->connection->params; +void *must_malloc(char *const descr, size_t size) +{ + void *ptr; - buf = must_malloc(descr, IN_BUFSZ); + ptr = malloc(size); + if (size != 0 && ptr == NULL) + die(1, NULL, descr, ""); - while(1) { - read_count = read_message(descr, params, from, (char *) buf, IN_BUFSZ); - - write_count = write(to, buf, read_count); - if (write_count < 0) die(1, params, "", "copy %s: error writing: ", descr); - - // /dev/fuse accepts only complete writes - if (write_count != read_count) - die(1, params, NULL, "copy %s: read %d but only wrote %d", - descr, read_count, write_count); - } - - free(buf); + return ptr; } -void copy_notify_fuse(copy_thread_state * copy_state) { - int from = copy_state->from; - int to = copy_state->to; - char * descr = copy_state->connection->mount_point; - int read_count, write_count; - uint32_t zero = 0, err; - void * buf; - parameters * params = copy_state->connection->params; - - buf = must_malloc(descr, IN_BUFSZ); - - while (1) { - read_count = read_message(descr, params, from, (char *) buf, IN_BUFSZ); - write_count = write(to, buf, read_count); - if (write_count < 0) { - err = errno; - write_count = write(from, &err, 4); - if (write_count < 0) { - log_time(params, "copy notify %s write error: %s", strerror(err)); - die(1, params, "", "copy notify %s reply write error: ", - descr); - } - continue; - } else { - if (write(from, &zero, 4) < 0) - die(1, params, "", "copy notify %s reply write error: ", - descr); - } - - if (write_count != read_count) - die(1, params, NULL, "copy notify %s: read %d but only wrote %d", - descr, read_count, write_count); - } - - free(buf); +void cond_init(char *const descr, pthread_cond_t *cond, + const pthread_condattr_t *restrict attr) +{ + errno = pthread_cond_init(cond, attr); + if (errno) + die(1, NULL, "", "cond init %s: ", descr); } -void write_exactly(char * descr, int fd, void * p, size_t nbyte) { - int write_count; - char * buf = p; - - do { - // TODO: socket write conditions e.g. EAGAIN - write_count = write(fd, buf, nbyte); - if (write_count < 0) die(1, NULL, "", "%s: error writing: ", descr); - if (write_count == 0) die(1, NULL, "", "%s: 0 write: ", descr); - - nbyte -= write_count; - buf += write_count; - } while (nbyte != 0); +void lock_init(char *const descr, pthread_mutex_t *mutex, + const pthread_mutexattr_t *restrict attr) +{ + errno = pthread_mutex_init(mutex, attr); + if (errno) + die(1, NULL, "", "lock init %s: ", descr); } -void copy_outof_fuse(copy_thread_state * copy_state) { - int from = copy_state->from; - int to = copy_state->to; - char * descr = copy_state->connection->mount_point; - int read_count; - void * buf; - parameters * params = copy_state->connection->params; - - buf = must_malloc(descr, OUT_BUFSZ); - - while(1) { - // /dev/fuse only returns complete reads - read_count = read(from, buf, OUT_BUFSZ); - if (read_count < 0) die(1, params, "", "copy %s: error reading: ", descr); - - write_exactly(descr, to, (char *) buf, read_count); - } - - free(buf); +void lock(char *const descr, pthread_mutex_t *mutex) +{ + errno = pthread_mutex_lock(mutex); + if (errno) + die(1, NULL, "", "lock %s: ", descr); } -void * copy_clean_into_fuse(copy_thread_state * copy_state) { - copy_into_fuse(copy_state); - - close(copy_state->from); - - free(copy_state); - - return NULL; +void unlock(char *const descr, pthread_mutex_t *mutex) +{ + errno = pthread_mutex_unlock(mutex); + if (errno) + die(1, NULL, "", "unlock %s: ", descr); } -void * copy_clean_into_fuse_thread(void * copy_state) { - return (copy_clean_into_fuse((copy_thread_state *) copy_state)); +int bind_socket(const char *socket) +{ + int sock; + + if (socket[0] == 0) + die(2, NULL, NULL, "Socket family required"); + + if (socket[1] != ':') + die(2, NULL, NULL, "Socket address required"); + + switch (socket[0]) { + case 'v': + sock = bind_vsock(socket + 2); + break; + default: + die(2, NULL, NULL, "Unknown socket family '%c'", socket[0]); + } + + return sock; } -void * copy_clean_notify_fuse(copy_thread_state * copy_state) { - copy_notify_fuse(copy_state); +int connect_socket(const char *socket) +{ + int sock; - close(copy_state->from); + if (socket[0] == 0) + die(2, NULL, NULL, "Socket family required"); + if (socket[1] != ':') + die(2, NULL, NULL, "Scoket address required"); - free(copy_state); + switch (socket[0]) { + case 'v': + sock = connect_vsock(socket + 2); + break; + default: + die(2, NULL, NULL, "Unknown socket family '%c'", socket[0]); + } - return NULL; + return sock; } -void * copy_clean_notify_fuse_thread(void * copy_state) { - return (copy_clean_notify_fuse((copy_thread_state *) copy_state)); +char **read_opts(connection_t *conn, char *buf) +{ + int read_count; + int optc = 1; + char **optv; + size_t mount_len; + int j; + + /* TODO: deal with socket read conditions e.g.EAGAIN */ + read_count = read(conn->sock, buf, EVENT_BUFSZ - 1); + if (read_count < 0) + die(1, conn->params, "read_opts error reading", ""); + + /* TODO: protocol should deal with short read */ + buf[read_count] = 0x0; + + for (int i = 0; i < read_count; i++) { + if (buf[i] == 0x0) + optc++; + } + + optv = (char **)must_malloc("read_opts optv", (optc + 1) * sizeof(void *)); + optv[0] = buf; + optv[optc] = 0x0; + + j = 1; + for (int i = 0; i < read_count && j < optc; i++) { + if (buf[i] == 0x0) { + optv[j] = buf + i + 1; + j++; + } + } + + mount_len = strnlen(optv[optc - 1], 4096) + 1; + conn->mount_point = must_malloc("mount point string", mount_len); + strncpy(conn->mount_point, optv[optc - 1], mount_len - 1); + conn->mount_point[mount_len - 1] = '\0'; + + return optv; } -void * copy_clean_outof_fuse(copy_thread_state * copy_state) { - copy_outof_fuse(copy_state); - - close(copy_state->to); - - free(copy_state); - - return NULL; +uint64_t message_id(uint64_t *message) +{ + return message[1]; } -void * copy_clean_outof_fuse_thread(void * copy_state) { - return (copy_clean_outof_fuse((copy_thread_state *) copy_state)); +int read_message(char *descr, parameters *params, int fd, + char *buf, size_t max_read){ + int read_count; + size_t nbyte; + uint32_t len; + + /* TODO: socket read conditions e.g.EAGAIN */ + read_count = read(fd, buf, 4); + if (read_count != 4) { + if (read_count < 0) + die(1, params, "", "read %s: error reading: ", descr); + if (read_count == 0) + die(1, params, NULL, + "read %s: EOF reading length", descr); + die(1, params, NULL, + "read %s: short read length %d", descr, read_count); + } + len = *((uint32_t *) buf); + if (len > max_read) + die(1, params, NULL, + "read %s: message size %d exceeds buffer capacity %d", + len, max_read); + + nbyte = (size_t)(len - 4); + buf += 4; + + do { + /* TODO: socket read conditions e.g.EAGAIN */ + read_count = read(fd, buf, nbyte); + if (read_count < 0) + die(1, params, "", "read %s: error reading: ", descr); + if (read_count == 0) + die(1, params, NULL, "read %s: EOF reading", descr); + nbyte -= read_count; + buf += read_count; + } while (nbyte != 0); + + return (int)len; } -int recv_fd(parameters * params, int sock) { - int ret; - int fd = -1; - char iochar; - char buf[CMSG_SPACE(sizeof(fd))]; +void copy_into_fuse(copy_thread_state *copy_state) +{ + int from = copy_state->from; + int to = copy_state->to; + char *descr = copy_state->connection->mount_point; + int read_count, write_count; + void *buf; + parameters *params = copy_state->connection->params; - struct msghdr msg; - struct iovec vec; - struct cmsghdr *cmsg; + buf = must_malloc(descr, IN_BUFSZ); - msg.msg_name = NULL; - msg.msg_namelen = 0; - vec.iov_base = &iochar; - vec.iov_len = 1; - msg.msg_iov = &vec; + while (1) { + read_count = read_message(descr, params, + from, (char *)buf, IN_BUFSZ); - msg.msg_iovlen = 1; + write_count = write(to, buf, read_count); + if (write_count < 0) + die(1, params, "", "copy %s: error writing: ", descr); - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); + /* /dev/fuse accepts only complete writes */ + if (write_count != read_count) + die(1, params, NULL, + "copy %s: read %d but only wrote %d", + descr, read_count, write_count); + } - ret = recvmsg(sock, &msg, 0); - - if (ret == -1) die(1, params, "recvmsg", ""); - - if (ret > 0 && msg.msg_controllen > 0) { - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg->cmsg_level == SOL_SOCKET && (cmsg->cmsg_type == SCM_RIGHTS)) { - fd = *(int*)CMSG_DATA(cmsg); - } - } - - return fd; + free(buf); } -// optv must be null-terminated -int get_fuse_sock(connection_t * conn, int optc, char *const optv[]) { - char ** argv; - char * envp[2]; - char * mount_notice, * arg_acc; - pid_t fusermount_pid; - int fuse_socks[2]; - int status; - int fd; +void copy_notify_fuse(copy_thread_state *copy_state) +{ + int from = copy_state->from; + int to = copy_state->to; + char *descr = copy_state->connection->mount_point; + int read_count, write_count; + uint32_t zero = 0, err; + void *buf; + parameters *params = copy_state->connection->params; - // prepare argv from optv - argv = (char **) must_malloc("fusermount argv", (optc + 2) * sizeof(char *)); + buf = must_malloc(descr, IN_BUFSZ); - argv[0] = conn->params->fusermount; - memcpy(&argv[1], optv, (optc + 1) * sizeof(char *)); + while (1) { + read_count = read_message(descr, params, + from, (char *)buf, IN_BUFSZ); + write_count = write(to, buf, read_count); + if (write_count < 0) { + err = errno; + write_count = write(from, &err, 4); + if (write_count < 0) { + log_time(params, + "copy notify %s write error: %s", strerror(err)); + die(1, params, "", + "copy notify %s reply write error: ", descr); + } + continue; + } else { + if (write(from, &zero, 4) < 0) + die(1, params, "", + "copy notify %s reply write error: ", descr); + } - // report the mount command issued - if (asprintf(&arg_acc, "mount") == -1) - die(1, conn->params, "Couldn't allocate mount notice base string", ""); + if (write_count != read_count) + die(1, params, NULL, + "copy notify %s: read %d but only wrote %d", + descr, read_count, write_count); + } - for (int i = 0; argv[i]; i++) { - if (asprintf(&mount_notice, "%s %s", arg_acc, argv[i]) == -1) - die(1, conn->params, "", "Couldn't allocate mount notice arg %d: ", i); - free(arg_acc); - arg_acc = mount_notice; - } - - if (asprintf(&mount_notice, "%s\n", arg_acc) == -1) - die(1, conn->params, "Couldn't allocate mount notice", ""); - - log_notice_time(conn->params, mount_notice); - - free(mount_notice); - free(arg_acc); - - // make the socket over which we'll be sent the FUSE socket fd - if (socketpair(PF_UNIX, SOCK_STREAM, 0, fuse_socks)) - die(1, conn->params, "Couldn't create FUSE socketpair", ""); - - // prepare to exec the suid binary fusermount - if (asprintf(&envp[0], "_FUSE_COMMFD=%d", fuse_socks[0]) == -1) - die(1, conn->params, "Couldn't allocate fusermount envp", ""); - - envp[1] = 0x0; - - // fork and exec fusermount - fusermount_pid = fork(); - if (!fusermount_pid) // child - if (execve(argv[0], argv, envp)) - die(1, conn->params, "Failed to execute fusermount", ""); - - // parent - free(argv); - free(envp[0]); - - // close the end of the socket that we gave away - close(fuse_socks[0]); - - // wait for fusermount to return - waitpid(fusermount_pid, &status, 0); - if (!WIFEXITED(status)) - die(1, conn->params, NULL, "fusermount terminated abnormally"); - - if (WEXITSTATUS(status)) - die(1, conn->params, NULL, - "fusermount exited with code %d", WEXITSTATUS(status)); - - if (debug) log_time(conn->params, "about to recv_fd from fusermount\n"); - - fd = recv_fd(conn->params, fuse_socks[1]); - if (fd == -1) - die(1, conn->params, NULL, "Couldn't receive fd over FUSE socket"); - - // close the read end of the socket - close(fuse_socks[1]); - - return fd; + free(buf); } -void start_reader(connection_t * connection, int fuse) { - pthread_t child; - copy_thread_state * copy_state; +void write_exactly(char *descr, int fd, void *p, size_t nbyte) +{ + int write_count; + char *buf = p; - copy_state = (copy_thread_state *) must_malloc("start_reader copy_state", - sizeof(copy_thread_state)); - copy_state->connection = connection; - copy_state->from = connection->sock; - copy_state->to = fuse; - if ((errno = pthread_create(&child, &detached, - copy_clean_into_fuse_thread, copy_state))) - die(1, connection->params, "", - "Couldn't create read copy thread for mount %s: ", - connection->mount_point); + do { + /* TODO: socket write conditions e.g.EAGAIN */ + write_count = write(fd, buf, nbyte); + if (write_count < 0) + die(1, NULL, "", "%s: error writing: ", descr); + if (write_count == 0) + die(1, NULL, "", "%s: 0 write: ", descr); + + nbyte -= write_count; + buf += write_count; + } while (nbyte != 0); } -void start_writer(connection_t * connection, int fuse) { - pthread_t child; - copy_thread_state * copy_state; +void copy_outof_fuse(copy_thread_state *copy_state) +{ + int from = copy_state->from; + int to = copy_state->to; + char *descr = copy_state->connection->mount_point; + int read_count; + void *buf; + parameters *params = copy_state->connection->params; - copy_state = (copy_thread_state *) must_malloc("start_writer copy_state", - sizeof(copy_thread_state)); - copy_state->connection = connection; - copy_state->from = fuse; - copy_state->to = connection->sock; - if ((errno = pthread_create(&child, &detached, - copy_clean_outof_fuse_thread, copy_state))) - die(1, connection->params, "", - "Couldn't create write copy thread for mount %s: ", - connection->mount_point); + buf = must_malloc(descr, OUT_BUFSZ); + + while (1) { + /* /dev/fuse only returns complete reads */ + read_count = read(from, buf, OUT_BUFSZ); + if (read_count < 0) + die(1, params, "", "copy %s: error reading: ", descr); + + write_exactly(descr, to, (char *)buf, read_count); + } + + free(buf); } -void negotiate_notify_channel(char * mount_point, int notify_sock) { - int len = strlen(mount_point); - char hdr[6]; +void *copy_clean_into_fuse(copy_thread_state *copy_state) +{ + copy_into_fuse(copy_state); - *((uint32_t *) hdr) = 6 + len; - *((uint16_t *) (hdr + 4)) = TRANSFUSE_NOTIFY_CHANNEL; + close(copy_state->from); - write_exactly("negotiate_notify_channel hdr", notify_sock, hdr, 6); - write_exactly("negotiate_notify_channel mnt", notify_sock, mount_point, len); + free(copy_state); + + return NULL; } -void start_notify(connection_t * connection, int fuse) { - pthread_t child; - copy_thread_state * copy_state; +void *copy_clean_into_fuse_thread(void *copy_state) +{ + return copy_clean_into_fuse((copy_thread_state *)copy_state); +} - copy_state = (copy_thread_state *) must_malloc("start_notify copy_state", - sizeof(copy_thread_state)); - copy_state->connection = connection; - copy_state->from = connect_socket(connection->params->server); - copy_state->to = fuse; +void *copy_clean_notify_fuse(copy_thread_state *copy_state) +{ + copy_notify_fuse(copy_state); - negotiate_notify_channel(connection->mount_point, copy_state->from); + close(copy_state->from); - if ((errno = pthread_create(&child, &detached, - copy_clean_notify_fuse_thread, copy_state))) - die(1, connection->params, "", - "Couldn't create notify copy thread for mount %s: ", - connection->mount_point); + free(copy_state); + + return NULL; +} + +void *copy_clean_notify_fuse_thread(void *copy_state) +{ + return copy_clean_notify_fuse((copy_thread_state *) copy_state); +} + +void *copy_clean_outof_fuse(copy_thread_state *copy_state) +{ + copy_outof_fuse(copy_state); + + close(copy_state->to); + + free(copy_state); + + return NULL; +} + +void *copy_clean_outof_fuse_thread(void *copy_state) +{ + return copy_clean_outof_fuse((copy_thread_state *) copy_state); +} + +int recv_fd(parameters *params, int sock) +{ + int ret; + int fd = -1; + char iochar; + char buf[CMSG_SPACE(sizeof(fd))]; + + struct msghdr msg; + struct iovec vec; + struct cmsghdr *cmsg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + vec.iov_base = &iochar; + vec.iov_len = 1; + msg.msg_iov = &vec; + + msg.msg_iovlen = 1; + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + ret = recvmsg(sock, &msg, 0); + + if (ret == -1) + die(1, params, "recvmsg", ""); + + if (ret > 0 && msg.msg_controllen > 0) { + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg->cmsg_level == SOL_SOCKET && (cmsg->cmsg_type == SCM_RIGHTS)) + fd = *(int *)CMSG_DATA(cmsg); + } + return fd; +} + +/* optv must be null-terminated */ +int get_fuse_sock(connection_t *conn, int optc, char *const optv[]) +{ + char **argv; + char *envp[2]; + char *mount_notice, *arg_acc; + pid_t fusermount_pid; + int fuse_socks[2]; + int status; + int fd; + + /* prepare argv from optv */ + argv = (char **)must_malloc("fusermount argv", + (optc + 2) * sizeof(char *)); + + argv[0] = conn->params->fusermount; + memcpy(&argv[1], optv, (optc + 1) * sizeof(char *)); + + /* report the mount command issued */ + if (asprintf(&arg_acc, "mount") == -1) + die(1, conn->params, + "Couldn't allocate mount notice base string", ""); + + for (int i = 0; argv[i]; i++) { + if (asprintf(&mount_notice, "%s %s", arg_acc, argv[i]) == -1) + die(1, conn->params, "", + "Couldn't allocate mount notice arg %d: ", i); + free(arg_acc); + arg_acc = mount_notice; + } + + if (asprintf(&mount_notice, "%s\n", arg_acc) == -1) + die(1, conn->params, "Couldn't allocate mount notice", ""); + + log_notice_time(conn->params, mount_notice); + + free(mount_notice); + free(arg_acc); + + /* make the socket over which we'll be sent the FUSE socket fd */ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fuse_socks)) + die(1, conn->params, "Couldn't create FUSE socketpair", ""); + + /* prepare to exec the suid binary fusermount */ + if (asprintf(&envp[0], "_FUSE_COMMFD=%d", fuse_socks[0]) == -1) + die(1, conn->params, "Couldn't allocate fusermount envp", ""); + + envp[1] = 0x0; + + /* fork and exec fusermount */ + fusermount_pid = fork(); + if (!fusermount_pid) + /* child */ + if (execve(argv[0], argv, envp)) + die(1, conn->params, + "Failed to execute fusermount", ""); + + /* parent */ + free(argv); + free(envp[0]); + + /* close the end of the socket that we gave away */ + close(fuse_socks[0]); + + /* wait for fusermount to return */ + waitpid(fusermount_pid, &status, 0); + if (!WIFEXITED(status)) + die(1, conn->params, NULL, "fusermount terminated abnormally"); + + if (WEXITSTATUS(status)) + die(1, conn->params, NULL, + "fusermount exited with code %d", WEXITSTATUS(status)); + + if (debug) + log_time(conn->params, "about to recv_fd from fusermount\n"); + + fd = recv_fd(conn->params, fuse_socks[1]); + if (fd == -1) + die(1, conn->params, NULL, "Couldn't receive fd over FUSE socket"); + + /* close the read end of the socket */ + close(fuse_socks[1]); + + return fd; +} + +void start_reader(connection_t *connection, int fuse) +{ + pthread_t child; + copy_thread_state *copy_state; + + copy_state = (copy_thread_state *) + must_malloc("start_reader copy_state", + sizeof(copy_thread_state)); + copy_state->connection = connection; + copy_state->from = connection->sock; + copy_state->to = fuse; + errno = pthread_create(&child, &detached, + copy_clean_into_fuse_thread, copy_state); + if (errno) + die(1, connection->params, "", + "Couldn't create read copy thread for mount %s: ", + connection->mount_point); +} + +void start_writer(connection_t *connection, int fuse) +{ + pthread_t child; + copy_thread_state *copy_state; + + copy_state = (copy_thread_state *) + must_malloc("start_writer copy_state", + sizeof(copy_thread_state)); + copy_state->connection = connection; + copy_state->from = fuse; + copy_state->to = connection->sock; + errno = pthread_create(&child, &detached, + copy_clean_outof_fuse_thread, copy_state); + if (errno) + die(1, connection->params, "", + "Couldn't create write copy thread for mount %s: ", + connection->mount_point); +} + +void negotiate_notify_channel(char *mount_point, int notify_sock) +{ + int len = strlen(mount_point); + char hdr[6]; + + *((uint32_t *)hdr) = 6 + len; + *((uint16_t *)(hdr + 4)) = TRANSFUSE_NOTIFY_CHANNEL; + + write_exactly("negotiate_notify_channel hdr", notify_sock, hdr, 6); + write_exactly("negotiate_notify_channel mnt", + notify_sock, mount_point, len); +} + +void start_notify(connection_t *connection, int fuse) +{ + pthread_t child; + copy_thread_state *copy_state; + + copy_state = (copy_thread_state *) + must_malloc("start_notify copy_state", + sizeof(copy_thread_state)); + copy_state->connection = connection; + copy_state->from = connect_socket(connection->params->server); + copy_state->to = fuse; + + negotiate_notify_channel(connection->mount_point, copy_state->from); + + errno = pthread_create(&child, &detached, + copy_clean_notify_fuse_thread, copy_state); + if (errno) + die(1, connection->params, "", + "Couldn't create notify copy thread for mount %s: ", + connection->mount_point); } -char * alloc_dirname(connection_t * conn, char * path) { - size_t len = strlen(path) + 1; - char * input = must_malloc("alloc_dirname input", len); - char * output = must_malloc("alloc_dirname output", len); - char * dir; - strlcpy(input, path, len); +char *alloc_dirname(connection_t *conn, char *path) +{ + size_t len = strlen(path) + 1; + char *input = must_malloc("alloc_dirname input", len); + char *output = must_malloc("alloc_dirname output", len); + char *dir; - dir = dirname(input); - if (dir == NULL) - die(1, conn->params, "", "Couldn't get dirname of %s: ", path); - strcpy(output, dir); + strlcpy(input, path, len); - free(input); - return output; + dir = dirname(input); + if (dir == NULL) + die(1, conn->params, "", "Couldn't get dirname of %s: ", path); + strcpy(output, dir); + + free(input); + return output; } -void mkdir_p(connection_t * conn, char * path) { - char * parent; +void mkdir_p(connection_t *conn, char *path) +{ + char *parent; - if (mkdir(path, 0700)) switch (errno) { - case EEXIST: return; - case ENOENT: - parent = alloc_dirname(conn, path); - mkdir_p(conn, parent); - free(parent); - if (mkdir(path, 0700)) - die(1, conn->params, "", "Couldn't create directory %s: ", path); - break; - default: - die(1, conn->params, "", "Couldn't create directory %s: ", path); - } + if (mkdir(path, 0700)) + switch (errno) { + case EEXIST: + return; + case ENOENT: + parent = alloc_dirname(conn, path); + mkdir_p(conn, parent); + free(parent); + if (mkdir(path, 0700)) + die(1, conn->params, "", + "Couldn't create directory %s: ", path); + break; + default: + die(1, conn->params, "", + "Couldn't create directory %s: ", path); + } } -int is_next_child_ok(parameters * params, char * path, DIR * dir) { - struct dirent * child; +int is_next_child_ok(parameters *params, char *path, DIR *dir) +{ + struct dirent *child; - errno = 0; - child = readdir(dir); - if (child == NULL) { - if (errno != 0) - die(1, params, "", "Couldn't read directory %s: ", path); - else return 0; - } - return 1; + errno = 0; + child = readdir(dir); + if (child == NULL) { + if (errno != 0) + die(1, params, "", + "Couldn't read directory %s: ", path); + else + return 0; + } + return 1; } -int is_path_mountable -(parameters * params, int allow_empty, char * path) { - DIR * dir; +int is_path_mountable(parameters *params, int allow_empty, char *path) +{ + DIR *dir; - dir = opendir(path); - if (dir != NULL) { - // allow for . and .. - if (is_next_child_ok(params, path, dir)) - if (is_next_child_ok(params, path, dir)) { - if (is_next_child_ok(params, path, dir)) goto no; - else if (allow_empty) goto yes; - else goto no; - } - goto yes; - } else { - switch (errno) { - case ENOENT: goto yes; - case ENOTDIR: goto no; - default: goto no; - } - } - goto no; + dir = opendir(path); + if (dir != NULL) { + /* allow for . and .. */ + if (is_next_child_ok(params, path, dir)) + if (is_next_child_ok(params, path, dir)) { + if (is_next_child_ok(params, path, dir)) + goto no; + else if (allow_empty) + goto yes; + else + goto no; + } + goto yes; + } else { + switch (errno) { + case ENOENT: + goto yes; + case ENOTDIR: + goto no; + default: + goto no; + } + } + goto no; - no: if (dir) closedir(dir); return 0; - yes: if (dir) closedir(dir); return 1; +no: + if (dir) + closedir(dir); + return 0; + +yes: + if (dir) + closedir(dir); + return 1; } -// The leaf may exist but must be empty. Any proper path prefix may exist. -void prepare_mount_point(connection_t * conn) { - char * mount_point = conn->mount_point; +/* The leaf may exist but must be empty. Any proper path prefix may exist. */ +void prepare_mount_point(connection_t *conn) +{ + char *mount_point = conn->mount_point; - if (is_path_mountable(conn->params, 1, mount_point)) - mkdir_p(conn, mount_point); - else die(1, conn->params, NULL, - "Couldn't mount on %s: not missing or empty", mount_point); + if (is_path_mountable(conn->params, 1, mount_point)) + mkdir_p(conn, mount_point); + else + die(1, conn->params, NULL, + "Couldn't mount on %s: not missing or empty", mount_point); } -void * mount_connection(connection_t * conn) { - int optc; - char ** optv; - int fuse; - char * buf; - pthread_mutex_t copy_lock; - pthread_cond_t copy_halt; - int should_halt = 0; - - buf = (char *) must_malloc("read_opts packet malloc", EVENT_BUFSZ); +void *mount_connection(connection_t *conn) +{ + int optc; + char **optv; + int fuse; + char *buf; + pthread_mutex_t copy_lock; + pthread_cond_t copy_halt; + int should_halt = 0; - optv = read_opts(conn, buf); + buf = (char *)must_malloc("read_opts packet malloc", EVENT_BUFSZ); - prepare_mount_point(conn); + optv = read_opts(conn, buf); - for (optc = 0; optv[optc] != NULL; optc++) {} + prepare_mount_point(conn); - fuse = get_fuse_sock(conn, optc, optv); - free(buf); - free(optv); + for (optc = 0; optv[optc] != NULL; optc++) { + } - lock_init("copy_lock", ©_lock, NULL); - cond_init("copy_halt", ©_halt, NULL); + fuse = get_fuse_sock(conn, optc, optv); + free(buf); + free(optv); - start_reader(conn, fuse); - start_writer(conn, fuse); - start_notify(conn, fuse); + lock_init("copy_lock", ©_lock, NULL); + cond_init("copy_halt", ©_halt, NULL); - lock("copy lock", ©_lock); - while (!should_halt) - if ((errno = pthread_cond_wait(©_halt, ©_lock))) - die(1, conn->params, "", - "Couldn't wait for copy halt for mount %s: ", - conn->mount_point); - unlock("copy lock", ©_lock); + start_reader(conn, fuse); + start_writer(conn, fuse); + start_notify(conn, fuse); - free(conn); + lock("copy lock", ©_lock); + while (!should_halt) + errno = pthread_cond_wait(©_halt, ©_lock); + if (errno) + die(1, conn->params, "", + "Couldn't wait for copy halt for mount %s: ", + conn->mount_point); + unlock("copy lock", ©_lock); - return NULL; + free(conn); + + return NULL; } -void * mount_thread(void * connection) { - return mount_connection((connection_t *) connection); +void *mount_thread(void *connection) +{ + return mount_connection((connection_t *) connection); } -void write_pid(connection_t * connection) { - pid_t pid = gettid(); - char * pid_s; - int pid_s_len, write_count; +void write_pid(connection_t *connection) +{ + pid_t pid = gettid(); + char *pid_s; + int pid_s_len, write_count; - if (asprintf(&pid_s, "%lld", (long long) pid) == -1) - die(1, connection->params, "Couldn't allocate pid string", ""); + if (asprintf(&pid_s, "%lld", (long long)pid) == -1) + die(1, connection->params, "Couldn't allocate pid string", ""); - pid_s_len = strlen(pid_s); + pid_s_len = strlen(pid_s); - // TODO: check for socket write conditions e.g. EAGAIN - write_count = write(connection->sock, pid_s, pid_s_len); - if (write_count < 0) - die(1, connection->params, "Error writing pid", ""); + /* TODO: check for socket write conditions e.g.EAGAIN */ + write_count = write(connection->sock, pid_s, pid_s_len); + if (write_count < 0) + die(1, connection->params, "Error writing pid", ""); - // TODO: handle short writes - if (write_count != pid_s_len) - die(1, connection->params, NULL, - "Error writing pid %s to socket: only wrote %d bytes", - pid_s, write_count); + /* TODO: handle short writes */ + if (write_count != pid_s_len) + die(1, connection->params, NULL, + "Error writing pid %s to socket: only wrote %d bytes", + pid_s, write_count); - free(pid_s); + free(pid_s); } -void pong(parameters * params) { - char pong_msg[6] = { '\6', '\0', '\0', '\0', PONG_REPLY, '\0' }; +void pong(parameters *params) +{ + char pong_msg[6] = {'\6', '\0', '\0', '\0', PONG_REPLY, '\0'}; - write_exactly("pong reply", params->ctl_sock, pong_msg, 6); + write_exactly("pong reply", params->ctl_sock, pong_msg, 6); } -void perform_syscall(connection_t * conn, uint8_t syscall, char path[]) { - char * name; - int r = 0; +void perform_syscall(connection_t *conn, uint8_t syscall, char path[]) +{ + char *name; + int r = 0; - switch (syscall) { + switch (syscall) { - case PING: - pong(conn->params); - r = 0; - break; + case PING: + pong(conn->params); + r = 0; + break; - case RMDIR_SYSCALL: - name = "rmdir"; - r = rmdir(path); - break; + case RMDIR_SYSCALL: + name = "rmdir"; + r = rmdir(path); + break; - case UNLINK_SYSCALL: - name = "unlink"; - r = unlink(path); - break; + case UNLINK_SYSCALL: + name = "unlink"; + r = unlink(path); + break; - case MKDIR_SYSCALL: - name = "mkdir"; - r = mkdir(path, 00000); - break; + case MKDIR_SYSCALL: + name = "mkdir"; + r = mkdir(path, 00000); + break; - case SYMLINK_SYSCALL: - name = "symlink"; - r = symlink(".",path); - break; + case SYMLINK_SYSCALL: + name = "symlink"; + r = symlink(".", path); + break; - case MKNOD_REG_SYSCALL: - name = "mknod"; - r = mknod(path, 0600, 0); - break; + case MKNOD_REG_SYSCALL: + name = "mknod"; + r = mknod(path, 0600, 0); + break; - case TRUNCATE_SYSCALL: - name = "truncate"; - r = truncate(path, 0); - break; + case TRUNCATE_SYSCALL: + name = "truncate"; + r = truncate(path, 0); + break; - case CHMOD_SYSCALL: - name = "chmod"; - r = chmod(path, 0700); - break; + case CHMOD_SYSCALL: + name = "chmod"; + r = chmod(path, 0700); + break; - default: - die(1, conn->params, NULL, "Unknown event syscall %" PRIu8, syscall); - } + default: + die(1, conn->params, NULL, + "Unknown event syscall %" PRIu8, syscall); + } - if (r != 0) - thread_log_time(conn, "Event %s %s error: %s\n", - name, path, strerror(errno)); + if (r != 0) + thread_log_time(conn, "Event %s %s error: %s\n", + name, path, strerror(errno)); } -void * event_thread(void * connection_ptr) { - int read_count, path_len; - void * buf; - connection_t * connection = connection_ptr; +void * event_thread(void *connection_ptr) +{ + int read_count, path_len; + void *buf; + connection_t *connection = connection_ptr; - char * path; - uint8_t syscall; + char *path; + uint8_t syscall; - // This thread registers with the file system server as being an - // fsnotify event actuator. Other mounted file system interactions - // (such as self-logging) SHOULD NOT occur on this thread. + /* This thread registers with the file system server as being an + * fsnotify event actuator. Other mounted file system interactions + * (such as self-logging) SHOULD NOT occur on this thread. */ + write_pid(connection); - write_pid(connection); + buf = must_malloc("incoming event buffer", EVENT_BUFSZ); - buf = must_malloc("incoming event buffer", EVENT_BUFSZ); + while (1) { + read_count = read_message("events", connection->params, + connection->sock, buf, EVENT_BUFSZ); - while(1) { - read_count = read_message("events", connection->params, - connection->sock, buf, EVENT_BUFSZ); + if (debug) + thread_log_time(connection, + "read %d bytes from event connection\n", + read_count); - if (debug) - thread_log_time(connection, "read %d bytes from event connection\n", - read_count); + path_len = (int)ntohs(*(((uint32_t *) buf) + 1)); + /* TODO: could check the path length isn't a lie here */ + path = (char *)(((uint8_t *)buf) + 6); + /* TODO: could check the path is NULL terminated here */ + syscall = *(((uint8_t *)buf) + 6 + path_len); - path_len = (int) ntohs(*(((uint32_t *) buf) + 1)); - // TODO: could check the path length isn't a lie here - path = (char *) (((uint8_t *) buf) + 6); - // TODO: could check the path is NUL terminated here - syscall = *(((uint8_t *) buf) + 6 + path_len); + /* TODO: should this be in another thread ? */ + perform_syscall(connection, syscall, path); + } - // TODO: should this be in another thread? - perform_syscall(connection, syscall, path); - } - - free(buf); - // TODO: close connection - return NULL; + free(buf); + /* TODO: close connection */ + return NULL; } -void write_pidfile(parameters * params) { - int fd; - pid_t pid = getpid(); - char * pid_s; - int pid_s_len, write_count; +void write_pidfile(parameters *params) +{ + int fd; + pid_t pid = getpid(); + char *pid_s; + int pid_s_len, write_count; - if (asprintf(&pid_s, "%lld", (long long) pid) == -1) - die(1, params, "Couldn't allocate pidfile string", ""); + if (asprintf(&pid_s, "%lld", (long long)pid) == -1) + die(1, params, "Couldn't allocate pidfile string", ""); - pid_s_len = strlen(pid_s); + pid_s_len = strlen(pid_s); - fd = open(params->pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) - die(1, params, "", "Couldn't open pidfile path %s: ", params->pidfile); + fd = open(params->pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + die(1, params, "", + "Couldn't open pidfile path %s: ", params->pidfile); - write_count = write(fd, pid_s, pid_s_len); - if (write_count == -1) - die(1, params, "", "Error writing pidfile %s: ", params->pidfile); + write_count = write(fd, pid_s, pid_s_len); + if (write_count == -1) + die(1, params, "", + "Error writing pidfile %s: ", params->pidfile); - if (write_count != pid_s_len) - die(1, params, NULL, - "Error writing %s to pidfile %s: only wrote %d bytes", - pid_s, params->pidfile, write_count); + if (write_count != pid_s_len) + die(1, params, NULL, + "Error writing %s to pidfile %s: only wrote %d bytes", + pid_s, params->pidfile, write_count); - close(fd); - free(pid_s); + close(fd); + free(pid_s); } -// TODO: the message parsing here is rickety, do it properly -void * determine_mount_suitability(parameters * params, - int allow_empty, char * req, int len) { - void * buf = (void *) req; - uint16_t id = *((uint16_t *) buf); - uint16_t slen; - char * reply; - int roff; +/* TODO: the message parsing here is rickety, do it properly */ +void *determine_mount_suitability(parameters *params, int allow_empty, + char *req, int len) +{ + void *buf = (void *)req; + uint16_t id = *((uint16_t *) buf); + uint16_t slen; + char *reply; + int roff; - reply = (char *) must_malloc("determine_mount_suitability", len + 6); - *((uint16_t *)(reply + 4)) = MOUNT_SUITABILITY_REPLY; - *((uint16_t *)(reply + 6)) = id; - roff = 8; + reply = (char *)must_malloc("determine_mount_suitability", len + 6); + *((uint16_t *) (reply + 4)) = MOUNT_SUITABILITY_REPLY; + *((uint16_t *) (reply + 6)) = id; + roff = 8; - buf = (void *) ((char *) buf + 2); - len -= 2; - while (len) { - slen = *((uint16_t *) buf) + 1; - if (is_path_mountable(params, allow_empty, ((char *) buf) + 2)) { - slen = strlcpy(reply + roff + 2, ((char *) buf) + 2, slen) + 1; - *((uint16_t *) ((void *) (reply + roff))) = slen - 1; - roff += 2 + slen; - } - buf = (void *) ((char *) buf + 2 + slen); - len -= 2 + slen; - } + buf = (void *)((char *)buf + 2); + len -= 2; + while (len) { + slen = *((uint16_t *) buf) + 1; + if (is_path_mountable(params, allow_empty, ((char *)buf) + 2)) { + slen = strlcpy(reply + roff + 2, + ((char *)buf) + 2, slen) + 1; + *((uint16_t *)((void *)(reply + roff))) = slen - 1; + roff += 2 + slen; + } + buf = (void *)((char *)buf + 2 + slen); + len -= 2 + slen; + } - *((uint32_t *) ((void *) reply)) = roff; - return (void *) reply; + *((uint32_t *) ((void *)reply)) = roff; + return (void *)reply; } -void * init_thread(void * params_ptr) { - parameters * params = params_ptr; - int write_count, read_count, len; - char init_msg[6] = { '\6', '\0', '\0', '\0', '\0', '\0' }; - void * buf, * response; - uint16_t msg_type; +void *init_thread(void *params_ptr) +{ + parameters *params = params_ptr; + int write_count, read_count, len; + char init_msg[6] = {'\6', '\0', '\0', '\0', '\0', '\0'}; + void *buf, *response; + uint16_t msg_type; - params->ctl_sock = connect_socket(params->server); + params->ctl_sock = connect_socket(params->server); - // TODO: handle short write/socket conditions - write_count = write(params->ctl_sock, init_msg, sizeof(init_msg)); - if (write_count < 0) die(1, NULL, "init thread: couldn't write init", ""); - if (write_count != sizeof(init_msg)) - die(1, NULL, "init thread: incomplete write", ""); + /* TODO: handle short write/socket conditions */ + write_count = write(params->ctl_sock, init_msg, sizeof(init_msg)); + if (write_count < 0) + die(1, NULL, "init thread: couldn't write init", ""); + if (write_count != sizeof(init_msg)) + die(1, NULL, "init thread: incomplete write", ""); - buf = must_malloc("incoming control message buffer", CTL_BUFSZ); + buf = must_malloc("incoming control message buffer", CTL_BUFSZ); - // TODO: handle short read/socket conditions - read_count = read(params->ctl_sock, buf, 6); - if (read_count < 0) die(1, params, "init thread: error reading", ""); - // TODO: handle other messages - if (read_count != 6) die(1, params, NULL, "init thread: response not 6"); - for (int i = 0; i < sizeof(init_msg); i++) - if (((char *)buf)[i] != init_msg[i]) - die(1, params, NULL, "init thread: unexpected message"); + /* TODO: handle short read / socket conditions */ + read_count = read(params->ctl_sock, buf, 6); + if (read_count < 0) + die(1, params, "init thread: error reading", ""); + /* TODO: handle other messages */ + if (read_count != 6) + die(1, params, NULL, "init thread: response not 6"); + for (int i = 0; i < sizeof(init_msg); i++) + if (((char *)buf)[i] != init_msg[i]) + die(1, params, NULL, "init thread: unexpected message"); - // we've gotten Continue so write the pidfile - if (params->pidfile != NULL) - write_pidfile(params); + /* we've gotten Continue so write the pidfile */ + if (params->pidfile != NULL) + write_pidfile(params); - while (1) { - read_count = read_message("control", params, params->ctl_sock, - buf, CTL_BUFSZ); - msg_type = *((uint16_t *) buf + 2); - switch (msg_type) { - case MOUNT_SUITABILITY_REQUEST: - response = - determine_mount_suitability(params, 0, - (char *) buf + 6, read_count - 6); - len = *((size_t *) response); - write_exactly("init thread: mount suitability response", - params->ctl_sock, response, len); - free(response); - break; - case EXPORT_SUITABILITY_REQUEST: - response = - determine_mount_suitability(params, 1, - (char *) buf + 6, read_count - 6); - len = *((size_t *) response); - write_exactly("init thread: export suitability response", - params->ctl_sock, response, len); - free(response); - break; - default: - die(1, params, NULL, "init thread: unknown message %d", msg_type); - } - } + while (1) { + read_count = read_message("control", params, params->ctl_sock, + buf, CTL_BUFSZ); + msg_type = *((uint16_t *)buf + 2); + switch (msg_type) { + case MOUNT_SUITABILITY_REQUEST: + response = determine_mount_suitability(params, 0, + (char *)buf + 6, + read_count - 6); + len = *((size_t *) response); + write_exactly("init thread: mount suitability response", + params->ctl_sock, response, len); + free(response); + break; - free(buf); - return NULL; + case EXPORT_SUITABILITY_REQUEST: + response = determine_mount_suitability(params, 1, + (char *)buf + 6, + read_count - 6); + len = *((size_t *) response); + write_exactly("init thread: export suitability response", + params->ctl_sock, response, len); + free(response); + break; + + default: + die(1, params, NULL, + "init thread: unknown message %d", msg_type); + } + } + + free(buf); + return NULL; } -void toggle_debug(int sig) { - debug = !debug; +void toggle_debug(int sig) +{ + debug = !debug; } -void setup_debug() { - if (SIG_ERR == signal(SIGHUP, toggle_debug)) - die(1, NULL, "Couldn't set SIGHUP behavior", ""); +void setup_debug(void) +{ + if (signal(SIGHUP, toggle_debug) == SIG_ERR) + die(1, NULL, "Couldn't set SIGHUP behavior", ""); - if (siginterrupt(SIGHUP, 1)) - die(1, NULL, "Couldn't set siginterrupt for SIGHUP", ""); + if (siginterrupt(SIGHUP, 1)) + die(1, NULL, "Couldn't set siginterrupt for SIGHUP", ""); } -void parse_parameters(int argc, char * argv[], parameters * params) { - int c; - int errflg = 0; +void parse_parameters(int argc, char *argv[], parameters *params) +{ + int c; + int errflg = 0; - params->pidfile = NULL; - params->socket = NULL; - params->fusermount = NULL; - params->logfile = NULL; - params->logfile_fd = 0; - params->data_sock = 0; - params->ctl_sock = 0; - lock_init("ctl_lock", ¶ms->ctl_lock, NULL); + params->pidfile = NULL; + params->socket = NULL; + params->fusermount = NULL; + params->logfile = NULL; + params->logfile_fd = 0; + params->data_sock = 0; + params->ctl_sock = 0; + lock_init("ctl_lock", ¶ms->ctl_lock, NULL); - while ((c = getopt(argc, argv, ":p:d:s:f:l:")) != -1) { - switch(c) { + while ((c = getopt(argc, argv, ":p:d:s:f:l:")) != -1) { + switch (c) { - case 'p': - params->pidfile = optarg; - break; + case 'p': + params->pidfile = optarg; + break; - case 'd': - params->server = optarg; - break; + case 'd': + params->server = optarg; + break; - case 's': - params->socket = optarg; - break; + case 's': + params->socket = optarg; + break; - case 'f': - params->fusermount = optarg; - break; + case 'f': + params->fusermount = optarg; + break; - case 'l': - params->logfile = optarg; - break; + case 'l': + params->logfile = optarg; + break; - case ':': - fprintf(stderr, "Option -%c requires a path argument\n", optopt); - errflg++; - break; + case ':': + fprintf(stderr, "Option -%c requires a path argument\n", optopt); + errflg++; + break; - case '?': - fprintf(stderr, "Unrecognized option: '-%c'\n", optopt); - errflg++; - break; + case '?': + fprintf(stderr, "Unrecognized option: '-%c'\n", optopt); + errflg++; + break; - default: - fprintf(stderr, "Internal error parsing -%c\n", c); - errflg++; - } - } + default: + fprintf(stderr, "Internal error parsing -%c\n", c); + errflg++; + } + } - if (errflg) { - fprintf(stderr, "%s", usage); - exit(2); - } + if (errflg) { + fprintf(stderr, "%s", usage); + exit(2); + } + if (params->pidfile != NULL && access(params->pidfile, W_OK)) + if (errno != ENOENT) { + fprintf(stderr, "-p %s path to pidfile must be writable: ", + params->pidfile); + perror(""); + exit(2); + } + if (params->fusermount == NULL) + params->fusermount = default_fusermount; + if (access(params->fusermount, X_OK)) { + fprintf(stderr, "-f %s path to fusermount must be executable: ", + params->fusermount); + perror(""); + exit(2); + } + if (params->socket == NULL) + params->socket = default_socket; - if (params->pidfile != NULL && access(params->pidfile, W_OK)) - if (errno != ENOENT) { - fprintf(stderr, "-p %s path to pidfile must be writable: ", - params->pidfile); - perror(""); - exit(2); - } + if (params->server == NULL) + params->server = default_server; - if (params->fusermount == NULL) - params->fusermount = default_fusermount; - if (access(params->fusermount, X_OK)) { - fprintf(stderr, "-f %s path to fusermount must be executable: ", - params->fusermount); - perror(""); - exit(2); - } - - if (params->socket == NULL) - params->socket = default_socket; - - if (params->server == NULL) - params->server = default_server; - - if (params->logfile != NULL && access(params->logfile, W_OK)) - if (errno != ENOENT) { - fprintf(stderr, "-l %s path to logfile must be writable: ", - params->logfile); - perror(""); - exit(2); - } + if (params->logfile != NULL && access(params->logfile, W_OK)) + if (errno != ENOENT) { + fprintf(stderr, "-l %s path to logfile must be writable: ", + params->logfile); + perror(""); + exit(2); + } } -void serve(parameters * params) { - ssize_t read_count; - char subproto_selector; - pthread_t child; - connection_t * conn; - void * (*connection_handler_thread)(void *); +void serve(parameters *params) +{ + ssize_t read_count; + char subproto_selector; + pthread_t child; + connection_t *conn; + void *(*connection_handler_thread)(void *); - if (listen(params->data_sock, 16)) - die(1, NULL, "listen", ""); + if (listen(params->data_sock, 16)) + die(1, NULL, "listen", ""); - if ((errno = pthread_create(&child, &detached, init_thread, params))) - die(1, NULL, "", "Couldn't create initialization thread: "); + errno = pthread_create(&child, &detached, init_thread, params); + if (errno) + die(1, NULL, "", "Couldn't create initialization thread: "); - while (1) { - conn = (connection_t *) must_malloc("connection state", - sizeof(connection_t)); - conn->params = params; - conn->mount_point = ""; + while (1) { + conn = (connection_t *)must_malloc("connection state", + sizeof(connection_t)); + conn->params = params; + conn->mount_point = ""; - conn->sock = accept(params->data_sock, - &conn->sa_client, &conn->socklen_client); - if (conn->sock < 0) - die(1, params, "accept", ""); + conn->sock = accept(params->data_sock, + &conn->sa_client, &conn->socklen_client); + if (conn->sock < 0) + die(1, params, "accept", ""); - // TODO: check for socket read conditions e.g. EAGAIN - read_count = read(conn->sock, &subproto_selector, 1); - if (read_count <= 0) - die(1, params, "read subprotocol selector", ""); + /* TODO: check for socket read conditions e.g.EAGAIN */ + read_count = read(conn->sock, &subproto_selector, 1); + if (read_count <= 0) + die(1, params, "read subprotocol selector", ""); - switch (subproto_selector) { - case 'm': - conn->type_descr = "mount"; - connection_handler_thread = mount_thread; - break; - case 'e': - conn->type_descr = "event"; - connection_handler_thread = event_thread; - break; - default: - die(1, params, NULL, "Unknown subprotocol type '%c'", subproto_selector); - } + switch (subproto_selector) { + case 'm': + conn->type_descr = "mount"; + connection_handler_thread = mount_thread; + break; + case 'e': + conn->type_descr = "event"; + connection_handler_thread = event_thread; + break; + default: + die(1, params, NULL, + "Unknown subprotocol type '%c'", subproto_selector); + } - if ((errno = pthread_create(&child, &detached, - connection_handler_thread, conn))) - die(1, params, "", "Couldn't create thread for %s connection: ", - conn->type_descr); + errno = pthread_create(&child, &detached, + connection_handler_thread, conn); + if (errno) + die(1, params, "", + "Couldn't create thread for %s connection: ", + conn->type_descr); - if (debug) log_time(conn->params, "thread spawned\n"); - } + if (debug) + log_time(conn->params, "thread spawned\n"); + } } -int main(int argc, char * argv[]) { - parameters params; - struct rlimit core_limit; +int main(int argc, char *argv[]) +{ + parameters params; + struct rlimit core_limit; - core_limit.rlim_cur = RLIM_INFINITY; - core_limit.rlim_max = RLIM_INFINITY; - if (setrlimit(RLIMIT_CORE, &core_limit)) - die(1, NULL, "", "Couldn't set RLIMIT_CORE to RLIM_INFINITY"); + core_limit.rlim_cur = RLIM_INFINITY; + core_limit.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &core_limit)) + die(1, NULL, "", "Couldn't set RLIMIT_CORE to RLIM_INFINITY"); - openlog(argv[0], LOG_CONS | LOG_PERROR | LOG_NDELAY, LOG_DAEMON); + openlog(argv[0], LOG_CONS | LOG_PERROR | LOG_NDELAY, LOG_DAEMON); - parse_parameters(argc, argv, ¶ms); - setup_debug(); + parse_parameters(argc, argv, ¶ms); + setup_debug(); - if ((errno = pthread_attr_setdetachstate(&detached, - PTHREAD_CREATE_DETACHED))) - die(1, NULL, "Couldn't set pthread detach state", ""); + errno = pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED); + if (errno) + die(1, NULL, "Couldn't set pthread detach state", ""); - if (params.logfile != NULL) { - params.logfile_fd = open(params.logfile, O_WRONLY | O_APPEND | O_CREAT); - if (params.logfile_fd == -1) - die(1, NULL, "", "Couldn't open log file %s: ", params.logfile); - } + if (params.logfile != NULL) { + params.logfile_fd = open(params.logfile, + O_WRONLY | O_APPEND | O_CREAT); + if (params.logfile_fd == -1) + die(1, NULL, "", + "Couldn't open log file %s: ", params.logfile); + } + params.data_sock = bind_socket(params.socket); + serve(¶ms); - params.data_sock = bind_socket(params.socket); - serve(¶ms); - - return 0; + return 0; } diff --git a/alpine/packages/transfused/transfused.h b/alpine/packages/transfused/transfused.h index 8bce1d9df..ba979bf68 100644 --- a/alpine/packages/transfused/transfused.h +++ b/alpine/packages/transfused/transfused.h @@ -1,37 +1,9 @@ +#ifndef _TRANSFUSED_H_ +#define _TRANSFUSED_H_ + #include #include -typedef struct { - char * server; - char * socket; - char * fusermount; - char * pidfile; - char * logfile; - int logfile_fd; - int ctl_sock; - int data_sock; - pthread_mutex_t ctl_lock; -} parameters; - -typedef struct { - parameters * params; - char * type_descr; - char * mount_point; - struct sockaddr sa_client; - socklen_t socklen_client; - int sock; -} connection_t; - -pthread_attr_t detached; - -void * must_malloc(char *const descr, size_t size); - -void lock(char *const descr, pthread_mutex_t * mutex); - -void unlock(char *const descr, pthread_mutex_t * mutex); - -void write_exactly(char * descr, int fd, void * buf, size_t nbyte); - #define IN_BUFSZ ((1 << 20) + 16) #define OUT_BUFSZ ((1 << 20) + 64) #define EVENT_BUFSZ 4096 @@ -49,7 +21,7 @@ void write_exactly(char * descr, int fd, void * buf, size_t nbyte); #define TRUNCATE_SYSCALL 4 #define CHMOD_SYSCALL 5 #define MKNOD_REG_SYSCALL 6 -// these could be turned into an enum probably but... C standard nausea +/* these could be turned into an enum probably but...C standard nausea */ #define MOUNT_SUITABILITY_REQUEST 1 #define EXPORT_SUITABILITY_REQUEST 2 @@ -59,3 +31,33 @@ void write_exactly(char * descr, int fd, void * buf, size_t nbyte); #define PONG_REPLY 3 #define MOUNT_SUITABILITY_REPLY 4 #define TRANSFUSE_NOTIFY_CHANNEL 5 + +typedef struct { + char *server; + char *socket; + char *fusermount; + char *pidfile; + char *logfile; + int logfile_fd; + int ctl_sock; + int data_sock; + pthread_mutex_t ctl_lock; +} parameters; + +typedef struct { + parameters *params; + char *type_descr; + char *mount_point; + struct sockaddr sa_client; + socklen_t socklen_client; + int sock; +} connection_t; + +pthread_attr_t detached; + +void *must_malloc(char *const descr, size_t size); +void lock(char *const descr, pthread_mutex_t *mutex); +void unlock(char *const descr, pthread_mutex_t *mutex); +void write_exactly(char *descr, int fd, void *buf, size_t nbyte); + +#endif /* _TRANSFUSED_H_ */ diff --git a/alpine/packages/transfused/transfused_log.c b/alpine/packages/transfused/transfused_log.c index 9b104031f..287cfbaf9 100644 --- a/alpine/packages/transfused/transfused_log.c +++ b/alpine/packages/transfused/transfused_log.c @@ -15,232 +15,243 @@ #include #include "transfused.h" +#include "transfused_log.h" -void log_timestamp(int fd) { - char timestamp[26]; - int msec; - struct tm* tm_info; - struct timeval tv; - - gettimeofday(&tv, NULL); - - msec = lrint(tv.tv_usec/1000.0); - if (msec >= 1000) { - msec -= 1000; - tv.tv_sec++; - } - - tm_info = localtime(&tv.tv_sec); - - strftime(timestamp, 26, "%Y-%m-%d %H:%M:%S", tm_info); - dprintf(fd, "%s.%03d ", timestamp, msec); -} - -void die -(int exit_code, parameters * params, const char * parg, const char * fmt, ...); - -void vlog_sock_locked -(int fd, uint16_t msg_type, const char * fmt, va_list args) { - int rc, len; - va_list targs; - char * fill; - - va_copy(targs, args); - len = vsnprintf(NULL, 0, fmt, targs); - if (len < 0) die(1, NULL, NULL, "Couldn't log due to vsnprintf failure"); - va_end(targs); - - rc = len + 4 + 2; // 4 for length itself and 2 for message type - write_exactly("vlog_sock_locked", fd, (uint32_t *) &rc, sizeof(uint32_t)); - write_exactly("vlog_sock_locked", fd, &msg_type, sizeof(uint16_t)); - - va_copy(targs, args); - rc = vdprintf(fd, fmt, targs); - if (rc < 0) die(1, NULL, "Couldn't send log message with vdprintf", ""); - va_end(targs); - - if (rc < len) { // we didn't write the whole message :-( - rc = len - rc; - fill = (char *) calloc(rc, 1); - if (fill == NULL) die(1, NULL, "vlog_sock_locked fill", ""); - write_exactly("vlog_sock_locked fill", fd, fill, rc); - } -} - -void log_sock_locked(int fd, uint16_t msg_type, const char * fmt, ...) { - va_list args; - - va_start(args, fmt); - - vlog_sock_locked(fd, msg_type, fmt, args); - - va_end(args); -} - -void die -(int exit_code, parameters * params, const char * parg, const char * fmt, ...) +void log_timestamp(int fd) { - va_list argp, targs; - int in_errno = errno; - int fd = 0; + char timestamp[26]; + int msec; + struct tm *tm_info; + struct timeval tv; - if (params != NULL) { - fd = params->ctl_sock; - lock("die ctl_lock", ¶ms->ctl_lock); - } + gettimeofday(&tv, NULL); - va_start(argp, fmt); - va_copy(targs, argp); - vsyslog(LOG_CRIT, fmt, targs); - va_end(targs); + msec = lrint(tv.tv_usec / 1000.0); + if (msec >= 1000) { + msec -= 1000; + tv.tv_sec++; + } + tm_info = localtime(&tv.tv_sec); - if (fd != 0) vlog_sock_locked(fd, TRANSFUSE_LOG_ERROR, fmt, argp); - va_end(argp); - - if (parg != NULL) { - if (*parg != 0) { - syslog(LOG_CRIT, "%s: %s", parg, strerror(in_errno)); - if (fd != 0) - log_sock_locked(fd, TRANSFUSE_LOG_ERROR, - "%s: %s", parg, strerror(in_errno)); - } else { - syslog(LOG_CRIT, "%s", strerror(in_errno)); - if (fd != 0) - log_sock_locked(fd, TRANSFUSE_LOG_ERROR, "%s", strerror(in_errno)); - } - } - - if (fd != 0) close(fd); // flush - exit(exit_code); - // Nobody else should die before we terminate everything - unlock("die ctl_lock", ¶ms->ctl_lock); + strftime(timestamp, 26, "%Y-%m-%d %H:%M:%S", tm_info); + dprintf(fd, "%s.%03d ", timestamp, msec); } -void vlog_locked -(parameters * params, uint16_t msg_type, const char * fmt, va_list args) { - int rc; - int fd = params->ctl_sock; - va_list targs; +void vlog_sock_locked(int fd, uint16_t msg_type, const char *fmt, va_list args) +{ + int rc, len; + va_list targs; + char *fill; - if (fd != 0) vlog_sock_locked(fd, msg_type, fmt, args); - else { - va_copy(targs, args); - // TODO: translate msg_type to syslog message type - vsyslog(LOG_INFO, fmt, targs); - va_end(targs); + va_copy(targs, args); + len = vsnprintf(NULL, 0, fmt, targs); + if (len < 0) + die(1, NULL, NULL, "Couldn't log due to vsnprintf failure"); + va_end(targs); - fd = params->logfile_fd; - if (fd != 0) { - va_copy(targs, args); - // TODO: include message type? - rc = vdprintf(fd, fmt, targs); - if (rc < 0) die(1, NULL, "Couldn't write log message with vdprintf", ""); - va_end(targs); - } - } + /* 4 for length itself and 2 for message type */ + rc = len + 4 + 2; + write_exactly("vlog_sock_locked", fd, + (uint32_t *)&rc, sizeof(uint32_t)); + write_exactly("vlog_sock_locked", fd, &msg_type, sizeof(uint16_t)); + + va_copy(targs, args); + rc = vdprintf(fd, fmt, targs); + if (rc < 0) + die(1, NULL, "Couldn't send log message with vdprintf", ""); + va_end(targs); + + if (rc < len) { + /* we didn't write the whole message :-( */ + rc = len - rc; + fill = (char *)calloc(rc, 1); + if (fill == NULL) + die(1, NULL, "vlog_sock_locked fill", ""); + write_exactly("vlog_sock_locked fill", fd, fill, rc); + } } -void vlog_time_locked -(parameters * params, uint16_t msg_type, const char * fmt, va_list args) { - int fd = params->logfile_fd; +void log_sock_locked(int fd, uint16_t msg_type, const char *fmt, ...) +{ + va_list args; - if (fd != 0 && params->ctl_sock == 0) log_timestamp(fd); - vlog_locked(params, msg_type, fmt, args); + va_start(args, fmt); + vlog_sock_locked(fd, msg_type, fmt, args); + va_end(args); } -void log_time_locked -(parameters * params, uint16_t msg_type, const char * fmt, ...) { - va_list args; +void die(int exit_code, parameters *params, const char *parg, + const char *fmt, ...) +{ + va_list argp, targs; + int in_errno = errno; + int fd = 0; - va_start(args, fmt); + if (params != NULL) { + fd = params->ctl_sock; + lock("die ctl_lock", ¶ms->ctl_lock); + } - vlog_time_locked(params, msg_type, fmt, args); + va_start(argp, fmt); + va_copy(targs, argp); + vsyslog(LOG_CRIT, fmt, targs); + va_end(targs); - va_end(args); + if (fd != 0) + vlog_sock_locked(fd, TRANSFUSE_LOG_ERROR, fmt, argp); + va_end(argp); + + if (parg != NULL) { + if (*parg != 0) { + syslog(LOG_CRIT, "%s: %s", parg, strerror(in_errno)); + if (fd != 0) + log_sock_locked(fd, TRANSFUSE_LOG_ERROR, + "%s: %s", parg, strerror(in_errno)); + } else { + syslog(LOG_CRIT, "%s", strerror(in_errno)); + if (fd != 0) + log_sock_locked(fd, TRANSFUSE_LOG_ERROR, + "%s", strerror(in_errno)); + } + } + if (fd != 0) + close(fd); /* flush */ + exit(exit_code); + /* Nobody else should die before we terminate everything */ + unlock("die ctl_lock", ¶ms->ctl_lock); } -void log_time(parameters * params, const char * fmt, ...) { - va_list args; +void vlog_locked(parameters *params, uint16_t msg_type, + const char *fmt, va_list args) +{ + int rc; + int fd = params->ctl_sock; + va_list targs; - va_start(args, fmt); + if (fd != 0) { + vlog_sock_locked(fd, msg_type, fmt, args); + } else { + va_copy(targs, args); + /* TODO: translate msg_type to syslog message type */ + vsyslog(LOG_INFO, fmt, targs); + va_end(targs); - lock("log_time ctl_lock", ¶ms->ctl_lock); - vlog_time_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); - unlock("log_time ctl_lock", ¶ms->ctl_lock); - - va_end(args); + fd = params->logfile_fd; + if (fd != 0) { + va_copy(targs, args); + /* TODO: include message type? */ + rc = vdprintf(fd, fmt, targs); + if (rc < 0) + die(1, NULL, + "Couldn't write log message with vdprintf", ""); + va_end(targs); + } + } } -void log_notice_time(parameters * params, const char * fmt, ...) { - va_list args; +void vlog_time_locked(parameters *params, uint16_t msg_type, + const char *fmt, va_list args) +{ + int fd = params->logfile_fd; - va_start(args, fmt); + if (fd != 0 && params->ctl_sock == 0) + log_timestamp(fd); + vlog_locked(params, msg_type, fmt, args); +} - lock("log_time ctl_lock", ¶ms->ctl_lock); - vlog_time_locked(params, TRANSFUSE_LOG_NOTICE, fmt, args); - unlock("log_time ctl_lock", ¶ms->ctl_lock); +void log_time_locked(parameters *params, uint16_t msg_type, + const char *fmt, ...) +{ + va_list args; - va_end(args); + va_start(args, fmt); + vlog_time_locked(params, msg_type, fmt, args); + va_end(args); +} + +void log_time(parameters *params, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + lock("log_time ctl_lock", ¶ms->ctl_lock); + vlog_time_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); + unlock("log_time ctl_lock", ¶ms->ctl_lock); + va_end(args); +} + +void log_notice_time(parameters *params, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + lock("log_time ctl_lock", ¶ms->ctl_lock); + vlog_time_locked(params, TRANSFUSE_LOG_NOTICE, fmt, args); + unlock("log_time ctl_lock", ¶ms->ctl_lock); + + va_end(args); } typedef struct { - parameters * params; - char * msg; + parameters *params; + char *msg; } log_thread_state; -void * log_time_thread(void * log_state_ptr) { - log_thread_state * log_state = log_state_ptr; +void *log_time_thread(void *log_state_ptr) +{ + log_thread_state *log_state = log_state_ptr; - log_time(log_state->params, log_state->msg); + log_time(log_state->params, log_state->msg); - free(log_state->msg); - free(log_state); - - return NULL; + free(log_state->msg); + free(log_state); + return NULL; } -void thread_log_time(connection_t * conn, const char * fmt, ...) { - pthread_t logger; - va_list args; - log_thread_state * log_state; +void thread_log_time(connection_t *conn, const char *fmt, ...) +{ + log_thread_state *log_state; + pthread_t logger; + va_list args; - log_state = must_malloc("thread_log_time log_state", - sizeof(log_thread_state)); - log_state->params = conn->params; + log_state = must_malloc("thread_log_time log_state", + sizeof(log_thread_state)); + log_state->params = conn->params; - va_start(args, fmt); - if (vasprintf(&log_state->msg, fmt, args) == -1) - die(1, conn->params, "Couldn't allocate thread_log_time message", ""); - va_end(args); + va_start(args, fmt); + if (vasprintf(&log_state->msg, fmt, args) == -1) + die(1, conn->params, + "Couldn't allocate thread_log_time message", ""); + va_end(args); - // TODO: We currently spawn a new thread for every message. This is - // far from ideal but fine for now as we anticipate thread-sensitive - // log demand to be low. - - if ((errno = pthread_create(&logger, &detached, log_time_thread, log_state))) - die(1, conn->params, "", - "Couldn't create log thread for %s connection %s: ", - conn->type_descr, conn->mount_point); + /* TODO: We currently spawn a new thread for every + * message. This is far from ideal but fine for now as we + * anticipate thread-sensitive log demand to be low. */ + errno = pthread_create(&logger, &detached, log_time_thread, log_state); + if (errno) + die(1, conn->params, "", + "Couldn't create log thread for %s connection %s: ", + conn->type_descr, conn->mount_point); } -void log_continue_locked(parameters * params, const char * fmt, ...) { - va_list args; +void log_continue_locked(parameters *params, const char *fmt, ...) +{ + va_list args; - va_start(args, fmt); - - vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); - - va_end(args); + va_start(args, fmt); + vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); + va_end(args); } -void log_continue(parameters * params, const char * fmt, ...) { - va_list args; +void log_continue(parameters *params, const char *fmt, ...) +{ + va_list args; - va_start(args, fmt); + va_start(args, fmt); - lock("log_continue ctl_lock", ¶ms->ctl_lock); - vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); - unlock("log_continue ctl_lock", ¶ms->ctl_lock); + lock("log_continue ctl_lock", ¶ms->ctl_lock); + vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args); + unlock("log_continue ctl_lock", ¶ms->ctl_lock); - va_end(args); + va_end(args); } diff --git a/alpine/packages/transfused/transfused_log.h b/alpine/packages/transfused/transfused_log.h index ab146d30e..e2176a1e4 100644 --- a/alpine/packages/transfused/transfused_log.h +++ b/alpine/packages/transfused/transfused_log.h @@ -1,27 +1,26 @@ +#ifndef _TRANSFUSED_LOG_H_ +#define _TRANSFUSED_LOG_H_ + #include #include #include "transfused.h" -void die -(int exit_code, parameters * params, const char * perror_arg, - const char * fmt, ...); +void die(int exit_code, parameters *params, const char *perror_arg, + const char *fmt, ...); -void vlog_locked -(parameters * params, uint16_t msg_type, const char * fmt, va_list args); +void vlog_locked(parameters *params, uint16_t msg_type, + const char *fmt, va_list args); +void vlog_time_locked(parameters *params, uint16_t msg_type, + const char *fmt, va_list args); -void vlog_time_locked -(parameters * params, uint16_t msg_type, const char * fmt, va_list args); +void log_time_locked(parameters *params, uint16_t msg_type, + const char *fmt, ...); -void log_time_locked -(parameters * params, uint16_t msg_type, const char * fmt, ...); +void log_time(parameters *params, const char *fmt, ...); +void log_notice_time(parameters *params, const char *fmt, ...); +void thread_log_time(connection_t *conn, const char *fmt, ...); +void log_continue_locked(parameters *params, const char *fmt, ...); +void log_continue(parameters *params, const char *fmt, ...); -void log_time(parameters * params, const char * fmt, ...); - -void log_notice_time(parameters * params, const char * fmt, ...); - -void thread_log_time(connection_t * conn, const char * fmt, ...); - -void log_continue_locked(parameters * params, const char * fmt, ...); - -void log_continue(parameters * params, const char * fmt, ...); +#endif /* _TRANSFUSED_LOG_H_ */ diff --git a/alpine/packages/transfused/transfused_vsock.c b/alpine/packages/transfused/transfused_vsock.c index 08408dd0e..04cdce6da 100644 --- a/alpine/packages/transfused/transfused_vsock.c +++ b/alpine/packages/transfused/transfused_vsock.c @@ -7,93 +7,100 @@ #include "transfused_log.h" -long parse_cid(const char * address) { - char * end = NULL; - long cid = strtol(address, &end, 10); - if (address == end || *end != ':') { - *end = 0; - die(2, NULL, NULL, "Invalid vsock cid: %s", address); - } - return cid; +long parse_cid(const char *address) +{ + char *end = NULL; + long cid = strtol(address, &end, 10); + + if (address == end || *end != ':') { + *end = 0; + die(2, NULL, NULL, "Invalid vsock cid: %s", address); + } + return cid; } -long parse_port(const char * port_str) { - char * end = NULL; - long port = strtol(port_str, &end, 10); - if (port_str == end || *end != '\0') { - *end = 0; - die(2, NULL, NULL, "Invalid vsock port: %s", port_str); - } - return port; +long parse_port(const char *port_str) +{ + char *end = NULL; + long port = strtol(port_str, &end, 10); + + if (port_str == end || *end != '\0') { + *end = 0; + die(2, NULL, NULL, "Invalid vsock port: %s", port_str); + } + return port; } -int find_colon(const char * address) { - int colon = 0; +int find_colon(const char *address) +{ + int colon = 0; - while (address[colon] != '\0') - if (address[colon] == ':') break; - else colon++; + while (address[colon] != '\0') + if (address[colon] == ':') + break; + else + colon++; - if (address[colon] == '\0') - die(2, NULL, NULL, "Missing port in vsock address %s", address); + if (address[colon] == '\0') + die(2, NULL, NULL, "Missing port in vsock address %s", address); - return colon; + return colon; } -int bind_vsock(const char * address) { - long cid, port; - int colon; +int bind_vsock(const char *address) +{ + long cid, port; + int colon; + struct sockaddr_vm sa_listen = { + .svm_family = AF_VSOCK, + }; + int sock_fd; - struct sockaddr_vm sa_listen = { - .svm_family = AF_VSOCK, - }; + colon = find_colon(address); - int sock_fd; + if (address[0] == '_' && colon == 1) + cid = VMADDR_CID_ANY; + else + cid = parse_cid(address); - colon = find_colon(address); + port = parse_port(address + colon + 1); - if (address[0] == '_' && colon == 1) cid = VMADDR_CID_ANY; - else cid = parse_cid(address); + sa_listen.svm_cid = cid; + sa_listen.svm_port = port; - port = parse_port(address + colon + 1); + sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (sock_fd < 0) + die(1, NULL, "socket(AF_VSOCK)", ""); - sa_listen.svm_cid = cid; - sa_listen.svm_port = port; + if (bind(sock_fd, (struct sockaddr *)&sa_listen, sizeof(sa_listen))) + die(1, NULL, "bind(AF_VSOCK)", ""); - sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0); - if (sock_fd < 0) - die(1, NULL, "socket(AF_VSOCK)", ""); - - if (bind(sock_fd, (struct sockaddr *) &sa_listen, sizeof(sa_listen))) - die(1, NULL, "bind(AF_VSOCK)", ""); - - return sock_fd; + return sock_fd; } -int connect_vsock(const char * address) { - long cid, port; - int colon; +int connect_vsock(const char *address) +{ + long cid, port; + int colon; + struct sockaddr_vm sa_connect = { + .svm_family = AF_VSOCK, + }; + int sock_fd; - struct sockaddr_vm sa_connect = { - .svm_family = AF_VSOCK, - }; + colon = find_colon(address); - int sock_fd; + cid = parse_cid(address); + port = parse_port(address + colon + 1); - colon = find_colon(address); + sa_connect.svm_cid = cid; + sa_connect.svm_port = port; - cid = parse_cid(address); - port = parse_port(address + colon + 1); + sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (sock_fd < 0) + die(1, NULL, "socket(AF_VSOCK)", ""); - sa_connect.svm_cid = cid; - sa_connect.svm_port = port; + if (connect(sock_fd, (struct sockaddr *)&sa_connect, sizeof(sa_connect))) + die(1, NULL, "connect(AF_VSOCK)", ""); - sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0); - if (sock_fd < 0) - die(1, NULL, "socket(AF_VSOCK)", ""); - - if (connect(sock_fd, (struct sockaddr *) &sa_connect, sizeof(sa_connect))) - die(1, NULL, "connect(AF_VSOCK)", ""); - - return sock_fd; + return sock_fd; } diff --git a/alpine/packages/transfused/transfused_vsock.h b/alpine/packages/transfused/transfused_vsock.h index a6bef6f08..6be8979e4 100644 --- a/alpine/packages/transfused/transfused_vsock.h +++ b/alpine/packages/transfused/transfused_vsock.h @@ -1,2 +1,7 @@ -int bind_vsock(const char * address); -int connect_vsock(const char * address); +#ifndef _TRANSFUSED_VSOCK_H_ +#define _TRANSFUSED_VSOCK_H_ + +int bind_vsock(const char *address); +int connect_vsock(const char *address); + +#endif /* _TRANSFUSED_VSOCK_H_ */ diff --git a/docs/coding-style.md b/docs/coding-style.md new file mode 100644 index 000000000..6e42d7dda --- /dev/null +++ b/docs/coding-style.md @@ -0,0 +1,15 @@ +## Shell scripts +Shell scripts should loosely follow the general Alpine style which is derived from the Linux Kernel guidelines, i.e. tabs for indentation etc. + +It's also useful to run `shellcheck` on the scripts. + +## Go code +New Go code should be formatted with `gofmt` + +## C code +C code written from scratch should follow the +[Linux kernel coding guidelines](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/CodingStyle) +as much as it makes sense for userspace code. You can check your code with [checkpatch.pl](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/scripts/checkpatch.pl) like this: +``` +checkpatch.pl --no-tree --file +```