transfused: address @yallop's comments

This commit is contained in:
David Sheets 2016-02-10 17:09:11 +00:00
parent 1efc36a38c
commit 7ab2f3816c

View File

@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -40,14 +41,20 @@ typedef struct {
char * fusermount = "fusermount"; char * fusermount = "fusermount";
void die(int exit_code, const char * perror_arg, const char * fmt, ...) {
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
if (perror_arg != NULL) perror(perror_arg);
exit(exit_code);
}
void * must_malloc(char *const descr, size_t size) { void * must_malloc(char *const descr, size_t size) {
void * ptr; void * ptr;
ptr = malloc(size); ptr = malloc(size);
if (size != 0 && ptr == NULL) { if (size != 0 && ptr == NULL) die(1,descr,"");
perror(descr);
exit(1);
}
return ptr; return ptr;
} }
@ -60,30 +67,23 @@ char ** read_opts(connection_state * connection, char * buf) {
char ** optv; char ** optv;
if (asprintf(&read_path, "%s/connections/%ld/read", if (asprintf(&read_path, "%s/connections/%ld/read",
connection->params->socket9p_root, connection->id) == -1) { connection->params->socket9p_root, connection->id) == -1)
fprintf(stderr, "Couldn't allocate read path\n"); die(1,"Couldn't allocate read path","");
exit(1);
}
read_fd = open(read_path, O_RDONLY); read_fd = open(read_path, O_RDONLY);
if (read_fd == -1) { if (read_fd == -1)
fprintf(stderr, "For connection %ld, ", connection->id); die(1,"couldn't open read path", "For connection %ld, ", connection->id);
perror("couldn't open read path");
exit(1);
}
read_count = read(read_fd, buf, COPY_BUFSZ - 1); read_count = read(read_fd, buf, COPY_BUFSZ - 1);
if (read_count == -1) { if (read_count == -1) die(1,"read_opts error reading", "");
perror("read_opts error reading");
exit(1);
}
buf[read_count] = 0x0; buf[read_count] = 0x0;
for (int i = 0; i < read_count; i++) { for (int i = 0; i < read_count; i++) {
if (buf[i] == 0x0) optc++; if (buf[i] == 0x0) optc++;
} }
optv = must_malloc("read_opts optv", (optc + 1) * sizeof(void *)); optv = (char **) must_malloc("read_opts optv", (optc + 1) * sizeof(void *));
optv[0] = buf; optv[0] = buf;
optv[optc] = 0x0; optv[optc] = 0x0;
@ -100,28 +100,24 @@ char ** read_opts(connection_state * connection, char * buf) {
return optv; return optv;
} }
uint64_t message_id(char * message) { uint64_t message_id(uint64_t * message) {
return *((uint64_t *) (message + 8)); return message[1];
} }
int copy(copy_thread_state * copy_state) { void copy(copy_thread_state * copy_state) {
int from = copy_state->from; int from = copy_state->from;
int to = copy_state->to; int to = copy_state->to;
char * descr = copy_state->descr; char * descr = copy_state->descr;
int read_count, write_count; int read_count, write_count;
long connection = copy_state->connection; long connection = copy_state->connection;
char * tag = copy_state->tag; char * tag = copy_state->tag;
char * buf; void * buf;
buf = must_malloc(descr, COPY_BUFSZ); buf = must_malloc(descr, COPY_BUFSZ);
while(1) { while(1) {
read_count = read(from, buf, COPY_BUFSZ); read_count = read(from, buf, COPY_BUFSZ);
if (read_count == -1) { if (read_count == -1) die(1, "", "copy %s: error reading: ", descr);
fprintf(stderr, "copy %s: error reading ", descr);
perror("");
exit(1);
}
if (save_trace) { if (save_trace) {
int trace_fd; int trace_fd;
@ -137,51 +133,42 @@ int copy(copy_thread_state * copy_state) {
} }
write_count = write(to, buf, read_count); write_count = write(to, buf, read_count);
if (write_count == -1) { if (write_count == -1) die(1, "", "copy %s: error writing: ", descr);
fprintf(stderr, "copy %s: error writing ", descr);
perror("");
exit(1);
}
if (write_count != read_count) { if (write_count != read_count)
fprintf(stderr, "copy %s: read %d but only wrote %d\n", die(1, NULL, "copy %s: read %d by only wrote %d\n",
descr, read_count, write_count); descr, read_count, write_count);
exit(1);
}
} }
free(buf); free(buf);
return 0;
} }
int copy_clean_from(copy_thread_state * copy_state) { void * copy_clean_from(copy_thread_state * copy_state) {
int ret = copy(copy_state); copy(copy_state);
if (close(copy_state->from)) { if (close(copy_state->from))
fprintf(stderr, "For %s, ", copy_state->descr); die(1, "couldn't close read fd", "For %s, ", copy_state->descr);
perror("couldn't close read fd");
exit(1);
}
free(copy_state->descr); free(copy_state->descr);
free(copy_state); free(copy_state);
return ret; return NULL;
} }
int copy_clean_to(copy_thread_state * copy_state) { void * copy_clean_from_thread(void * copy_state) {
int ret = copy(copy_state); return (copy_clean_from((copy_thread_state *) copy_state));
}
if (close(copy_state->to)) { void * copy_clean_to(copy_thread_state * copy_state) {
fprintf(stderr, "For %s, ", copy_state->descr); copy(copy_state);
perror("couldn't close write fd");
exit(1); if (close(copy_state->to))
} die(1, "couldn't close write fd", "For %s, ", copy_state->descr);
free(copy_state->descr); free(copy_state->descr);
free(copy_state); free(copy_state);
return ret; return NULL;
} }
int recv_fd(int sock) { int recv_fd(int sock) {
@ -207,17 +194,12 @@ int recv_fd(int sock) {
ret = recvmsg(sock, &msg, 0); ret = recvmsg(sock, &msg, 0);
if (ret == -1) { if (ret == -1) die(1,"recvmsg","");
perror("recvmsg");
exit(1);
}
if (ret > 0 && msg.msg_controllen > 0) { if (ret > 0 && msg.msg_controllen > 0) {
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg->cmsg_level == SOL_SOCKET && (cmsg->cmsg_type == SCM_RIGHTS)) { if (cmsg->cmsg_level == SOL_SOCKET && (cmsg->cmsg_type == SCM_RIGHTS)) {
fd = *(int*)CMSG_DATA(cmsg); fd = *(int*)CMSG_DATA(cmsg);
} else {
fprintf(stderr, "recvmsg: failed to receive an fd\n");
} }
} }
@ -237,134 +219,101 @@ int get_fuse_sock(char *const optv[]) {
// prepare argv from optv // prepare argv from optv
for (optc = 0; optv[optc] != NULL; optc++) {} for (optc = 0; optv[optc] != NULL; optc++) {}
argv = must_malloc("fusermount argv",(optc + 2) * sizeof(char *)); argv = (char **) must_malloc("fusermount argv",(optc + 2) * sizeof(char *));
argv[0] = fusermount; argv[0] = fusermount;
memcpy(&argv[1], optv, (optc + 1) * sizeof(char *)); memcpy(&argv[1], optv, (optc + 1) * sizeof(char *));
// make the socket over which we'll be sent the FUSE socket fd // make the socket over which we'll be sent the FUSE socket fd
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fuse_socks)) { if (socketpair(PF_UNIX, SOCK_STREAM, 0, fuse_socks))
perror("Couldn't create FUSE socketpair"); die(1, "Couldn't create FUSE socketpair", "");
exit(1);
}
// prepare to exec the suid binary fusermount // prepare to exec the suid binary fusermount
if (asprintf(&envp[0], "_FUSE_COMMFD=%d", fuse_socks[0]) == -1) { if (asprintf(&envp[0], "_FUSE_COMMFD=%d", fuse_socks[0]) == -1)
fprintf(stderr, "Couldn't allocate fusermount envp\n"); die(1, "", "Couldn't allocate fusermount envp");
exit(1);
}
envp[1] = 0x0; envp[1] = 0x0;
// fork and exec fusermount // fork and exec fusermount
fusermount_pid = fork(); fusermount_pid = fork();
if (!fusermount_pid) { // child if (!fusermount_pid) // child
if (execvpe(fusermount, argv, envp)) { if (execvpe(fusermount, argv, envp))
perror("Failed to execute fusermount"); die(1, "Failed to execute fusermount", "");
exit(1);
}
}
// parent // parent
free(argv); free(argv);
free(envp[0]); free(envp[0]);
// close the end of the socket that we gave away // close the end of the socket that we gave away
if (close(fuse_socks[0])) { if (close(fuse_socks[0]))
perror("Couldn't close unneeded fusermount socket"); die(1, "Couldn't close unneeded fusermount socket", "");
exit(1);
}
// wait for fusermount to return // wait for fusermount to return
waitpid(fusermount_pid, &status, 0); waitpid(fusermount_pid, &status, 0);
if (!WIFEXITED(status)) { if (!WIFEXITED(status))
fprintf(stderr, "fusermount terminated abnormally\n"); die(1, NULL, "fusermount terminated abnormally\n");
exit(1);
} if (WEXITSTATUS(status))
if (WEXITSTATUS(status)) { die(1, NULL, "fusermount exited with code %d\n", WEXITSTATUS(status));
fprintf(stderr, "fusermount exited with code %d\n", WEXITSTATUS(status));
exit(1);
}
if (debug) fprintf(stderr, "about to recv_fd from fusermount\n"); if (debug) fprintf(stderr, "about to recv_fd from fusermount\n");
fd = recv_fd(fuse_socks[1]); fd = recv_fd(fuse_socks[1]);
if (fd == -1) { if (fd == -1)
fprintf(stderr, "Couldn't receive fd over FUSE socket\n"); die(1, NULL, "Couldn't receive fd over FUSE socket\n");
exit(1);
}
// close the read end of the socket // close the read end of the socket
if (close(fuse_socks[1])) { if (close(fuse_socks[1]))
perror("Couldn't close fusermount read socket"); die(1, "Couldn't close fusermount read socket", "");
exit(1);
}
return fd; return fd;
} }
int start_reader(connection_state * connection, int fuse) { void start_reader(connection_state * connection, int fuse) {
int read_fd; int read_fd;
char * read_path; char * read_path;
pthread_t child; pthread_t child;
copy_thread_state * copy_state; copy_thread_state * copy_state;
void *(*copy_clean)(void *) = (void *(*)(void *)) copy_clean_from;
if (asprintf(&read_path, "%s/connections/%ld/read", if (asprintf(&read_path, "%s/connections/%ld/read",
connection->params->socket9p_root, connection->id) == -1) { connection->params->socket9p_root, connection->id) == -1)
fprintf(stderr, "Couldn't allocate read path\n"); die(1, "", "Couldn't allocate read path: ");
exit(1);
}
read_fd = open(read_path, O_RDONLY); read_fd = open(read_path, O_RDONLY);
if (read_fd == -1) { if (read_fd == -1)
fprintf(stderr, "For connection %ld, ", connection->id); die(1, "couldn't open read path", "For connection %ld, ", connection->id);
perror("couldn't open read path");
exit(1);
}
copy_state = must_malloc("start_reader copy_state", copy_state = (copy_thread_state *) must_malloc("start_reader copy_state",
sizeof(copy_thread_state)); sizeof(copy_thread_state));
copy_state->descr = read_path; copy_state->descr = read_path;
copy_state->connection = connection->id; copy_state->connection = connection->id;
copy_state->tag = "read"; copy_state->tag = "read";
copy_state->from = read_fd; copy_state->from = read_fd;
copy_state->to = fuse; copy_state->to = fuse;
if ((errno = pthread_create(&child, NULL, copy_clean, copy_state))) { if ((errno = pthread_create(&child, NULL,
fprintf(stderr, "couldn't create read copy thread for connection %ld ", copy_clean_from_thread, copy_state)))
die(1, "", "couldn't create read copy thread for connection %ld: ",
connection->id); connection->id);
perror("");
exit(1);
}
if ((errno = pthread_detach(child))) { if ((errno = pthread_detach(child)))
fprintf(stderr, "couldn't detach read copy thread for connection '%ld' ", die (1, "", "couldn't detach read copy thread for connection '%ld': ",
connection->id); connection->id);
perror("");
exit(1);
}
return 0;
} }
int start_writer(connection_state * connection, int fuse) { void do_write(connection_state * connection, int fuse) {
int write_fd; int write_fd;
char * write_path; char * write_path;
copy_thread_state * copy_state; copy_thread_state * copy_state;
if (asprintf(&write_path, "%s/connections/%ld/write", if (asprintf(&write_path, "%s/connections/%ld/write",
connection->params->socket9p_root, connection->id) == -1) { connection->params->socket9p_root, connection->id) == -1)
fprintf(stderr, "Couldn't allocate write path\n"); die(1, "", "Couldn't allocate write path: ");
exit(1);
}
write_fd = open(write_path, O_WRONLY); write_fd = open(write_path, O_WRONLY);
if (write_fd == -1) { if (write_fd == -1)
fprintf(stderr, "For connection %ld, ", connection->id); die(1, "couldn't open write path", "For connection %ld, ", connection->id);
perror("couldn't open write path");
exit(1);
}
copy_state = must_malloc("start_writer copy_state", copy_state = (copy_thread_state *) must_malloc("do_write copy_state",
sizeof(copy_thread_state)); sizeof(copy_thread_state));
copy_state->descr = write_path; copy_state->descr = write_path;
copy_state->connection = connection->id; copy_state->connection = connection->id;
@ -372,17 +321,14 @@ int start_writer(connection_state * connection, int fuse) {
copy_state->from = fuse; copy_state->from = fuse;
copy_state->to = write_fd; copy_state->to = write_fd;
copy_clean_to(copy_state); copy_clean_to(copy_state);
return 0;
} }
int handle_connection(connection_state * connection) { void * handle_connection(connection_state * connection) {
char ** optv; char ** optv;
int fuse; int fuse;
char * buf; char * buf;
int ret;
buf = must_malloc("read_opts packet malloc", COPY_BUFSZ); buf = (char *) must_malloc("read_opts packet malloc", COPY_BUFSZ);
optv = read_opts(connection, buf); optv = read_opts(connection, buf);
fuse = get_fuse_sock(optv); fuse = get_fuse_sock(optv);
@ -390,10 +336,14 @@ int handle_connection(connection_state * connection) {
free(buf); free(buf);
start_reader(connection, fuse); start_reader(connection, fuse);
ret = start_writer(connection, fuse); do_write(connection, fuse);
free(connection); free(connection);
return ret; return NULL;
}
void * handle_connection_thread(void * connection) {
return handle_connection((connection_state *) connection);
} }
void toggle_save_trace(int sig) { void toggle_save_trace(int sig) {
@ -403,15 +353,11 @@ void toggle_save_trace(int sig) {
void setup_save_trace() { void setup_save_trace() {
save_trace = 0; save_trace = 0;
if (SIG_ERR == signal(SIGHUP, toggle_save_trace)) { if (SIG_ERR == signal(SIGHUP, toggle_save_trace))
perror("Couldn't set SIGHUP behavior"); die(1, "Couldn't set SIGHUP behavior", "");
exit(1);
}
if (siginterrupt(SIGHUP, 1)) { if (siginterrupt(SIGHUP, 1))
perror("Couldn't set siginterrupt for SIGHUP"); die(1, "Couldn't set siginterrupt for SIGHUP", "");
exit(1);
}
} }
#define ID_LEN 512 #define ID_LEN 512
@ -419,11 +365,10 @@ void setup_save_trace() {
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
int events, read_count; int events, read_count;
char buf[ID_LEN]; char buf[ID_LEN];
long conn; long conn_id;
pthread_t child; pthread_t child;
void *(*handle)(void *) = (void *(*)(void *)) handle_connection;
parameters params; parameters params;
connection_state * connection; connection_state * conn;
char * events_path; char * events_path;
if (argc < 2) { if (argc < 2) {
@ -432,19 +377,17 @@ int main(int argc, char * argv[]) {
params.socket9p_root = argv[1]; params.socket9p_root = argv[1];
} }
if (asprintf(&events_path, "%s/events", params.socket9p_root) == -1) { if (asprintf(&events_path, "%s/events", params.socket9p_root) == -1)
fprintf(stderr, "Couldn't allocate events path\n"); die(1, "", "Couldn't allocate events path: ");
exit(1);
}
setup_save_trace(); setup_save_trace();
events = open(events_path, O_RDONLY | O_CLOEXEC); events = open(events_path, O_RDONLY | O_CLOEXEC);
while (events != -1) { if (events != -1) {
while (1) {
read_count = read(events, buf, ID_LEN - 1); read_count = read(events, buf, ID_LEN - 1);
if (read_count == -1) { if (read_count == -1) {
perror("Error reading events path"); die(1, "Error reading events path", "");
exit(1);
} else if (read_count == 0) { } else if (read_count == 0) {
// TODO: this is probably the 9p server's fault due to // TODO: this is probably the 9p server's fault due to
// not dropping the read 0 to force short read if // not dropping the read 0 to force short read if
@ -456,36 +399,29 @@ int main(int argc, char * argv[]) {
buf[read_count] = 0x0; buf[read_count] = 0x0;
errno = 0; errno = 0;
conn = strtol(buf, NULL, 10); conn_id = strtol(buf, NULL, 10);
if (errno) { if (errno) die(1, "failed", "Connection id of string '%s'", buf);
fprintf(stderr, "connection id of string '%s' ", buf);
perror("failed");
exit(1);
}
if (debug) fprintf(stderr, "handle connection %ld\n", conn); if (debug) fprintf(stderr, "handle connection %ld\n", conn_id);
connection = must_malloc("connection state", sizeof(connection_state)); conn = (connection_state *) must_malloc("connection state",
connection->id = conn; sizeof(connection_state));
connection->params = &params; conn->id = conn_id;
conn->params = &params;
if ((errno = pthread_create(&child, NULL, handle, connection))) { if ((errno = pthread_create(&child, NULL,
fprintf(stderr, "couldn't create thread for connection '%ld' ", conn); handle_connection_thread, conn)))
perror(""); die(1, "", "Couldn't create thread for connection '%ld': ", conn_id);
exit(1);
}
if ((errno = pthread_detach(child))) { if ((errno = pthread_detach(child)))
fprintf(stderr, "couldn't detach thread for connection '%ld' ", conn); die(1, "", "Couldn't detach thread for connection '%ld': ", conn_id);
perror("");
exit(1);
}
if (debug) fprintf(stderr, "thread spawned\n"); if (debug) fprintf(stderr, "thread spawned\n");
} }
}
fprintf(stderr, "failed to open events path: %s\n", events_path); fprintf(stderr, "Failed to open events path %s: ", events_path);
perror("");
free(events_path); free(events_path);
return 1; return 1;
} }