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_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_socket = DEFAULT_SOCKET;
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[]) {
char ** argv;
char * envp[2];
char * mount_notice, * arg_acc;
pid_t fusermount_pid;
int fuse_socks[2];
int status;
@ -357,12 +341,24 @@ int get_fuse_sock(connection_t * conn, int optc, char *const optv[]) {
argv[0] = conn->params->fusermount;
memcpy(&argv[1], optv, (optc + 1) * sizeof(char *));
lock("get_fuse_sock ctl_lock", &conn->params->ctl_lock);
log_time_locked(conn->params, "mount ");
for (int i = 0; argv[i]; i++)
log_continue_locked(conn->params, "%s ",argv[i]);
log_continue_locked(conn->params, "\n");
unlock("get_fuse_sock ctl_lock", &conn->params->ctl_lock);
// 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))
@ -460,6 +456,7 @@ 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);
@ -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;
errno = 0;
child = readdir(dir);
if (child == NULL) {
if (errno != 0)
die(1, conn->params, "", "Couldn't read mount point %s: ",
conn->mount_point);
die(1, params, "", "Couldn't read directory %s: ", path);
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;
}
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.
void prepare_mount_point(connection_t * conn) {
DIR * dir;
char * mount_point = conn->mount_point;
dir = opendir(mount_point);
if (dir != NULL) {
if (is_next_child_ok(conn, dir))
if (is_next_child_ok(conn, dir)) {
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);
if (is_path_missing_or_empty(conn->params, 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) {
@ -584,6 +585,12 @@ void write_pid(connection_t * connection) {
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[]) {
char * name;
int r = 0;
@ -591,7 +598,7 @@ void perform_syscall(connection_t * conn, uint8_t syscall, char path[]) {
switch (syscall) {
case PING:
log_time(conn->params, "PONG");
pong(conn->params);
r = 0;
break;
@ -701,11 +708,42 @@ void write_pidfile(parameters * params) {
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) {
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' };
void * buf;
void * buf, * response;
uint16_t msg_type;
params->ctl_sock = connect_socket(params->server);
@ -715,22 +753,40 @@ void * init_thread(void * params_ptr) {
if (write_count != sizeof(init_msg))
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
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", "");
// 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++)
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
if (params->pidfile != NULL)
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;
}

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 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
(int exit_code, parameters * params, const char * parg, const char * fmt, ...);
void vlog_sock_locked(int fd, const char * fmt, va_list args) {
uint16_t log_err_type = 1;
void vlog_sock_locked
(int fd, uint16_t msg_type, const char * fmt, va_list args) {
int rc, len;
va_list targs;
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
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);
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_start(args, fmt);
vlog_sock_locked(fd, fmt, args);
vlog_sock_locked(fd, msg_type, fmt, args);
va_end(args);
}
@ -94,16 +94,19 @@ void die
vsyslog(LOG_CRIT, fmt, 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);
if (parg != NULL) {
if (*parg != 0) {
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 {
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);
}
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 fd = params->ctl_sock;
va_list targs;
if (fd != 0) vlog_sock_locked(fd, fmt, args);
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);
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);
@ -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;
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_start(args, fmt);
vlog_time_locked(params, fmt, args);
vlog_time_locked(params, msg_type, fmt, args);
va_end(args);
}
@ -157,7 +165,19 @@ void log_time(parameters * params, const char * fmt, ...) {
va_start(args, fmt);
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);
va_end(args);
@ -208,7 +228,7 @@ void log_continue_locked(parameters * params, const char * fmt, ...) {
va_start(args, fmt);
vlog_locked(params, fmt, args);
vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args);
va_end(args);
}
@ -219,7 +239,7 @@ void log_continue(parameters * params, const char * fmt, ...) {
va_start(args, fmt);
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);
va_end(args);

View File

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