mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-23 02:51:55 +00:00
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:
parent
0a493c1fb7
commit
b58448fdf5
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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", ¶ms->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", ¶ms->ctl_lock);
|
||||
vlog_time_locked(params, fmt, args);
|
||||
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);
|
||||
@ -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", ¶ms->ctl_lock);
|
||||
vlog_locked(params, fmt, args);
|
||||
vlog_locked(params, TRANSFUSE_LOG_ERROR, fmt, args);
|
||||
unlock("log_continue ctl_lock", ¶ms->ctl_lock);
|
||||
|
||||
va_end(args);
|
||||
|
@ -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, ...);
|
||||
|
Loading…
Reference in New Issue
Block a user