transfused: update control protocol (#181)

Add a mount suitability predicate, a pong reply message type, and a log
notice message type. Also, fixes the multi-line mount point printing issue.

Signed-off-by: David Sheets <dsheets@docker.com>
This commit is contained in:
David Sheets 2016-06-07 19:13:52 +01:00
parent 0a493c1fb7
commit b58448fdf5
4 changed files with 186 additions and 79 deletions

View File

@ -25,23 +25,6 @@
#include "transfused_log.h" #include "transfused_log.h"
#include "transfused_vsock.h" #include "transfused_vsock.h"
#define IN_BUFSZ ((1 << 20) + 16)
#define OUT_BUFSZ ((1 << 20) + 64)
#define EVENT_BUFSZ 4096
#define DEFAULT_FUSERMOUNT "/bin/fusermount"
#define DEFAULT_SOCKET "v:_:1525"
#define DEFAULT_SERVER "v:2:1524"
#define PING 128
#define RMDIR_SYSCALL 0
#define UNLINK_SYSCALL 1
#define MKDIR_SYSCALL 2
#define SYMLINK_SYSCALL 3
#define TRUNCATE_SYSCALL 4
#define CHMOD_SYSCALL 5
// these could be turned into an enum probably but... C standard nausea
char * default_fusermount = DEFAULT_FUSERMOUNT; char * default_fusermount = DEFAULT_FUSERMOUNT;
char * default_socket = DEFAULT_SOCKET; char * default_socket = DEFAULT_SOCKET;
char * default_server = DEFAULT_SERVER; char * default_server = DEFAULT_SERVER;
@ -346,6 +329,7 @@ int recv_fd(parameters * params, int sock) {
int get_fuse_sock(connection_t * conn, int optc, char *const optv[]) { int get_fuse_sock(connection_t * conn, int optc, char *const optv[]) {
char ** argv; char ** argv;
char * envp[2]; char * envp[2];
char * mount_notice, * arg_acc;
pid_t fusermount_pid; pid_t fusermount_pid;
int fuse_socks[2]; int fuse_socks[2];
int status; int status;
@ -357,12 +341,24 @@ int get_fuse_sock(connection_t * conn, int optc, char *const optv[]) {
argv[0] = conn->params->fusermount; argv[0] = conn->params->fusermount;
memcpy(&argv[1], optv, (optc + 1) * sizeof(char *)); memcpy(&argv[1], optv, (optc + 1) * sizeof(char *));
lock("get_fuse_sock ctl_lock", &conn->params->ctl_lock); // report the mount command issued
log_time_locked(conn->params, "mount "); if (asprintf(&arg_acc, "mount") == -1)
for (int i = 0; argv[i]; i++) die(1, conn->params, "Couldn't allocate mount notice base string", "");
log_continue_locked(conn->params, "%s ",argv[i]);
log_continue_locked(conn->params, "\n"); for (int i = 0; argv[i]; i++) {
unlock("get_fuse_sock ctl_lock", &conn->params->ctl_lock); 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 // 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))
@ -460,6 +456,7 @@ void mkdir_p(connection_t * conn, char * path) {
char * parent; char * parent;
if (mkdir(path, 0700)) switch (errno) { if (mkdir(path, 0700)) switch (errno) {
case EEXIST: return;
case ENOENT: case ENOENT:
parent = alloc_dirname(conn, path); parent = alloc_dirname(conn, path);
mkdir_p(conn, parent); mkdir_p(conn, parent);
@ -472,48 +469,52 @@ void mkdir_p(connection_t * conn, char * path) {
} }
} }
int is_next_child_ok(connection_t * conn, DIR * dir) { int is_next_child_ok(parameters * params, char * path, DIR * dir) {
struct dirent * child; struct dirent * child;
errno = 0; errno = 0;
child = readdir(dir); child = readdir(dir);
if (child == NULL) { if (child == NULL) {
if (errno != 0) if (errno != 0)
die(1, conn->params, "", "Couldn't read mount point %s: ", die(1, params, "", "Couldn't read directory %s: ", path);
conn->mount_point);
else return 0; else return 0;
} else }
if (strcmp(".", child->d_name) != 0 && strcmp("..", child->d_name) != 0)
die(1, conn->params, NULL, "Couldn't mount on %s: %s exists",
conn->mount_point, child->d_name);
return 1; return 1;
} }
int is_path_missing_or_empty(parameters * params, 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 goto yes;
}
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;
}
// The leaf may exist but must be empty. Any proper path prefix may exist. // The leaf may exist but must be empty. Any proper path prefix may exist.
void prepare_mount_point(connection_t * conn) { void prepare_mount_point(connection_t * conn) {
DIR * dir;
char * mount_point = conn->mount_point; char * mount_point = conn->mount_point;
dir = opendir(mount_point); if (is_path_missing_or_empty(conn->params, mount_point))
if (dir != NULL) { mkdir_p(conn, mount_point);
if (is_next_child_ok(conn, dir)) else die(1, conn->params, NULL,
if (is_next_child_ok(conn, dir)) { "Couldn't mount on %s: not missing or empty", mount_point);
if (is_next_child_ok(conn, dir))
die(1, conn->params, "", "Couldn't mount on %s: not empty",
mount_point);
else return;
}
if (closedir(dir))
die(1, conn->params, "", "Couldn't close mount point %s: ", mount_point);
} else {
switch (errno) {
case ENOENT: break;
default:
die(1, conn->params, "", "Couldn't open mount point %s: ", mount_point);
}
}
mkdir_p(conn, mount_point);
} }
void * mount_connection(connection_t * conn) { void * mount_connection(connection_t * conn) {
@ -584,6 +585,12 @@ void write_pid(connection_t * connection) {
free(pid_s); free(pid_s);
} }
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);
}
void perform_syscall(connection_t * conn, uint8_t syscall, char path[]) { void perform_syscall(connection_t * conn, uint8_t syscall, char path[]) {
char * name; char * name;
int r = 0; int r = 0;
@ -591,7 +598,7 @@ void perform_syscall(connection_t * conn, uint8_t syscall, char path[]) {
switch (syscall) { switch (syscall) {
case PING: case PING:
log_time(conn->params, "PONG"); pong(conn->params);
r = 0; r = 0;
break; break;
@ -701,11 +708,42 @@ void write_pidfile(parameters * params) {
free(pid_s); free(pid_s);
} }
// TODO: the message parsing here is rickety, do it properly
void * determine_mount_suitability(parameters * params, 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;
buf = (void *) ((char *) buf + 2);
len -= 2;
while (len) {
slen = *((uint16_t *) buf) + 1;
if (is_path_missing_or_empty(params, ((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;
}
void * init_thread(void * params_ptr) { void * init_thread(void * params_ptr) {
parameters * params = params_ptr; parameters * params = params_ptr;
int write_count, read_count; int write_count, read_count, len;
char init_msg[6] = { '\6', '\0', '\0', '\0', '\0', '\0' }; char init_msg[6] = { '\6', '\0', '\0', '\0', '\0', '\0' };
void * buf; void * buf, * response;
uint16_t msg_type;
params->ctl_sock = connect_socket(params->server); params->ctl_sock = connect_socket(params->server);
@ -715,22 +753,40 @@ void * init_thread(void * params_ptr) {
if (write_count != sizeof(init_msg)) if (write_count != sizeof(init_msg))
die(1, NULL, "init thread: incomplete write", ""); die(1, NULL, "init thread: incomplete write", "");
buf = must_malloc("incoming init buffer", EVENT_BUFSZ); buf = must_malloc("incoming control message buffer", CTL_BUFSZ);
// TODO: handle short read/socket conditions // TODO: handle short read/socket conditions
read_count = read(params->ctl_sock, buf, EVENT_BUFSZ); read_count = read(params->ctl_sock, buf, 6);
if (read_count < 0) die(1, params, "init thread: error reading", ""); if (read_count < 0) die(1, params, "init thread: error reading", "");
// TODO: handle other messages // TODO: handle other messages
if (read_count != 6) die(1, params, "init thread: response not 6", ""); if (read_count != 6) die(1, params, NULL, "init thread: response not 6");
for (int i = 0; i < sizeof(init_msg); i++) for (int i = 0; i < sizeof(init_msg); i++)
if (((char *)buf)[i] != init_msg[i]) if (((char *)buf)[i] != init_msg[i])
die(1, params, "init thread: unexpected message", ""); die(1, params, NULL, "init thread: unexpected message");
// we've gotten Continue so write the pidfile // we've gotten Continue so write the pidfile
if (params->pidfile != NULL) if (params->pidfile != NULL)
write_pidfile(params); write_pidfile(params);
// TODO: handle more messages 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, (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;
default:
die(1, params, NULL, "init thread: unknown message %d", msg_type);
}
}
free(buf);
return NULL; return NULL;
} }

View File

@ -31,3 +31,28 @@ void lock(char *const descr, pthread_mutex_t * mutex);
void unlock(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); 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
#define CTL_BUFSZ 65536
#define DEFAULT_FUSERMOUNT "/bin/fusermount"
#define DEFAULT_SOCKET "v:_:1525"
#define DEFAULT_SERVER "v:2:1524"
#define PING 128
#define RMDIR_SYSCALL 0
#define UNLINK_SYSCALL 1
#define MKDIR_SYSCALL 2
#define SYMLINK_SYSCALL 3
#define TRUNCATE_SYSCALL 4
#define CHMOD_SYSCALL 5
// these could be turned into an enum probably but... C standard nausea
#define MOUNT_SUITABILITY_REQUEST 1
#define TRANSFUSE_LOG_ERROR 1
#define TRANSFUSE_LOG_NOTICE 2
#define PONG_REPLY 3
#define MOUNT_SUITABILITY_REPLY 4

View File

@ -39,8 +39,8 @@ void log_timestamp(int fd) {
void die void die
(int exit_code, parameters * params, const char * parg, const char * fmt, ...); (int exit_code, parameters * params, const char * parg, const char * fmt, ...);
void vlog_sock_locked(int fd, const char * fmt, va_list args) { void vlog_sock_locked
uint16_t log_err_type = 1; (int fd, uint16_t msg_type, const char * fmt, va_list args) {
int rc, len; int rc, len;
va_list targs; va_list targs;
char * fill; char * fill;
@ -52,7 +52,7 @@ void vlog_sock_locked(int fd, const char * fmt, va_list args) {
rc = len + 4 + 2; // 4 for length itself and 2 for message type 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, (uint32_t *) &rc, sizeof(uint32_t));
write_exactly("vlog_sock_locked", fd, &log_err_type, sizeof(uint16_t)); write_exactly("vlog_sock_locked", fd, &msg_type, sizeof(uint16_t));
va_copy(targs, args); va_copy(targs, args);
rc = vdprintf(fd, fmt, targs); rc = vdprintf(fd, fmt, targs);
@ -67,12 +67,12 @@ void vlog_sock_locked(int fd, const char * fmt, va_list args) {
} }
} }
void log_sock_locked(int fd, const char * fmt, ...) { void log_sock_locked(int fd, uint16_t msg_type, const char * fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vlog_sock_locked(fd, fmt, args); vlog_sock_locked(fd, msg_type, fmt, args);
va_end(args); va_end(args);
} }
@ -94,16 +94,19 @@ void die
vsyslog(LOG_CRIT, fmt, targs); vsyslog(LOG_CRIT, fmt, targs);
va_end(targs); va_end(targs);
if (fd != 0) vlog_sock_locked(fd, fmt, argp); if (fd != 0) vlog_sock_locked(fd, TRANSFUSE_LOG_ERROR, fmt, argp);
va_end(argp); va_end(argp);
if (parg != NULL) { if (parg != NULL) {
if (*parg != 0) { if (*parg != 0) {
syslog(LOG_CRIT, "%s: %s", parg, strerror(in_errno)); syslog(LOG_CRIT, "%s: %s", parg, strerror(in_errno));
if (fd != 0) log_sock_locked(fd, "%s: %s", parg, strerror(in_errno)); if (fd != 0)
log_sock_locked(fd, TRANSFUSE_LOG_ERROR,
"%s: %s", parg, strerror(in_errno));
} else { } else {
syslog(LOG_CRIT, "%s", strerror(in_errno)); syslog(LOG_CRIT, "%s", strerror(in_errno));
if (fd != 0) log_sock_locked(fd, "%s", strerror(in_errno)); if (fd != 0)
log_sock_locked(fd, TRANSFUSE_LOG_ERROR, "%s", strerror(in_errno));
} }
} }
@ -113,20 +116,23 @@ void die
unlock("die ctl_lock", &params->ctl_lock); unlock("die ctl_lock", &params->ctl_lock);
} }
void vlog_locked(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 rc;
int fd = params->ctl_sock; int fd = params->ctl_sock;
va_list targs; va_list targs;
if (fd != 0) vlog_sock_locked(fd, fmt, args); if (fd != 0) vlog_sock_locked(fd, msg_type, fmt, args);
else { else {
va_copy(targs, args); va_copy(targs, args);
// TODO: translate msg_type to syslog message type
vsyslog(LOG_INFO, fmt, targs); vsyslog(LOG_INFO, fmt, targs);
va_end(targs); va_end(targs);
fd = params->logfile_fd; fd = params->logfile_fd;
if (fd != 0) { if (fd != 0) {
va_copy(targs, args); va_copy(targs, args);
// TODO: include message type?
rc = vdprintf(fd, fmt, targs); rc = vdprintf(fd, fmt, targs);
if (rc < 0) die(1, NULL, "Couldn't write log message with vdprintf", ""); if (rc < 0) die(1, NULL, "Couldn't write log message with vdprintf", "");
va_end(targs); va_end(targs);
@ -134,19 +140,21 @@ void vlog_locked(parameters * params, const char * fmt, va_list args) {
} }
} }
void vlog_time_locked(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; int fd = params->logfile_fd;
if (fd != 0 && params->ctl_sock == 0) log_timestamp(fd); if (fd != 0 && params->ctl_sock == 0) log_timestamp(fd);
vlog_locked(params, fmt, args); vlog_locked(params, msg_type, fmt, args);
} }
void log_time_locked(parameters * params, const char * fmt, ...) { void log_time_locked
(parameters * params, uint16_t msg_type, const char * fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vlog_time_locked(params, fmt, args); vlog_time_locked(params, msg_type, fmt, args);
va_end(args); va_end(args);
} }
@ -157,7 +165,19 @@ void log_time(parameters * params, const char * fmt, ...) {
va_start(args, fmt); va_start(args, fmt);
lock("log_time ctl_lock", &params->ctl_lock); lock("log_time ctl_lock", &params->ctl_lock);
vlog_time_locked(params, fmt, args); vlog_time_locked(params, TRANSFUSE_LOG_ERROR, fmt, args);
unlock("log_time ctl_lock", &params->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", &params->ctl_lock);
vlog_time_locked(params, TRANSFUSE_LOG_NOTICE, fmt, args);
unlock("log_time ctl_lock", &params->ctl_lock); unlock("log_time ctl_lock", &params->ctl_lock);
va_end(args); va_end(args);
@ -208,7 +228,7 @@ void log_continue_locked(parameters * params, const char * fmt, ...) {
va_start(args, fmt); va_start(args, fmt);
vlog_locked(params, fmt, args); vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args);
va_end(args); va_end(args);
} }
@ -219,7 +239,7 @@ void log_continue(parameters * params, const char * fmt, ...) {
va_start(args, fmt); va_start(args, fmt);
lock("log_continue ctl_lock", &params->ctl_lock); lock("log_continue ctl_lock", &params->ctl_lock);
vlog_locked(params, fmt, args); vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args);
unlock("log_continue ctl_lock", &params->ctl_lock); unlock("log_continue ctl_lock", &params->ctl_lock);
va_end(args); va_end(args);

View File

@ -1,4 +1,5 @@
#include <stdarg.h> #include <stdarg.h>
#include <inttypes.h>
#include "transfused.h" #include "transfused.h"
@ -6,14 +7,19 @@ void die
(int exit_code, parameters * params, const char * perror_arg, (int exit_code, parameters * params, const char * perror_arg,
const char * fmt, ...); const char * fmt, ...);
void vlog_locked(parameters * params, 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, 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, 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_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 thread_log_time(connection_t * conn, const char * fmt, ...);
void log_continue_locked(parameters * params, const char * fmt, ...); void log_continue_locked(parameters * params, const char * fmt, ...);