mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-24 11:25:40 +00:00
commit
b891c52525
@ -23,8 +23,8 @@ COPY mkinitrd.sh /bin/
|
|||||||
|
|
||||||
COPY packages/9pudc/9pudc /sbin/
|
COPY packages/9pudc/9pudc /sbin/
|
||||||
COPY packages/9pudc/etc /etc/
|
COPY packages/9pudc/etc /etc/
|
||||||
COPY packages/9pudfuse/9pudfuse /sbin/
|
COPY packages/transfused/transfused /sbin/
|
||||||
COPY packages/9pudfuse/etc /etc/
|
COPY packages/transfused/etc /etc/
|
||||||
COPY packages/mdnstool/mdnstool /sbin/
|
COPY packages/mdnstool/mdnstool /sbin/
|
||||||
COPY packages/mdnstool/etc /etc/
|
COPY packages/mdnstool/etc /etc/
|
||||||
COPY packages/docker/docker /usr/bin/
|
COPY packages/docker/docker /usr/bin/
|
||||||
@ -78,7 +78,7 @@ RUN \
|
|||||||
rc-update add docker default && \
|
rc-update add docker default && \
|
||||||
rc-update add 9pinit boot && \
|
rc-update add 9pinit boot && \
|
||||||
rc-update add 9pudc default && \
|
rc-update add 9pudc default && \
|
||||||
rc-update add 9pudfuse default && \
|
rc-update add transfused default && \
|
||||||
rc-update add mdnstool default && \
|
rc-update add mdnstool default && \
|
||||||
rc-update add automount boot && \
|
rc-update add automount boot && \
|
||||||
rc-update add diagnostics default && \
|
rc-update add diagnostics default && \
|
||||||
|
1
alpine/packages/9pudfuse/.gitignore
vendored
1
alpine/packages/9pudfuse/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/9pudfuse
|
|
@ -1,6 +0,0 @@
|
|||||||
PKG result
|
|
||||||
PKG stringext
|
|
||||||
PKG fd-send-recv
|
|
||||||
|
|
||||||
S .
|
|
||||||
B .
|
|
@ -1,13 +0,0 @@
|
|||||||
FROM ocaml/opam:alpine-3.3_ocaml-4.02.3
|
|
||||||
|
|
||||||
ENV \
|
|
||||||
OPAMYES=true \
|
|
||||||
CAML_LD_LIBRARY_PATH="/root/.opam/4.02.3/lib/stublibs:/usr/pkg/lib/ocaml/stublibs" \
|
|
||||||
MANPATH="/root/.opam/4.02.3/man:" \
|
|
||||||
PERL5LIB="/root/.opam/4.02.3/lib/perl5" \
|
|
||||||
OCAML_TOPLEVEL_PATH="/root/.opam/4.02.3/lib/toplevel" \
|
|
||||||
PATH=/root/.opam/4.02.3/bin:$PATH
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
RUN opam depext -i result stringext fd-send-recv
|
|
||||||
RUN opam config exec -- ocamlbuild -tag debug -use-ocamlfind -package stringext,fd-send-recv,result fuse_socket_9p.native
|
|
@ -1,11 +0,0 @@
|
|||||||
all: 9pudfuse
|
|
||||||
|
|
||||||
9pudfuse: Dockerfile fuse_socket_9p.ml
|
|
||||||
docker build -t 9pudfuse:build .
|
|
||||||
docker run --rm 9pudfuse:build \
|
|
||||||
cat fuse_socket_9p.native > 9pudfuse
|
|
||||||
chmod 755 9pudfuse
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f 9pudfuse
|
|
||||||
docker images -q 9pudfuse:build | xargs docker rmi -f
|
|
@ -1,37 +0,0 @@
|
|||||||
#!/sbin/openrc-run
|
|
||||||
|
|
||||||
description="9p socket fuse proxy server"
|
|
||||||
|
|
||||||
depend()
|
|
||||||
{
|
|
||||||
need 9pinit
|
|
||||||
}
|
|
||||||
|
|
||||||
start()
|
|
||||||
{
|
|
||||||
[ -d /Transfuse ] || exit 0
|
|
||||||
|
|
||||||
ebegin "Starting FUSE socket passthrough"
|
|
||||||
|
|
||||||
[ -n "${PIDFILE}" ] || PIDFILE=/var/run/9pudfuse.pid
|
|
||||||
|
|
||||||
# start-stop-daemon --start --quiet \
|
|
||||||
# --exec /sbin/9pudfuse \
|
|
||||||
# --pidfile "${PIDFILE}" \
|
|
||||||
# -- -path /Transfuse
|
|
||||||
# eend $? "Failed to start 9pudfuse"
|
|
||||||
OCAMLRUNPARAM=b /sbin/9pudfuse &
|
|
||||||
}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
{
|
|
||||||
[ -d /Transfuse ] || exit 0
|
|
||||||
|
|
||||||
ebegin "Stopping FUSE socket passthrough"
|
|
||||||
|
|
||||||
[ -n "${PIDFILE}" ] || PIDFILE=/var/run/9pudfuse.pid
|
|
||||||
|
|
||||||
start-stop-daemon --stop --quiet \
|
|
||||||
--pidfile "${PIDFILE}"
|
|
||||||
eend $? "Failed to stop 9pudfuse"
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
|
|
||||||
exception ReadClosed
|
|
||||||
|
|
||||||
let fusermount = "fusermount"
|
|
||||||
let path = "/Transfuse"
|
|
||||||
|
|
||||||
module Log = struct
|
|
||||||
let fatal fmt =
|
|
||||||
Printf.ksprintf (fun s -> prerr_endline s; exit 1) fmt
|
|
||||||
let error fmt =
|
|
||||||
Printf.ksprintf (fun s -> prerr_endline s) fmt
|
|
||||||
let info fmt =
|
|
||||||
Printf.ksprintf (fun s -> prerr_endline s) fmt
|
|
||||||
end
|
|
||||||
|
|
||||||
let events_path = path ^ "/events"
|
|
||||||
|
|
||||||
let try_fork caller_name =
|
|
||||||
try
|
|
||||||
Unix.fork ()
|
|
||||||
with Unix.Unix_error (err,"fork",_) ->
|
|
||||||
Log.fatal "%s fork failed: %s" caller_name (Unix.error_message err)
|
|
||||||
|
|
||||||
let check_status = function
|
|
||||||
| Unix.WEXITED 0 -> Result.Ok ()
|
|
||||||
| Unix.WEXITED k ->
|
|
||||||
Result.Error ("exit code "^(string_of_int k))
|
|
||||||
| Unix.WSIGNALED k ->
|
|
||||||
Result.Error ("ocaml kill signal "^(string_of_int k))
|
|
||||||
| Unix.WSTOPPED k ->
|
|
||||||
Result.Error ("ocaml stop signal "^(string_of_int k))
|
|
||||||
|
|
||||||
let finally f at_end =
|
|
||||||
let r = try f () with e -> (at_end (); raise e) in
|
|
||||||
at_end ();
|
|
||||||
r
|
|
||||||
|
|
||||||
let copy description dst src =
|
|
||||||
let sz = 1 lsl 16 in
|
|
||||||
let buf = Bytes.create sz in
|
|
||||||
(*let pnum = ref 0 in*)
|
|
||||||
let rec loop () =
|
|
||||||
let n = Unix.read src buf 0 sz in
|
|
||||||
(if n = 0 then raise ReadClosed);
|
|
||||||
(*
|
|
||||||
let fd = Unix.(
|
|
||||||
openfile ("/tmp/"^description^"_"^(string_of_int !pnum))
|
|
||||||
[O_WRONLY; O_CREAT] 0o600) in
|
|
||||||
let k = Unix.write fd buf 0 n in
|
|
||||||
assert (k = n);
|
|
||||||
Unix.close fd;
|
|
||||||
incr pnum;
|
|
||||||
*)
|
|
||||||
let written = try
|
|
||||||
Unix.write dst buf 0 n
|
|
||||||
with
|
|
||||||
| Unix.Unix_error (Unix.EINVAL, "write", _) ->
|
|
||||||
failwith ("copy write for "^description^" failed with EINVAL")
|
|
||||||
| Unix.Unix_error (Unix.ENOENT, "write", _) ->
|
|
||||||
failwith ("copy write for "^description^" failed with ENOENT")
|
|
||||||
in
|
|
||||||
(if n <> written
|
|
||||||
then Log.error "copy of %s read %d but wrote %d" description n written);
|
|
||||||
loop ()
|
|
||||||
in
|
|
||||||
try loop ()
|
|
||||||
with
|
|
||||||
| ReadClosed -> raise ReadClosed
|
|
||||||
| e -> (Log.error "copy for %s failed" description; raise e)
|
|
||||||
|
|
||||||
let with_reader id f =
|
|
||||||
let read_path = Printf.sprintf "%s/connections/%d/read" path id in
|
|
||||||
let read_fd = Unix.(openfile read_path [O_RDONLY] 0o000) in
|
|
||||||
try finally (fun () ->
|
|
||||||
f read_path read_fd
|
|
||||||
) (fun () ->
|
|
||||||
Unix.close read_fd
|
|
||||||
) with
|
|
||||||
| ReadClosed -> exit 0
|
|
||||||
|
|
||||||
let with_writer id f =
|
|
||||||
let write_path = Printf.sprintf "%s/connections/%d/write" path id in
|
|
||||||
let write_fd = Unix.(openfile write_path [O_WRONLY] 0o000) in
|
|
||||||
finally (fun () ->
|
|
||||||
f write_path write_fd
|
|
||||||
) (fun () ->
|
|
||||||
Unix.close write_fd;
|
|
||||||
Unix.unlink write_path
|
|
||||||
)
|
|
||||||
|
|
||||||
let read_opts id = with_reader id (fun read_path read_fd ->
|
|
||||||
let sz = 512 in
|
|
||||||
let buf = Bytes.create sz in
|
|
||||||
let n = Unix.read read_fd buf 0 sz in
|
|
||||||
let opts = Stringext.split ~on:'\000' (Bytes.sub buf 0 n) in
|
|
||||||
Array.of_list opts
|
|
||||||
)
|
|
||||||
|
|
||||||
let get_fuse_sock opts =
|
|
||||||
let wsock, rsock = Unix.(socketpair PF_UNIX SOCK_STREAM 0) in
|
|
||||||
let wfd = Fd_send_recv.int_of_fd wsock in
|
|
||||||
let opts = Array.append [|fusermount|] opts in
|
|
||||||
let pid = Unix.(create_process_env fusermount opts
|
|
||||||
[|"_FUSE_COMMFD="^(string_of_int wfd)|]
|
|
||||||
stdin stdout stderr) in
|
|
||||||
let _, status = Unix.waitpid [] pid in
|
|
||||||
let () = Unix.(shutdown wsock SHUTDOWN_ALL) in
|
|
||||||
match check_status status with
|
|
||||||
| Result.Error str ->
|
|
||||||
let opts = String.concat " " (Array.to_list opts) in
|
|
||||||
Log.fatal "%s: %s" opts str
|
|
||||||
| Result.Ok () ->
|
|
||||||
(* We must read at least 1 byte, by POSIX! *)
|
|
||||||
let _, _, fd = Fd_send_recv.recv_fd rsock "\000" 0 1 [] in
|
|
||||||
let () = Unix.(shutdown rsock SHUTDOWN_ALL) in
|
|
||||||
fd
|
|
||||||
|
|
||||||
(* readers fork into a new process *)
|
|
||||||
let start_reader id fuse =
|
|
||||||
match try_fork "start_reader" with
|
|
||||||
| 0 -> (* child *)
|
|
||||||
with_reader id (fun _read_path read_fd ->
|
|
||||||
copy ("reader_"^string_of_int id) fuse read_fd
|
|
||||||
)
|
|
||||||
| _child_pid -> (* parent *)
|
|
||||||
()
|
|
||||||
|
|
||||||
(* writers stay in the calling process *)
|
|
||||||
let start_writer id fuse = with_writer id (fun write_path write_fd ->
|
|
||||||
copy ("writer_"^string_of_int id) write_fd fuse
|
|
||||||
)
|
|
||||||
|
|
||||||
let handle_connection id =
|
|
||||||
Log.info "handle_connection %d" id;
|
|
||||||
match try_fork "handle_connection" with
|
|
||||||
| 0 -> (* child *)
|
|
||||||
let opts = read_opts id in
|
|
||||||
let fuse = get_fuse_sock opts in
|
|
||||||
start_reader id fuse;
|
|
||||||
begin try ignore (start_writer id fuse); exit 0
|
|
||||||
with
|
|
||||||
| e -> prerr_endline (Printexc.to_string e); exit 1
|
|
||||||
end
|
|
||||||
| _child_pid -> (* parent *)
|
|
||||||
()
|
|
||||||
|
|
||||||
let connection_loop () =
|
|
||||||
let events = Unix.(openfile events_path [O_RDONLY] 0o000) in
|
|
||||||
(* 512 bytes is easily big enough to read a whole connection id *)
|
|
||||||
let sz = 512 in
|
|
||||||
let buf = Bytes.create sz in
|
|
||||||
let rec recv () =
|
|
||||||
begin try
|
|
||||||
let n = Unix.read events buf 0 sz in
|
|
||||||
let s = String.trim Bytes.(to_string (sub buf 0 n)) in
|
|
||||||
let id = int_of_string s in
|
|
||||||
handle_connection id;
|
|
||||||
with
|
|
||||||
| Unix.Unix_error (err,"read",path) ->
|
|
||||||
Log.fatal "Error reading events file %s: %s"
|
|
||||||
path (Unix.error_message err)
|
|
||||||
| Failure "int_of_string" ->
|
|
||||||
Log.fatal "Failed to parse integer connection id"
|
|
||||||
end;
|
|
||||||
recv ()
|
|
||||||
in
|
|
||||||
recv ()
|
|
||||||
|
|
||||||
;;
|
|
||||||
connection_loop ()
|
|
@ -1,6 +1,6 @@
|
|||||||
all:
|
all:
|
||||||
$(MAKE) -C 9pudc
|
$(MAKE) -C 9pudc
|
||||||
$(MAKE) -C 9pudfuse
|
$(MAKE) -C transfused
|
||||||
$(MAKE) -C mdnstool
|
$(MAKE) -C mdnstool
|
||||||
$(MAKE) -C docker
|
$(MAKE) -C docker
|
||||||
$(MAKE) -C hupper
|
$(MAKE) -C hupper
|
||||||
@ -8,14 +8,14 @@ all:
|
|||||||
|
|
||||||
arm:
|
arm:
|
||||||
$(MAKE) -C 9pudc ARCH=arm
|
$(MAKE) -C 9pudc ARCH=arm
|
||||||
$(MAKE) -C 9pudfuse ARCH=arm
|
$(MAKE) -C transfused ARCH=arm
|
||||||
$(MAKE) -C mdnstool ARCH=arm
|
$(MAKE) -C mdnstool ARCH=arm
|
||||||
$(MAKE) -C docker ARCH=arm
|
$(MAKE) -C docker ARCH=arm
|
||||||
$(MAKE) -C hupper ARCH=arm
|
$(MAKE) -C hupper ARCH=arm
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C 9pudc clean
|
$(MAKE) -C 9pudc clean
|
||||||
$(MAKE) -C 9pudfuse clean
|
$(MAKE) -C transfused clean
|
||||||
$(MAKE) -C mdnstool clean
|
$(MAKE) -C mdnstool clean
|
||||||
$(MAKE) -C docker clean
|
$(MAKE) -C docker clean
|
||||||
$(MAKE) -C hupper clean
|
$(MAKE) -C hupper clean
|
||||||
|
@ -11,8 +11,8 @@ UDC=$(ps -eo args | grep '^/sbin/9pudc')
|
|||||||
[ $? -eq 0 ] && printf "✓ Process 9pudc running: $UDC\n" || printf "✗ No 9pudc process\n"
|
[ $? -eq 0 ] && printf "✓ Process 9pudc running: $UDC\n" || printf "✗ No 9pudc process\n"
|
||||||
if [ -d /Transfuse ]
|
if [ -d /Transfuse ]
|
||||||
then
|
then
|
||||||
FUSE=$(ps -eo args | grep '^/sbin/9pudfuse')
|
FUSE=$(ps -eo args | grep '^/sbin/transfused')
|
||||||
[ $? -eq 0 ] && printf "✓ Process 9pudfuse running\n" || printf "✗ No 9pudfuse process\n"
|
[ $? -eq 0 ] && printf "✓ Process transfused running\n" || printf "✗ No transfused process\n"
|
||||||
fi
|
fi
|
||||||
MDNS=$(ps -eo args | grep '^/sbin/mdnstool')
|
MDNS=$(ps -eo args | grep '^/sbin/mdnstool')
|
||||||
[ $? -eq 0 ] && printf "✓ Process mdnstool running: $MDNS\n" || printf "✗ No mdnstool process\n"
|
[ $? -eq 0 ] && printf "✓ Process mdnstool running: $MDNS\n" || printf "✗ No mdnstool process\n"
|
||||||
|
@ -27,6 +27,6 @@ start_stop_daemon_args="--background \
|
|||||||
|
|
||||||
depend()
|
depend()
|
||||||
{
|
{
|
||||||
after 9pudc 9pudfuse
|
after 9pudc transfused
|
||||||
before chronyd
|
before chronyd
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
depends()
|
depends()
|
||||||
{
|
{
|
||||||
before acpid docker syslog chronyd
|
before acpid docker syslog chronyd
|
||||||
after 9pinit 9pudfuse
|
after 9pinit transfused
|
||||||
}
|
}
|
||||||
|
|
||||||
start()
|
start()
|
||||||
|
1
alpine/packages/transfused/.gitignore
vendored
Normal file
1
alpine/packages/transfused/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/transfused
|
10
alpine/packages/transfused/Dockerfile
Normal file
10
alpine/packages/transfused/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM alpine:3.3
|
||||||
|
|
||||||
|
RUN apk update && apk upgrade && apk add alpine-sdk
|
||||||
|
|
||||||
|
RUN mkdir -p /transfused
|
||||||
|
WORKDIR /transfused
|
||||||
|
|
||||||
|
COPY . /transfused
|
||||||
|
|
||||||
|
RUN make transfused
|
15
alpine/packages/transfused/Makefile
Normal file
15
alpine/packages/transfused/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DEPS=transfused.c
|
||||||
|
|
||||||
|
all: Dockerfile $(DEPS)
|
||||||
|
docker build -t transfused:build .
|
||||||
|
docker run transfused:build cat transfused > transfused
|
||||||
|
chmod 755 transfused
|
||||||
|
|
||||||
|
transfused: $(DEPS)
|
||||||
|
gcc -g -static -Wall -Werror -o transfused transfused.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f transfused
|
||||||
|
docker images -q transfused:build | xargs docker rmi -f
|
32
alpine/packages/transfused/etc/init.d/transfused
Executable file
32
alpine/packages/transfused/etc/init.d/transfused
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
description="fuse proxy server"
|
||||||
|
|
||||||
|
depend()
|
||||||
|
{
|
||||||
|
need 9pinit
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
[ -d /Transfuse ] || exit 0
|
||||||
|
|
||||||
|
ebegin "Starting FUSE socket passthrough"
|
||||||
|
|
||||||
|
[ -n "${PIDFILE}" ] || PIDFILE=/var/run/transfused.pid
|
||||||
|
|
||||||
|
/sbin/transfused -p "${PIDFILE}" &
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
[ -d /Transfuse ] || exit 0
|
||||||
|
|
||||||
|
ebegin "Stopping FUSE socket passthrough"
|
||||||
|
|
||||||
|
[ -n "${PIDFILE}" ] || PIDFILE=/var/run/transfused.pid
|
||||||
|
|
||||||
|
start-stop-daemon --stop --quiet \
|
||||||
|
--pidfile "${PIDFILE}"
|
||||||
|
eend $? "Failed to stop transfused"
|
||||||
|
}
|
524
alpine/packages/transfused/transfused.c
Normal file
524
alpine/packages/transfused/transfused.c
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#define COPY_BUFSZ 65536
|
||||||
|
|
||||||
|
#define DEFAULT_FUSERMOUNT "/bin/fusermount"
|
||||||
|
#define DEFAULT_SOCKET9P_ROOT "/Transfuse"
|
||||||
|
|
||||||
|
char * default_fusermount = DEFAULT_FUSERMOUNT;
|
||||||
|
char * default_socket9p_root = DEFAULT_SOCKET9P_ROOT;
|
||||||
|
char * usage =
|
||||||
|
"usage: transfused [-p pidfile] [-9 socket9p_root] [-f fusermount]\n"
|
||||||
|
" -p pidfile\tthe path at which to write the pid of the process\n"
|
||||||
|
" -9 " DEFAULT_SOCKET9P_ROOT "\tthe root of the 9p socket file system\n"
|
||||||
|
" -f " DEFAULT_FUSERMOUNT "\tthe fusermount executable to use\n";
|
||||||
|
|
||||||
|
int debug = 0;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char * socket9p_root;
|
||||||
|
char * fusermount;
|
||||||
|
char * pidfile;
|
||||||
|
} parameters;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
parameters * params;
|
||||||
|
long id;
|
||||||
|
} connection_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char * descr;
|
||||||
|
long connection;
|
||||||
|
char * tag;
|
||||||
|
int from;
|
||||||
|
int to;
|
||||||
|
} copy_thread_state;
|
||||||
|
|
||||||
|
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 * ptr;
|
||||||
|
|
||||||
|
ptr = malloc(size);
|
||||||
|
if (size != 0 && ptr == NULL) die(1, descr, "");
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ** read_opts(connection_state * connection, char * buf) {
|
||||||
|
int read_fd;
|
||||||
|
char * read_path;
|
||||||
|
int read_count;
|
||||||
|
int optc = 1;
|
||||||
|
char ** optv;
|
||||||
|
|
||||||
|
if (asprintf(&read_path, "%s/connections/%ld/read",
|
||||||
|
connection->params->socket9p_root, connection->id) == -1)
|
||||||
|
die(1, "Couldn't allocate read path", "");
|
||||||
|
|
||||||
|
read_fd = open(read_path, O_RDONLY);
|
||||||
|
if (read_fd == -1)
|
||||||
|
die(1, "couldn't open read path", "For connection %ld, ", connection->id);
|
||||||
|
|
||||||
|
read_count = read(read_fd, buf, COPY_BUFSZ - 1);
|
||||||
|
if (read_count == -1) die(1, "read_opts error reading", "");
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(read_path);
|
||||||
|
|
||||||
|
return optv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t message_id(uint64_t * message) {
|
||||||
|
return message[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(copy_thread_state * copy_state) {
|
||||||
|
int from = copy_state->from;
|
||||||
|
int to = copy_state->to;
|
||||||
|
char * descr = copy_state->descr;
|
||||||
|
int read_count, write_count;
|
||||||
|
long connection = copy_state->connection;
|
||||||
|
char * tag = copy_state->tag;
|
||||||
|
void * buf;
|
||||||
|
|
||||||
|
buf = must_malloc(descr, COPY_BUFSZ);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
read_count = read(from, buf, COPY_BUFSZ);
|
||||||
|
if (read_count == -1) die(1, "", "copy %s: error reading: ", descr);
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
int trace_fd;
|
||||||
|
char * trace_path;
|
||||||
|
|
||||||
|
if (asprintf(&trace_path, "/tmp/transfused.%ld.%s.%llu",
|
||||||
|
connection, tag, message_id(buf)) == -1)
|
||||||
|
die(1, "Couldn't allocate trace packet path", "");
|
||||||
|
|
||||||
|
trace_fd = open(trace_path, O_WRONLY | O_CREAT, 0600);
|
||||||
|
if (trace_fd == -1)
|
||||||
|
die(1, "couldn't open trace packet path", "For %s, ", descr);
|
||||||
|
|
||||||
|
write_count = write(trace_fd, buf, read_count);
|
||||||
|
if (write_count == -1)
|
||||||
|
die(1, "", "copy %s trace: error writing %s: ", descr, trace_path);
|
||||||
|
|
||||||
|
if (write_count != read_count)
|
||||||
|
die(1, NULL, "copy %s trace: read %d but only write %d\n",
|
||||||
|
descr, read_count, write_count);
|
||||||
|
|
||||||
|
close(trace_fd);
|
||||||
|
free(trace_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_count = write(to, buf, read_count);
|
||||||
|
if (write_count == -1) die(1, "", "copy %s: error writing: ", descr);
|
||||||
|
|
||||||
|
if (write_count != read_count)
|
||||||
|
die(1, NULL, "copy %s: read %d by only wrote %d\n",
|
||||||
|
descr, read_count, write_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * copy_clean_from(copy_thread_state * copy_state) {
|
||||||
|
copy(copy_state);
|
||||||
|
|
||||||
|
close(copy_state->from);
|
||||||
|
|
||||||
|
free(copy_state->descr);
|
||||||
|
free(copy_state);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * copy_clean_from_thread(void * copy_state) {
|
||||||
|
return (copy_clean_from((copy_thread_state *) copy_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void * copy_clean_to(copy_thread_state * copy_state) {
|
||||||
|
copy(copy_state);
|
||||||
|
|
||||||
|
close(copy_state->to);
|
||||||
|
|
||||||
|
free(copy_state->descr);
|
||||||
|
free(copy_state);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int recv_fd(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, "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(char * fusermount, char *const optv[]) {
|
||||||
|
int optc;
|
||||||
|
char ** argv;
|
||||||
|
char * envp[2];
|
||||||
|
pid_t fusermount_pid;
|
||||||
|
int fuse_socks[2];
|
||||||
|
int status;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
// prepare argv from optv
|
||||||
|
for (optc = 0; optv[optc] != NULL; optc++) {}
|
||||||
|
|
||||||
|
argv = (char **) must_malloc("fusermount argv", (optc + 2) * sizeof(char *));
|
||||||
|
|
||||||
|
argv[0] = fusermount;
|
||||||
|
memcpy(&argv[1], optv, (optc + 1) * sizeof(char *));
|
||||||
|
|
||||||
|
// make the socket over which we'll be sent the FUSE socket fd
|
||||||
|
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fuse_socks))
|
||||||
|
die(1, "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, "Couldn't allocate fusermount envp", "");
|
||||||
|
|
||||||
|
envp[1] = 0x0;
|
||||||
|
|
||||||
|
// fork and exec fusermount
|
||||||
|
fusermount_pid = fork();
|
||||||
|
if (!fusermount_pid) // child
|
||||||
|
if (execve(fusermount, argv, envp))
|
||||||
|
die(1, "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, NULL, "fusermount terminated abnormally\n");
|
||||||
|
|
||||||
|
if (WEXITSTATUS(status))
|
||||||
|
die(1, NULL, "fusermount exited with code %d\n", WEXITSTATUS(status));
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, "about to recv_fd from fusermount\n");
|
||||||
|
|
||||||
|
fd = recv_fd(fuse_socks[1]);
|
||||||
|
if (fd == -1)
|
||||||
|
die(1, NULL, "Couldn't receive fd over FUSE socket\n");
|
||||||
|
|
||||||
|
// close the read end of the socket
|
||||||
|
close(fuse_socks[1]);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_reader(connection_state * connection, int fuse) {
|
||||||
|
int read_fd;
|
||||||
|
char * read_path;
|
||||||
|
pthread_t child;
|
||||||
|
copy_thread_state * copy_state;
|
||||||
|
|
||||||
|
if (asprintf(&read_path, "%s/connections/%ld/read",
|
||||||
|
connection->params->socket9p_root, connection->id) == -1)
|
||||||
|
die(1, "Couldn't allocate read path", "");
|
||||||
|
|
||||||
|
read_fd = open(read_path, O_RDONLY);
|
||||||
|
if (read_fd == -1)
|
||||||
|
die(1, "couldn't open read path", "For connection %ld, ", connection->id);
|
||||||
|
|
||||||
|
copy_state = (copy_thread_state *) must_malloc("start_reader copy_state",
|
||||||
|
sizeof(copy_thread_state));
|
||||||
|
copy_state->descr = read_path;
|
||||||
|
copy_state->connection = connection->id;
|
||||||
|
copy_state->tag = "read";
|
||||||
|
copy_state->from = read_fd;
|
||||||
|
copy_state->to = fuse;
|
||||||
|
if ((errno = pthread_create(&child, NULL,
|
||||||
|
copy_clean_from_thread, copy_state)))
|
||||||
|
die(1, "", "couldn't create read copy thread for connection %ld: ",
|
||||||
|
connection->id);
|
||||||
|
|
||||||
|
if ((errno = pthread_detach(child)))
|
||||||
|
die (1, "", "couldn't detach read copy thread for connection '%ld': ",
|
||||||
|
connection->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_write(connection_state * connection, int fuse) {
|
||||||
|
int write_fd;
|
||||||
|
char * write_path;
|
||||||
|
copy_thread_state * copy_state;
|
||||||
|
|
||||||
|
if (asprintf(&write_path, "%s/connections/%ld/write",
|
||||||
|
connection->params->socket9p_root, connection->id) == -1)
|
||||||
|
die(1, "Couldn't allocate write path", "");
|
||||||
|
|
||||||
|
write_fd = open(write_path, O_WRONLY);
|
||||||
|
if (write_fd == -1)
|
||||||
|
die(1, "couldn't open write path", "For connection %ld, ", connection->id);
|
||||||
|
|
||||||
|
copy_state = (copy_thread_state *) must_malloc("do_write copy_state",
|
||||||
|
sizeof(copy_thread_state));
|
||||||
|
copy_state->descr = write_path;
|
||||||
|
copy_state->connection = connection->id;
|
||||||
|
copy_state->tag = "write";
|
||||||
|
copy_state->from = fuse;
|
||||||
|
copy_state->to = write_fd;
|
||||||
|
copy_clean_to(copy_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * handle_connection(connection_state * connection) {
|
||||||
|
char ** optv;
|
||||||
|
int fuse;
|
||||||
|
char * buf;
|
||||||
|
|
||||||
|
buf = (char *) must_malloc("read_opts packet malloc", COPY_BUFSZ);
|
||||||
|
|
||||||
|
optv = read_opts(connection, buf);
|
||||||
|
fuse = get_fuse_sock(connection->params->fusermount, optv);
|
||||||
|
free(optv);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
start_reader(connection, fuse);
|
||||||
|
do_write(connection, fuse);
|
||||||
|
free(connection);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * handle_connection_thread(void * connection) {
|
||||||
|
return handle_connection((connection_state *) connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggle_debug(int sig) {
|
||||||
|
debug = !debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_debug() {
|
||||||
|
if (SIG_ERR == signal(SIGHUP, toggle_debug))
|
||||||
|
die(1, "Couldn't set SIGHUP behavior", "");
|
||||||
|
|
||||||
|
if (siginterrupt(SIGHUP, 1))
|
||||||
|
die(1, "Couldn't set siginterrupt for SIGHUP", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_parameters(int argc, char * argv[], parameters * params) {
|
||||||
|
int c;
|
||||||
|
int errflg = 0;
|
||||||
|
|
||||||
|
params->pidfile = NULL;
|
||||||
|
params->socket9p_root = NULL;
|
||||||
|
params->fusermount = NULL;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, ":p:9:f:")) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
params->pidfile = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '9':
|
||||||
|
params->socket9p_root = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
params->fusermount = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':':
|
||||||
|
fprintf(stderr, "Option -%c requires a path argument\n", optopt);
|
||||||
|
errflg++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
fprintf(stderr, "Unrecognized option: '-%c'\n", optopt);
|
||||||
|
errflg++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Internal error parsing -%c\n", c);
|
||||||
|
errflg++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errflg) die(2, NULL, usage);
|
||||||
|
|
||||||
|
if (params->pidfile != NULL && access(params->pidfile, W_OK))
|
||||||
|
if (errno != ENOENT)
|
||||||
|
die(2, "", "-p %s path to pidfile must be writable: ", params->pidfile);
|
||||||
|
|
||||||
|
if (params->fusermount == NULL)
|
||||||
|
params->fusermount = default_fusermount;
|
||||||
|
if (access(params->fusermount, X_OK))
|
||||||
|
die(2, "", "-f %s path to fusermount must be executable: ",
|
||||||
|
params->fusermount);
|
||||||
|
|
||||||
|
if (params->socket9p_root == NULL)
|
||||||
|
params->socket9p_root = default_socket9p_root;
|
||||||
|
if (access(params->socket9p_root, X_OK))
|
||||||
|
die(2, "", "-9 %s path to socket 9p root directory must be executable: ",
|
||||||
|
params->socket9p_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_pidfile(char * pidfile) {
|
||||||
|
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, "Couldn't allocate pidfile string", "");
|
||||||
|
|
||||||
|
pid_s_len = strlen(pid_s);
|
||||||
|
|
||||||
|
fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if (fd == -1)
|
||||||
|
die(1, "", "Couldn't open pidfile path %s: ", pidfile);
|
||||||
|
|
||||||
|
write_count = write(fd, pid_s, pid_s_len);
|
||||||
|
if (write_count == -1)
|
||||||
|
die(1, "", "Error writing pidfile %s: ", pidfile);
|
||||||
|
|
||||||
|
if (write_count != pid_s_len)
|
||||||
|
die(1, NULL, "Error writing %s to pidfile %s: only wrote %d bytes\n",
|
||||||
|
pid_s, pidfile, write_count);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
free(pid_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ID_LEN 512
|
||||||
|
|
||||||
|
void process_events(char * events_path, int events, parameters * params) {
|
||||||
|
char buf[ID_LEN];
|
||||||
|
int read_count;
|
||||||
|
long conn_id;
|
||||||
|
pthread_t child;
|
||||||
|
connection_state * conn;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
read_count = read(events, buf, ID_LEN - 1);
|
||||||
|
if (read_count == -1) {
|
||||||
|
die(1, "", "Error reading events path %s: ", events_path);
|
||||||
|
} else if (read_count == 0) {
|
||||||
|
// TODO: this is probably the 9p server's fault due to
|
||||||
|
// not dropping the read 0 to force short read if
|
||||||
|
// the real read is flushed
|
||||||
|
fprintf(stderr, "read 0 from event stream %s\n", events_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[read_count] = 0x0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
conn_id = strtol(buf, NULL, 10);
|
||||||
|
if (errno) die(1, "failed", "Connection id of string '%s'", buf);
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, "handle connection %ld\n", conn_id);
|
||||||
|
|
||||||
|
conn = (connection_state *) must_malloc("connection state",
|
||||||
|
sizeof(connection_state));
|
||||||
|
conn->id = conn_id;
|
||||||
|
conn->params = params;
|
||||||
|
|
||||||
|
if ((errno = pthread_create(&child, NULL,
|
||||||
|
handle_connection_thread, conn)))
|
||||||
|
die(1, "", "Couldn't create thread for connection '%ld': ", conn_id);
|
||||||
|
|
||||||
|
if ((errno = pthread_detach(child)))
|
||||||
|
die(1, "", "Couldn't detach thread for connection '%ld': ", conn_id);
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, "thread spawned\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
int events;
|
||||||
|
parameters params;
|
||||||
|
char * events_path;
|
||||||
|
|
||||||
|
parse_parameters(argc, argv, ¶ms);
|
||||||
|
setup_debug();
|
||||||
|
|
||||||
|
if (params.pidfile != NULL) write_pidfile(params.pidfile);
|
||||||
|
|
||||||
|
if (asprintf(&events_path, "%s/events", params.socket9p_root) == -1)
|
||||||
|
die(1, "Couldn't allocate events path", "");
|
||||||
|
|
||||||
|
events = open(events_path, O_RDONLY | O_CLOEXEC);
|
||||||
|
if (events != -1) process_events(events_path, events, ¶ms);
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to open events path %s: ", events_path);
|
||||||
|
perror("");
|
||||||
|
free(events_path);
|
||||||
|
return 1;
|
||||||
|
}
|
@ -17,7 +17,7 @@ fi
|
|||||||
#IMG_HDD="-s 4,virtio-blk,/somepath/somefile.img"
|
#IMG_HDD="-s 4,virtio-blk,/somepath/somefile.img"
|
||||||
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
|
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
|
||||||
RND="-s 5,virtio-rnd"
|
RND="-s 5,virtio-rnd"
|
||||||
FS="-s 6,virtio-9p,path=9pudfuse.sock,tag=fuse"
|
FS="-s 6,virtio-9p,path=transfused.sock,tag=fuse"
|
||||||
LPC_DEV="-l com1,stdio"
|
LPC_DEV="-l com1,stdio"
|
||||||
ACPI="-A"
|
ACPI="-A"
|
||||||
CLOCK="-u"
|
CLOCK="-u"
|
||||||
|
Loading…
Reference in New Issue
Block a user