+backend.cmo: inotify.cmi globals.cmo frontend.cmo fifowatcher.cmo \
+ dirwatcher.cmo
+backend.cmx: inotify.cmi globals.cmx frontend.cmx fifowatcher.cmx \
+ dirwatcher.cmx
+conffile.cmo: globals.cmo
+conffile.cmx: globals.cmx
+directfifowatcher.cmo: splice.cmo inotify.cmi globals.cmo dirwatcher.cmo
+directfifowatcher.cmx: splice.cmx inotify.cmi globals.cmx dirwatcher.cmx
dirwatcher.cmo: inotify.cmi globals.cmo fdwatcher.cmo
dirwatcher.cmx: inotify.cmi globals.cmx fdwatcher.cmx
fdwatcher.cmo: globals.cmo
fdwatcher.cmx: globals.cmx
-fifowatcher.cmo: inotify.cmi globals.cmo fdwatcher.cmo dirwatcher.cmo
-fifowatcher.cmx: inotify.cmi globals.cmx fdwatcher.cmx dirwatcher.cmx
-frontend.cmo: globals.cmo fifowatcher.cmo
-frontend.cmx: globals.cmx fifowatcher.cmx
+fifowatcher.cmo: splice.cmo inotify.cmi globals.cmo fdwatcher.cmo \
+ dirwatcher.cmo
+fifowatcher.cmx: splice.cmx inotify.cmi globals.cmx fdwatcher.cmx \
+ dirwatcher.cmx
+frontend.cmo: globals.cmo directfifowatcher.cmo
+frontend.cmx: globals.cmx directfifowatcher.cmx
main.cmo: inotify.cmi globals.cmo frontend.cmo fifowatcher.cmo fdwatcher.cmo \
- dirwatcher.cmo backend.cmo
+ dirwatcher.cmo conffile.cmo backend.cmo
main.cmx: inotify.cmi globals.cmx frontend.cmx fifowatcher.cmx fdwatcher.cmx \
- dirwatcher.cmx backend.cmx
+ dirwatcher.cmx conffile.cmx backend.cmx
ocaml_inotify-0.4/inotify.cmxa:
$(MAKE) -C ocaml_inotify-0.4 && cp -f ocaml_inotify-0.4/inotify_stubs.o ./
-vsys: ocaml_inotify-0.4/inotify.cmxa globals.cmx fdwatcher.cmx conffile.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx main.cmx docs
- ocamlopt -I ocaml_inotify-0.4 str.cmxa unix.cmxa inotify.cmxa globals.cmx fdwatcher.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx str.cmxa conffile.cmx main.cmx -o vsys
+splice_stub.o: splice_stub.c
+ gcc -c -I /usr/lib/ocaml -I /usr/lib64/ocaml splice_stub.c -o splice_stub.o
-vsys.b: inotify.cma inotify.cmi globals.ml fdwatcher.ml dirwatcher.ml fifowatcher.ml frontend.ml backend.ml main.ml
- ocamlc -g str.cma unix.cma inotify.cma globals.cmo fdwatcher.cmo dirwatcher.cmo fifowatcher.cmo frontend.cmo backend.cmo str.cma main.cmo -o vsys.b
+vsys: ocaml_inotify-0.4/inotify.cmxa globals.cmx fdwatcher.cmx conffile.cmx splice_stub.o splice.cmx dirwatcher.cmx fifowatcher.cmx frontend.cmx backend.cmx main.cmx docs
+ ocamlopt -I ocaml_inotify-0.4 str.cmxa unix.cmxa inotify.cmxa globals.cmx fdwatcher.cmx dirwatcher.cmx splice.cmx splice_stub.o directfifowatcher.cmx frontend.cmx backend.cmx str.cmxa conffile.cmx main.cmx -o vsys
+
+vsys.b: ocaml_inotify-0.4/inotify.cma inotify.cmi globals.ml fdwatcher.ml dirwatcher.ml directfifowatcher.ml frontend.ml backend.ml main.ml
+ ocamlc -g str.cma unix.cma ocaml_inotify-0.4/inotify.cma globals.cmo fdwatcher.cmo dirwatcher.cmo directfifowatcher.cmo frontend.cmo backend.cmo str.cma conffile.cmo main.cmo -o vsys.b
install: vsys
cp vsys $(INSTALL_DIR)/usr/bin
open Frontend
open Printf
-(** Helper functions:
-
-*)
-
(** Turn an absolute path into a relative path. *)
let delete_prefix prefix str =
let len = String.length str in
| [] -> false
| car::cdr -> if (car==elt) then true else list_check cdr elt
-
(** The backendhandler class: defines event handlers for events in
the backend backend directory.
@param dir_root The location of the backend in the server context (eg. root context for vservers)
let mk_rel_path = delete_prefix dir_root in object(this)
(** Regular expression that defines a legal script name. Filter out
- * temporary files using this *)
- val file_regexp = Str.regexp "[a-zA-Z][a-zA-Z0-9_\.]*"
+ * temporary files using it *)
+ val file_regexp = Str.regexp "^[a-zA-Z][a-zA-Z0-9_\.\-]*$"
val acl_file_regexp = Str.regexp ".*acl$"
- val dir_regexp = Str.regexp "^dir_";
- val acl_regexp = Str.regexp ".*_.*";
-
(** Somebody created a new directory *)
- (* XXX Race condition here *)
method private new_dir slice_list fqp func =
let s = Unix.stat fqp in
List.iter
(fun frontend->
try begin
frontend#mkdir (mk_rel_path fqp) (s.st_perm);
- Dirwatcher.add_watch fqp [S_Create;S_Delete] (Some(func))
+ Dirwatcher.add_watch fqp [S_Create;S_Delete] func
end
with _ ->
- printf "Could not create %s. Looks like a slice shot itself in the foot\n" fqp;flush Pervasives.stdout;
+ logprint "Could not create %s. Looks like a slice shot itself in the foot\n" fqp;
)
slice_list
(** Somebody copied in a new script *)
- (* XXX Race condition here *)
method private new_script slice_list fqp =
let s = Unix.stat fqp in
List.iter (fun frontend->
- frontend#mkentry (mk_rel_path fqp) fqp (s.st_perm)) slice_list
+ frontend#mkentry (mk_rel_path fqp) fqp (s.st_perm))
+ slice_list
method private make_filter acl_fqp =
let filter = Hashtbl.create 16 in
with _ -> None
in
match next_item with
- | None -> cur_filter
+ | None -> close_in acl_file;cur_filter
| Some(item) ->
Hashtbl.add cur_filter item true;
read_acl cur_filter
with _ ->
None
+ method is_acl fname = Str.string_match acl_file_regexp fname 0
+
(** Gets called every time there's an inotify event at the backend
@param dirname Name of the backend directory
@param evlist Description of what happened
@param fname Name of the file that the event applies to
*)
- method handle_dir_event dirname evlist fname =
+ method handle_dir_event _ dirname evlist fname =
let fqp = String.concat "/" [dirname;fname] in
if ((Str.string_match file_regexp fname 0) && not (Str.string_match acl_file_regexp fname 0)) then
begin
let acl_filter = this#make_filter acl_fqp in
let slice_list =
match acl_filter with
- | None -> frontend_lst
- | Some(filter) -> List.filter (fun fe->Hashtbl.mem filter (fe#get_slice_name ())) frontend_lst
+ | None -> [] (* No ACL *)
+ | Some(filter) -> List.filter
+ (fun fe->Hashtbl.mem filter (fe#get_slice_name ()))
+ frontend_lst
in
let is_event = list_check evlist in
if (is_event Create) then
else
(* It's a new script *)
begin
- (*
- if (Str.string_match dir_regexp fname 0) then
- let fqp = String.concat "/" [dirname;String.sub fname 4 ((String.length fname)-4+1)] in
- let real_fqp = String.concat "/" [dirname;fname] in
- this#new_dir fqp this#handle_spool_event;
- Hashtbl.add spools fqp real_fqp
- else*)
this#new_script slice_list fqp
end
end
end
end
else (* regex not matched *)
- ()
+ fprintf logfd "Rejected weird entry %s\n" fname
(** Initializer - build the initial tree based on the contents of /vsys *)
initializer
let cont = ref true in
while (!cont) do
try
- let curfile = readdir dir_handle in
- let fqp = String.concat "/" [dir;curfile] in
- let acl_fqp = String.concat "." [fqp;"acl"] in
- let acl_filter = this#make_filter acl_fqp in
- let slice_list =
- match acl_filter with
- | None -> frontend_lst
- | Some(filter) -> List.filter (fun fe->Hashtbl.mem filter (fe#get_slice_name ())) frontend_lst
- in
- if (Str.string_match file_regexp curfile 0 && not (Str.string_match acl_file_regexp curfile 0)) then
- let s = Unix.stat fqp in
- begin
- match s.st_kind with
- | S_DIR ->
- this#new_dir slice_list fqp this#handle_dir_event;
- build_initial_tree fqp;
- | S_REG ->
- this#new_script slice_list fqp
- | _ ->
- printf "Don't know what to do with %s\n" curfile;flush Pervasives.stdout
- end
- with
- _->cont:=false;()
+ let curfile = readdir dir_handle in
+ if (not (this#is_acl curfile)) then
+ begin
+ let fqp = String.concat "/" [dir;curfile] in
+ let acl_fqp = String.concat "." [fqp;"acl"] in
+ let acl_filter = this#make_filter acl_fqp in
+ let slice_list =
+ match acl_filter with
+ | None -> [] (*frontend_lst -> No ACL => No Show *)
+ | Some(filter) -> List.filter
+ (fun fe->Hashtbl.mem filter (fe#get_slice_name ()))
+ frontend_lst
+ in
+ if (Str.string_match file_regexp curfile 0) then
+ let s = Unix.stat fqp in
+ begin
+ match s.st_kind with
+ | S_DIR ->
+ this#new_dir slice_list fqp this#handle_dir_event;
+ build_initial_tree fqp;
+ | S_REG ->
+ this#new_script slice_list fqp
+ | _ ->
+ logprint "Don't know what to do with %s\n" curfile
+ end
+ end
+ with _
+ ->cont:=false;()
done
in
begin
build_initial_tree dir_root;
- Dirwatcher.add_watch dir_root [S_Create;S_Delete] (Some(this#handle_dir_event));
+ Dirwatcher.add_watch dir_root [S_Create;S_Delete] (this#handle_dir_event);
end
end
open Printf
+open Globals
open Scanf
let split_conf_line s =
sscanf s "%s %s" (fun s1 s2->(s1,s2))
+let check_dir fe =
+ let (vsysdir,slice) = fe in
+ let verdict = try Some(Unix.stat vsysdir) with
+ _ -> logprint "vsys directory not setup for slice %s\n" slice;None
+ in
+ match verdict with
+ | None->false
+ | Some(_) -> true
+
+let rec in_list elt lst =
+ match lst with
+ | car::cdr ->
+ if (elt = car) then true else in_list elt cdr
+ | [] -> false
+
let read_frontends f =
- let f_file = try open_in f with e -> printf "Could not open config
- file\n";flush Pervasives.stdout;raise e
+ let setup_ok = if (!Globals.failsafe) then check_dir else fun _ -> true in
+ let f_file = try open_in f with e -> logprint "Could not open config file\n";raise e
in
let rec read_conf_file cur_list =
let next_line = try Some(input_line f_file) with _ -> None in
match next_line with
- | Some(inp_line) -> read_conf_file (split_conf_line(inp_line)::cur_list)
+ | Some(inp_line) ->
+ let fe = split_conf_line inp_line in
+ let new_list = if (not (in_list fe cur_list) && (setup_ok(fe))) then (fe::cur_list) else cur_list
+ in
+ read_conf_file new_list
| None -> cur_list
in
read_conf_file []
--- /dev/null
+(** directfifowatcher.ml: Routines to handle non-persistent scripts *)
+(* Semantics:
+ * - The 'out' descriptor must be opened first
+ * - As soon as the backend script dies, the connection to the entry is
+ * closed.
+ * - To avoid user-inflicted pain, all entries are opened at the time
+ * that they are created. Reopening these entries is a little complicated
+ * but nevertheless sound:
+ * * When a script dies, its fd is reopened
+ * * If a script fails to execute, its fd is closed and reopened to
+ * beat a race that can happen when the user closes the connection
+ * before the script can be launched.
+ *)
+
+open Inotify
+open Unix
+open Globals
+open Dirwatcher
+open Printf
+open Splice
+
+let close_if_open fd = (try (ignore(close fd);) with _ -> ())
+
+type in_pathname = string
+type directory = string
+type base_pathname = string
+type slice_name = string
+
+let direct_fifo_table: (in_pathname,(directory*base_pathname*slice_name*Unix.file_descr) option) Hashtbl.t =
+ Hashtbl.create 1024
+
+let pidmap: (int,in_pathname * Unix.file_descr) Hashtbl.t = Hashtbl.create 1024
+
+let move_gate fname =
+ let tmpfname=String.concat "." [fname;"tmp"] in
+ Unix.rename fname tmpfname;
+ tmpfname
+
+let move_ungate fname restore =
+ Unix.rename restore fname
+
+let list_check lst elt _ =
+ let rec list_check_rec lst =
+ match lst with
+ | [] -> false
+ | car::cdr ->
+ if (car==elt) then
+ true
+ else
+ list_check_rec cdr
+ in
+ list_check_rec lst
+
+let openentry_int fifoin =
+ let fdin =
+ try openfile fifoin [O_RDONLY;O_NONBLOCK] 0o777 with
+ e->logprint "Error opening and connecting FIFO: %s,%o\n" fifoin 0o777;raise e
+ in
+ fdin
+
+(** Open entry safely, by first masking out the file to be opened *)
+let openentry_safe root_dir fqp_in backend_spec =
+ let restore = move_gate fqp_in in
+ let fd_in = openentry_int restore in
+ move_ungate fqp_in restore;
+ let (fqp,slice_name) = backend_spec in
+ Hashtbl.replace direct_fifo_table fqp_in (Some(root_dir,fqp,slice_name,fd_in))
+
+let openentry root_dir fqp backend_spec =
+ let fqp_in = String.concat "." [fqp;"in"] in
+ openentry_safe root_dir fqp_in backend_spec
+
+let reopenentry fifoin =
+ let entry = try Hashtbl.find direct_fifo_table fifoin with _ -> None in
+ match entry with
+ | Some(dir, fqp,slice_name,fd) -> close_if_open fd;openentry_safe dir fifoin (fqp,slice_name)
+ | None -> ()
+
+(* vsys is activated when a client opens an in file *)
+let connect_file fqp_in =
+ (* Do we care about this file? *)
+ let entry_info = try
+ Hashtbl.find direct_fifo_table fqp_in with _ -> None in
+ match entry_info with
+ | Some(_,execpath,slice_name,fifo_fdin) ->
+ begin
+ let len = String.length fqp_in in
+ let fqp = String.sub fqp_in 0 (len-3) in
+ let fqp_out = String.concat "." [fqp;"out"] in
+ let fifo_fdout =
+ try openfile fqp_out [O_WRONLY;O_NONBLOCK] 0o777 with
+ _-> (* The client is opening the descriptor too fast *)
+ sleep 1;try openfile fqp_out [O_WRONLY;O_NONBLOCK] 0o777 with
+ _->
+ logprint "%s Output pipe not open, using stdout in place of %s\n" slice_name fqp_out;stdout
+ in
+ ignore(sigprocmask SIG_BLOCK [Sys.sigchld]);
+ (
+ clear_nonblock fifo_fdin;
+ let pid=try Some(create_process execpath [|execpath;slice_name|] fifo_fdin fifo_fdout fifo_fdout) with e -> None in
+ match pid with
+ | Some(pid) ->
+ if (fifo_fdout <> stdout) then close_if_open fifo_fdout;
+ Hashtbl.add pidmap pid (fqp_in,fifo_fdout)
+ | None ->logprint "Error executing service: %s\n" execpath;reopenentry fqp_in
+ );
+ ignore(sigprocmask SIG_UNBLOCK [Sys.sigchld]);
+ end
+ | None -> ()
+
+
+(** Make a pair of fifo entries *)
+let mkentry fqp abspath perm uname =
+ logprint "Making entry %s->%s\n" fqp abspath;
+ let fifoin=sprintf "%s.in" fqp in
+ let fifoout=sprintf "%s.out" fqp in
+ (try Unix.unlink fifoin with _ -> ());
+ (try Unix.unlink fifoout with _ -> ());
+ (try
+ let infname =(sprintf "%s.in" fqp) in
+ let outfname =(sprintf "%s.out" fqp) in
+ Unix.mkfifo infname 0o666;
+ Unix.mkfifo outfname 0o666;
+ ( (* Make the user the owner of the pipes in a non-chroot environment *)
+ if (!Globals.nochroot) then
+ let pwentry = Unix.getpwnam uname in
+ Unix.chown infname pwentry.pw_uid pwentry.pw_gid;
+ Unix.chown outfname pwentry.pw_uid pwentry.pw_gid
+ );
+ Success
+ with
+ e->logprint "Error creating FIFO: %s->%s. May be something wrong at the frontend.\n" fqp fifoout;Failed)
+
+
+(** Close fifos that just got removed *)
+let closeentry fqp =
+ let fqp_in = String.concat "." [fqp;"in"] in
+ let entry = try Hashtbl.find direct_fifo_table fqp_in with Not_found -> None in
+ match entry with
+ | None -> ()
+ | Some(_,_,_,fd) ->
+ close_if_open fd;
+ Hashtbl.remove direct_fifo_table fqp_in
+
+let sigchld_handle s =
+ let pid,_=Unix.waitpid [Unix.WNOHANG] 0 in
+ try
+ let fqp_in,fd_out = Hashtbl.find pidmap pid in
+ begin
+ reopenentry fqp_in
+ end
+ with _ -> ()
+
+let rec add_dir_watch fqp =
+ Dirwatcher.add_watch fqp [S_Open] direct_fifo_handler
+and
+ direct_fifo_handler wd dirname evlist fname =
+ let is_event = list_check evlist in
+ if (is_event Open Attrib) then
+ let fqp_in = String.concat "/" [dirname;fname] in
+ connect_file fqp_in
+
+let del_dir_watch fqp =
+ ()
+
+let initialize () =
+ Sys.set_signal Sys.sigchld (Sys.Signal_handle sigchld_handle)
(** Watches directories for events. Agnostic to vsys semantics of backends and
-frontends *)
+ frontends *)
open Inotify
open Fdwatcher
open Printf
(* I don't know if a wd corresponding to a deleted directory is evicted or just
* leaks - fix implementation of rmdir accordingly
*)
-
let wdmap = Hashtbl.create 1024
let fd = Inotify.init ()
+let rec list_check lst elt =
+ match lst with
+ | [] -> false
+ | car::cdr -> if (car==elt) then true else list_check cdr elt
+
+let pevlist evlist =
+ List.iter
+ (fun e ->
+ logprint "Event: %s\n" (string_of_event e))
+ evlist
+
let handle_dir_event dirname evlist str =
- let fname = String.concat "/" [dirname;str] in
- printf "File: %s. " fname;List.iter
- (fun e ->
- printf "Event: %s\n" (string_of_event e))
- evlist;
- flush Pervasives.stdout
+ let fname = String.concat "/" [dirname;str] in
+ logprint "File: %s. " fname;
+ pevlist evlist
let add_watch dir events handler =
- printf "Adding watch for %s\n" dir;flush Pervasives.stdout;
let wd = Inotify.add_watch fd dir events in
- Hashtbl.add wdmap wd (dir,handler)
+ Hashtbl.add wdmap wd (dir,Some(handler))
+ (* Ignore the possibility that the whole directory can disappear and come
+ * back while it is masked *)
let asciiz s =
let rec findfirstnul str idx len =
if ((idx==len) ||
- (str.[idx]==(char_of_int 0))) then idx
- else
- findfirstnul str (idx+1) len
+ (str.[idx]==(char_of_int 0))) then idx
+ else
+ findfirstnul str (idx+1) len
in
let nulterm = findfirstnul s 0 (String.length s) in
String.sub s 0 nulterm
let receive_event (eventdescriptor:fname_and_fd) (bla:fname_and_fd) =
let (_,fd) = eventdescriptor in
- let evs = Inotify.read fd in
- List.iter (fun x->
- match x with
- | (wd,evlist,_,Some(str)) ->
- let purestr = asciiz(str) in
- let (dirname,handler) =
- try Hashtbl.find wdmap wd with Not_found->printf "Unknown watch descriptor\n";raise Not_found
- in
- (
- match handler with
- | None->handle_dir_event dirname evlist purestr
- | Some(handler)->handler dirname evlist purestr
- )
- | _ -> ())
- evs
+ let evs = Inotify.read fd in
+ List.iter (fun x->
+ match x with
+ | (wd,evlist,_,Some(str)) ->
+ begin
+ let purestr = asciiz(str) in
+ let (dirname,handler) =
+ try Hashtbl.find wdmap wd with Not_found->("",None)
+ in
+ match handler with
+ | None->
+ logprint "Unhandled watch descriptor\n"
+ | Some(handler)->
+ let fqp = String.concat "/" [dirname;purestr] in
+ begin
+ handler wd dirname evlist
+ purestr
+ end
+ end
+ | _ -> ())
+ evs
let initialize () =
Fdwatcher.add_fd (None,fd) (None,fd) receive_event
--- /dev/null
+#!/usr/bin/perl
+use strict;
+
+#######################################################
+#
+# run any (allowed) progam in the root context
+#
+#######################################################
+
+my @allowed = ("/bin/df"); # allowed commands
+my $cmdline;
+my $path;
+my $p;
+
+# read command line
+$cmdline = <STDIN>;
+chomp($cmdline);
+
+# identify the path
+if ($cmdline =~ /\s*(.+)\s+/) {
+ $path = $1;
+} else {
+ $path = $cmdline;
+}
+
+# run the program if it's executable and allowed to run
+if (-x $path) {
+ foreach $p (@allowed) {
+ if ($p eq $path) {
+ system($cmdline);
+ exit(0);
+ }
+ }
+ print "fatal: '$cmdline' is not allowed to run\n";
+} else {
+ print "fatal: $path either does not exist or is not executable\n";
+}
+
+# some error occurred
+exit(-1);
--- /dev/null
+#!/bin/sh
+# Remove hide_netif network attribute. Attribute is used to hide interfaces that don't have an IP attached.
+
+# $Id$
+
+nattribute --set --nid $1 --flag ~hide_netif
--- /dev/null
+#!/bin/sh
+# Mount the planetflow directory in a slice
+
+#mount --bind /usr/local/fprobe /vservers/$1/pf
+# changed from request of Faiyaz
+DEST="/vservers/$1/pf"
+mount | grep "on $DEST type" > /dev/null
+if [ $? -eq 1 ]; then
+ mount --bind /var/local/fprobe -o ro $DEST
+fi
--- /dev/null
+#!/usr/bin/perl
+use strict;
+
+###############################################
+# pl-ps for slicestat by KyoungSoo Park
+###############################################
+
+my %slice_id;
+my %slice;
+
+open THIS_PIPE, "/bin/awk -F: \'{print \$1, \$3}\' /etc/passwd |";
+while(<THIS_PIPE>) {
+ if (/(.+)\s+(\d+)/) {
+ $slice_id{$1} = $2;
+ $slice{$2} = $1;
+ }
+}
+close THIS_PIPE;
+
+open THIS_PIPE, "/usr/sbin/vps -eo pid,user | sed 1d | awk \'{print \$1, \$2}\' | sort -k 2 |";
+while(<THIS_PIPE>) {
+ if (/(\d+)\s+(.+)$/) {
+ my $pid = $1;
+ my ($id, $sl);
+
+ if (defined($slice_id{$2})) {
+ $id = $slice_id{$2};
+ $sl = $2;
+ } else {
+ $id = $2;
+ $sl = $slice{$2};
+ }
+ print sprintf("%s %s %s\n", $id, $sl, $pid);
+ }
+}
+close THIS_PIPE;
--- /dev/null
+#!/bin/sh +x
+
+IP=/sbin/ip
+
+SLICE=$1
+SLICEID=`id -u $SLICE`
+read INDEX
+read REMOTE
+read KEY
+
+LINK=${KEY}if${INDEX}
+
+modprobe ip_gre
+modprobe etun
+
+### Setup EGRE tunnel
+EGRE=d$LINK
+$IP tunnel add $EGRE mode gre/eth remote $REMOTE key $KEY
+$IP link set $EGRE up
+
+### Setup etun
+ETUN0=a$LINK
+ETUN1=b$LINK
+echo $ETUN0,$ETUN1 > /sys/module/etun/parameters/newif
+ifconfig $ETUN0 mtu 1458 up
+ifconfig $ETUN1 up
+
+### Setup bridge
+BRIDGE=c$LINK
+brctl addbr $BRIDGE
+brctl addif $BRIDGE $EGRE
+brctl addif $BRIDGE $ETUN1
+ifconfig $BRIDGE up
+
+### Setup iptables so that packets are visible in the vserver
+iptables -t mangle -A FORWARD -o $BRIDGE -j MARK --set-mark $SLICEID
+
+### Create "grab link" script
+GRAB=/vsys/local_grab-$ETUN0
+echo $SLICE > $GRAB.acl
+rm -f $GRAB
+cat > $GRAB <<EOF
+#!/bin/sh
+
+read PID
+
+chcontext --ctx 1 -- echo \$PID > /sys/class/net/$ETUN0/new_ns_pid
+EOF
+chmod +x $GRAB
+
+### Create script for setting link rate
+BIND=/vsys/local_rate-$ETUN0
+echo $SLICE > $BIND.acl
+rm -f $BIND
+cat > $BIND <<EOF
+#!/bin/sh
+
+read rt
+
+tc qdisc add dev $EGRE root handle 1: htb default 10
+tc class add dev $EGRE parent 1: classid 1:10 htb rate \$rt ceil \$rt
+
+rm -rf $BIND.acl
+touch $BIND.acl
+
+EOF
+chmod +x $BIND
+
+### Create "delete link" script
+DELETE=/vsys/local_delete-$ETUN0
+echo $SLICE > $DELETE.acl
+rm -f $DELETE
+cat > $DELETE <<EOF
+#!/bin/sh
+
+read NULL
+
+# Remove iptables rule
+iptables -t mangle -D FORWARD -o $BRIDGE -j MARK --set-mark $SLICEID
+
+# Get rid of etun devices, only need name of one of them
+echo $ETUN1 > /sys/module/etun/parameters/delif
+
+# Get rid of bridge
+ifconfig $BRIDGE down
+brctl delbr $BRIDGE
+
+# Get rid of EGRE tunnel
+ip tunnel del $EGRE
+
+# Clean up files
+rm -f $GRAB $GRAB.acl
+rm -f $DELETE $DELETE.acl
+rm -f $BIND $BIND.acl
+EOF
+chmod +x $DELETE
--- /dev/null
+#!/bin/sh +x
+
+IP=/sbin/ip
+
+SLICE=$1
+SLICEID=`id -u $SLICE`
+read KEY
+
+modprobe etun
+
+### Setup etun
+ETUN0=nat$KEY
+ETUN1=natx$KEY
+echo $ETUN0,$ETUN1 > /sys/module/etun/parameters/newif
+ifconfig $ETUN1 10.0.$KEY.1 up
+
+/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
+/sbin/iptables -A FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
+/sbin/iptables -A FORWARD -i $ETUN1 -o eth0 -j ACCEPT
+
+### Create "grab link" script
+GRAB=/vsys/local_grab-$ETUN0
+echo $SLICE > $GRAB.acl
+rm -f $GRAB
+cat > $GRAB <<EOF
+#!/bin/sh
+
+read PID
+
+chcontext --ctx 1 -- echo \$PID > /sys/class/net/$ETUN0/new_ns_pid
+EOF
+chmod +x $GRAB
+
+### Create "delete link" script
+DELETE=/vsys/local_delete-$ETUN0
+echo $SLICE > $DELETE.acl
+rm -f $DELETE
+cat > $DELETE <<EOF
+#!/bin/sh
+
+read NULL
+
+# Remove iptables rules
+/sbin/iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
+/sbin/iptables -D FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
+/sbin/iptables -D FORWARD -i $ETUN1 -o eth0 -j ACCEPT
+
+# Get rid of etun devices, only need name of one of them
+echo $ETUN1 > /sys/module/etun/parameters/delif
+
+# Clean up files
+rm -f $GRAB $GRAB.acl
+rm -f $DELETE $DELETE.acl
+
+EOF
+chmod +x $DELETE
+
--- /dev/null
+#!/usr/bin/perl
+use strict;
+
+###############################################
+# vtop for slicestat by KyoungSoo Park
+###############################################
+
+open THIS_PIPE, "/usr/sbin/vtop bn1 |";
+while(<THIS_PIPE>) {
+ print;
+}
+close THIS_PIPE;
(** Fdwatcher - The main event loop. Agnostic to the type of file descriptors
- involved.*)
+ involved.*)
open Printf
open Globals
+open Printexc
let fdset = ref []
let cbtable = Hashtbl.create 1024
-(* The in descriptor is always open. Thanks to the broken semantics of
- * fifo outputs, the out descriptor must be opened a nouveau whenever we
- * want to send out data, and so we keep the associated filename as well.
- * Same with input fifos. Yipee.*)
let add_fd (evpair:fname_and_fd) (fd_other:fname_and_fd) (callback:fname_and_fd->fname_and_fd->unit) =
let (fname,fd) = evpair in
- fdset := (fd::!fdset);
- Hashtbl.replace cbtable fd (callback,(evpair,fd_other))
+ fdset := (fd::!fdset);
+ Hashtbl.replace cbtable fd (callback,(evpair,fd_other))
let del_fd fd =
fdset:=List.filter (fun l->l<>fd) !fdset;
- flush Pervasives.stdout
+ flush logfd
let start_watch () =
- while (true)
- do
- let (fds,_,_) = try Unix.select !fdset [] [] (-1.)
- with e->
- ([],[],[])
- in
- List.iter (fun elt->
- let (func,(evd,fd_other)) = Hashtbl.find cbtable elt in
- func evd fd_other) fds
- done
-
+ while (true)
+ do
+ let (fds,_,_) = try Unix.select !fdset [] [] (-1.)
+ with e->
+ ([],[],[])
+ in
+ List.iter (fun elt->
+ let (func,(evd,fd_other)) = Hashtbl.find cbtable elt in
+ try (* Never fail *)
+ func evd fd_other
+ with e->
+ let wtf = Printexc.to_string e in
+ logprint "%s\n" wtf
+ ) fds
+ done
open Globals
open Dirwatcher
open Printf
+open Splice
(** A connected process, FIFO *)
-type channel_pipe = Process of out_channel | Fifo of out_channel | BrokenPipe
-(** Signed file descriptors. Usually, we'll make sure that they're not
- mistreated *)
+type channel_pipe = Process of Unix.file_descr | Fifo of Unix.file_descr | BrokenPipe
+
+(** Signed file descriptors. *)
type signed_fd = Infd of Unix.file_descr | Outfd of Unix.file_descr | Eventfd of Unix.file_descr
+(** XXX This will get deprecated when we switch to inotify *)
let fdmap: (Unix.file_descr,string*string) Hashtbl.t = Hashtbl.create 1024
+
(** Maps pids to slice connections. Needed to clean up fds when a script dies
with EPIPE *)
let pidmap: (int,signed_fd list) Hashtbl.t = Hashtbl.create 1024
let backend_prefix = ref ""
let open_fds: (Unix.file_descr,channel_pipe) Hashtbl.t = Hashtbl.create 1024
-
(** Receive an event from a running script. This event must be relayed to the
slice that invoked it.
let (_,ifd) = idesc in
let cp = try Hashtbl.find open_fds ifd with
Not_found->
- printf "Fifo fd disappeared\n";flush Pervasives.stdout;raise Bug
+ fprintf logfd "Fifo fd disappeared\n";flush logfd;raise Bug
in
match (cp) with
- | Fifo(fifo_outchan) ->
- let process_inchan = in_channel_of_descr ifd in
- let cont = ref true in
- while (!cont) do
- try
- let curline = input_line process_inchan in
- fprintf fifo_outchan "%s\n" curline;flush fifo_outchan
- with
- | End_of_file|Sys_blocked_io|Unix_error(EPIPE,_,_)|Unix_error(EBADF,_,_) ->
- begin
- cont:=false
- end
- | Unix_error(_,s1,s2) -> printf "Unix error %s - %s\n" s1 s2;flush Pervasives.stdout;cont:=false
- | Sys_error(s) -> (* We get this error if the EPIPE comes before the EOF marker*) cont:=false
- | e -> printf "Error - received unexpected event from file system !!!\n";raise e
- done
- | _ -> printf "Bug! Process fd received in the channel handler\n";flush Pervasives.stdout;raise Bug
-
+ | Fifo(fifo_outfd) ->
+ begin
+ try
+ printf "Received process event\n";flush Pervasives.stdout;
+ (* transferred = 4096 => there were at least 4096 bytes in the
+ * stream, so we should try again.
+ * transferred < 4096 => EAGAIN => either this is all the data we
+ * have (move on)
+ * OR XXX the receiver is blocking (supposedly this can't happen) *)
+ let transferred = ref 4096 in
+ while (!transferred == 4096) do
+ transferred:=tee ifd fifo_outfd 4096
+ done;
+ with
+ Failure(s)->fprintf logfd "Transfer failure: %s\n" s;flush logfd
+ end
+ | _ -> fprintf logfd "Bug! Process fd received in the channel handler\n";flush logfd;raise Bug
let rec openentry_int fifoin fifoout (abspath:string*string) =
let fdin =
try openfile fifoin [O_RDONLY;O_NONBLOCK] 0o777 with
- e->printf "Error opening and connecting FIFO: %s,%o\n" fifoin 0o777;flush Pervasives.stdout;raise e
+ e->fprintf logfd "Error opening and connecting FIFO: %s,%o\n" fifoin 0o777;flush logfd;raise e
in
Hashtbl.replace fdmap fdin abspath;
Fdwatcher.add_fd (Some(fifoin),fdin) (Some(fifoout),stdout) receive_fifo_event
close fdin;
Fdwatcher.del_fd fdin;
let abspath = try
- Hashtbl.find fdmap fdin with _ -> printf "Bug: Phantom pipe\n";flush Pervasives.stdout;raise Bug
+ Hashtbl.find fdmap fdin with _ -> fprintf logfd "Bug: Phantom pipe\n";flush logfd;raise Bug
in
openentry_int fifoin fifoout abspath
+
(** receive an event from a fifo and connect to the corresponding service, or to
create it if it doesn't exit
@param eventdescriptor Name of input pipe,in descriptor
| Some(str)->
(
try openfile str [O_WRONLY;O_NONBLOCK] 0o777 with
- _->printf "Output pipe not open, using stdout in place of %s\n" str;flush Pervasives.stdout;stdout
+ _->fprintf logfd "Output pipe not open, using stdout in place of %s\n" str;flush logfd;stdout
)
- | None-> printf "Bug, nameless pipe\n";flush Pervasives.stdout;raise Bug
+ | None-> fprintf logfd "Bug, nameless pipe\n";flush logfd;raise Bug
in
(* Check if the input descriptor is already registered (=> a session is open).
If not, register it and start a new session.*)
let (script_infd,pout) = Unix.pipe () in
let (pin,script_outfd) = Unix.pipe () in
set_nonblock script_infd;
- let rpid = try Some(create_process execpath [|execpath;slice_name|] pin pout pout) with e -> printf "Error executing service: %s\n" execpath;flush Pervasives.stdout;None
+ ignore(sigprocmask SIG_BLOCK [Sys.sigchld]);
+ let rpid = try Some(create_process execpath [|execpath;slice_name|] pin pout pout) with e -> fprintf logfd "Error executing service: %s\n" execpath;flush logfd;None
in
match rpid with
| None-> BrokenPipe
Hashtbl.add pidmap pid [Infd(script_infd);Outfd(script_outfd);Eventfd(evfd)];
(* Connect pipe to running script *)
- Hashtbl.add open_fds evfd (Process(out_channel_of_descr script_outfd));
+ Hashtbl.add open_fds evfd (Process(script_outfd));
(* Connect the running script to the pipe *)
- Hashtbl.add open_fds script_infd (Fifo(out_channel_of_descr outfd));
+ Hashtbl.add open_fds script_infd (Fifo(outfd));
(* Activate running script *)
Fdwatcher.add_fd (None,script_infd) (None,script_infd) receive_process_event;
- (Process(out_channel_of_descr script_outfd))
+ (Process(script_outfd))
in
- (* We have the connection to the process - because it was open, or because it
- just got established *)
- let inchan_fd = in_channel_of_descr evfd in
+ (* We have the connection to the process - because it was open, or because it
+ just got established *)
match (pipe) with
- | Process(out_channel) ->
- let cont = ref true in
- while (!cont) do
- try
- printf "Reading...\n";flush Pervasives.stdout;
- let curline = input_line inchan_fd in
- fprintf out_channel "%s\n" curline;flush out_channel
- with
- |End_of_file->
- (
- match (evfname,fname_other) with
- | Some(str1),Some(str2)->
- printf "Reopening entry\n";flush Pervasives.stdout;
- reopenentry_int evfd str1 str2
- | Some(str1),None ->
- printf "Bug, nameless pipe\n";flush Pervasives.stdout;raise Bug
- | None,_ ->
- printf "Race condition -> user deleted file before closing it. Clever ploy, but won't work.\n";
- flush Pervasives.stdout
- );
- cont:=false
- |Sys_blocked_io ->printf "Sysblockedio\n";flush Pervasives.stdout;
- cont:=false
- | _ ->printf "Bug: unhandled exception\n";flush Pervasives.stdout;raise Bug
- done
+ | Process(fifo_outfd) ->
+ begin
+ try
+ let transferred = ref 4096 in
+ while (!transferred == 4096) do
+ begin
+ transferred:=tee evfd fifo_outfd 4096;
+ printf "Transferred: %d\n" !transferred;flush Pervasives.stdout
+ end
+ done;
+ with Failure(str) ->
+ begin
+ fprintf logfd "Error connecting user to service: %s\n" str;
+ flush logfd
+ end;
+ ignore(sigprocmask SIG_UNBLOCK [Sys.sigchld]);
+ printf "Out of the loop\n";flush Pervasives.stdout
+
+ end
| BrokenPipe -> ()
- | Fifo(_) -> printf "BUG! received process event from fifo\n";raise Bug
+ | Fifo(_) -> fprintf logfd "BUG! received process event from fifo\n";raise Bug
(** Make a pair of fifo entries *)
let mkentry fqp abspath perm uname =
- printf "Making entry %s->%s\n" fqp abspath;flush Pervasives.stdout;
+ fprintf logfd "Making entry %s->%s\n" fqp abspath;flush logfd;
let fifoin=sprintf "%s.in" fqp in
let fifoout=sprintf "%s.out" fqp in
(try Unix.unlink fifoin with _ -> ());
Unix.mkfifo infname 0o666;
Unix.mkfifo outfname 0o666;
( (* Make the user the owner of the pipes in a non-chroot environment *)
- if (!Globals.nochroot) then
- let pwentry = Unix.getpwnam uname in
- Unix.chown infname pwentry.pw_uid pwentry.pw_gid;
- Unix.chown outfname pwentry.pw_uid pwentry.pw_gid
+ if (!Globals.nochroot) then
+ let pwentry = Unix.getpwnam uname in
+ Unix.chown infname pwentry.pw_uid pwentry.pw_gid;
+ Unix.chown outfname pwentry.pw_uid pwentry.pw_gid
);
Success
with
- e->printf "Error creating FIFO: %s->%s. May be something wrong at the frontend.\n" fqp fifoout;flush Pervasives.stdout;Failed)
+ e->fprintf logfd "Error creating FIFO: %s->%s. May be something wrong at the frontend.\n" fqp fifoout;flush logfd;Failed)
(** Open fifos for a session. Will shutdown vsys if the fifos don't exist *)
let openentry fqp abspath perm =
open Printf
open Unix
open Globals
-open Fifowatcher
+open Directfifowatcher
(** frontendhandler class: Methods to create and unlink pipes and directories
@param root_dir vsys directory inside a slice
@param abspath Absolute path of the entry
@param perm Permissions of the entry at the frontend *)
method mkentry (rp:relpath) abspath perm =
- let realperm = perm land (lnot 0o111) in
- match rp with Relpath(rel) ->
- let fqp = String.concat "/" [root_dir;rel] in
- let res = Fifowatcher.mkentry fqp abspath realperm slice_name in
- match res with
- | Success ->
- Fifowatcher.openentry fqp (abspath,slice_name) realperm
- | _ -> ()
+ let realperm = perm land (lnot 0o111) in
+ match rp with Relpath(rel) ->
+ let fqp = String.concat "/" [root_dir;rel] in
+ let res = Directfifowatcher.mkentry fqp abspath realperm slice_name in
+ match res with
+ | Success ->
+ Directfifowatcher.openentry root_dir fqp (abspath,slice_name)
+ | _ -> ()
(** A new directory was created at the backend, make a corresponding directory
at the frontend. Refer to mkentry for parameters *)
method mkdir rp perm =
match rp with Relpath(rel) ->
- let fqp = String.concat "/" [root_dir;rel] in
- try
- let s = Unix.stat fqp in
- if (s.st_kind<>S_DIR) then
- begin
- Unix.unlink fqp;
- Unix.mkdir fqp perm
- end
- else if (s.st_perm <> perm) then
- begin
- printf "Removing directory %s\n" fqp;
- flush Pervasives.stdout;
- Unix.rmdir fqp;
- Unix.mkdir fqp perm
- end
- with Unix.Unix_error(_,_,_) ->
- Unix.mkdir fqp perm
+ let fqp = String.concat "/" [root_dir;rel] in
+ try
+ let s = Unix.stat fqp in
+ if (s.st_kind<>S_DIR) then
+ begin
+ Unix.unlink fqp;
+ Unix.mkdir fqp perm
+ end
+ else if (s.st_perm <> perm) then
+ begin
+ Unix.rmdir fqp;
+ Unix.mkdir fqp perm
+ end;
+ with Unix.Unix_error(_,_,_) ->
+ Unix.mkdir fqp perm;
+ Directfifowatcher.add_dir_watch fqp
(** Functions corresponding to file deletion/directory removal *)
(** *)
method unlink rp =
match rp with Relpath(rel) ->
- let fqp1 = String.concat "/" [root_dir;rel;".in"] in
- let fqp2 = String.concat "/" [root_dir;rel;".out"] in
- try
- Unix.unlink fqp1;
- Unix.unlink fqp2
- with _ ->
- printf "Hm. %s disappeared. Looks like slice %s shot itself in the foot\n" fqp1 (this#get_slice_name ());flush Pervasives.stdout
+ let fqp = String.concat "/" [root_dir;rel] in
+ let fqp_in = String.concat "." [fqp;"in"] in
+ let fqp_out = String.concat "." [fqp;"out"] in
+ Directfifowatcher.closeentry fqp;
+ try
+ Unix.unlink fqp_in;
+ Unix.unlink fqp_out
+ with _ ->
+ logprint "Hm. %s disappeared. Looks like slice %s shot itself in the foot\n" fqp (this#get_slice_name ())
method rmdir rp =
match rp with Relpath(rel) ->
- let fqp = String.concat "/" [root_dir;rel] in
- try
- Unix.rmdir fqp
- with _ ->
- printf "Hm. %s disappeared. Looks like slice %s shot itself in the foot\n" fqp (this#get_slice_name ());flush Pervasives.stdout
+ let fqp = String.concat "/" [root_dir;rel] in
+ Directfifowatcher.del_dir_watch fqp;
+ try
+ Unix.rmdir fqp
+ with _ ->
+ logprint "Hm. %s disappeared or not empty. Looks like slice %s shot itself in the foot\n" fqp (this#get_slice_name ())
+
+ initializer
+ (
+ try
+ let s = Unix.stat root_dir in
+ if (s.st_kind<>S_DIR) then
+ begin
+ Unix.unlink root_dir;
+ Unix.mkdir root_dir 0o700
+ end
+ else if (s.st_perm <> 0o700) then
+ begin
+ Unix.rmdir root_dir;
+ Unix.mkdir root_dir 0o700
+ end;
+ with Unix.Unix_error(_,_,_) ->
+ begin
+ try
+ Unix.mkdir root_dir 0o700;
+ with _ -> ();
+ end);
+ Directfifowatcher.add_dir_watch root_dir
end
(** Some things that didn't fit in elsewhere *)
let backend = ref ""
let debug = ref true
-let vsys_version = "0.5"
+let vsys_version = "0.7"
let nochroot = ref false
let conffile = ref ""
+let pid_filepath = ref "/var/run/vsys.pid"
+let log_filepath = ref "/var/log/vsys"
+let failsafe = ref false
-type result = Success | Failed
+let logfd = open_out_gen [Open_append;Open_creat] 0o644 !log_filepath
+let logprint fmt = Printf.fprintf logfd (fmt ^^ "%!")
+let debprint fmt = if (!debug) then Printf.fprintf logfd (fmt ^^ "%!")
+let print fmt = Printf.printf (fmt ^^ "%!")
+type result = Success | Failed
type fname_and_fd = string option * Unix.file_descr
(* Relative path, never precededed by a '/' *)
open Inotify
open Backend
open Frontend
-open Fifowatcher
open Conffile
let input_file_list = ref []
let cur_dir = ref ""
let cur_slice = ref ""
+let daemonize = ref false
let cmdspeclist =
[
+ ("-daemon",Arg.Set(daemonize), "Daemonize");
("-conffile",Arg.Set_string(Globals.conffile), "Config file");
("-backend",Arg.Set_string(Globals.backend), "Backend directory");
- ("-frontend",Arg.Tuple[Arg.String(fun s->cur_dir:=s);Arg.String(fun s->cur_slice:=s;input_file_list:=(!cur_dir,!cur_slice)::!input_file_list)], "frontendN,slicenameN");
- ("-nochroot",Arg.Set(Globals.nochroot), "Run in non-chroot environment")
+ ("-frontend",Arg.Tuple[Arg.String(fun s->cur_dir:=s);
+ Arg.String(fun s->cur_slice:=s;
+ input_file_list:=(!cur_dir,!cur_slice)::!input_file_list)],
+ "frontendN,slicenameN");
+ ("-nochroot",Arg.Set(Globals.nochroot), "Run in non-chroot environment");
+ ("-failsafe",Arg.Set(Globals.failsafe), "Never crash. Be stupid, but never crash. Use at your own risk.");
]
-let cont = ref true
-
let _ =
- printf "Vsys v%s\n" Globals.vsys_version;flush stdout;
+ logprint "Starting Vsys v%s\n" Globals.vsys_version;
+ print "Starting Vsys v%s\n" Globals.vsys_version;
Arg.parse cmdspeclist (fun x->()) "Usage: vsys <list of mount points>";
if (!Globals.backend == "") then
- printf "Try vsys --help\n"
+ printf "Try vsys --help\n"
else
begin
- Dirwatcher.initialize ();
- Fifowatcher.initialize ();
- if (!Globals.conffile != "") then
- let frontends = Conffile.read_frontends !Globals.conffile in
- input_file_list:=List.concat [!input_file_list;frontends];
+ if (!daemonize) then
+ begin
+ print "Daemonizing\n";
+ let child = Unix.fork () in
+ if (child <> 0) then
+ begin
+ let pidfile = open_out !Globals.pid_filepath in
+ fprintf pidfile "%d" child;
+ close_out pidfile;
+ exit(0)
+ end
+ end;
+
+ Dirwatcher.initialize ();
+ Directfifowatcher.initialize ();
+
+ if (!Globals.conffile <> "") then
+ begin
+ let frontends = Conffile.read_frontends !Globals.conffile in
+ input_file_list:=List.concat [!input_file_list;frontends]
+ end;
- let felst = List.map (fun lst->let (x,y)=lst in printf "Slice %s (%s)\n" x y;flush Pervasives.stdout;new frontendHandler lst) !input_file_list in
- let _ = new backendHandler !Globals.backend felst in
- Fdwatcher.start_watch ()
+ let felst = List.map
+ (fun lst->let (x,y)=lst in
+ logprint "Slice %s (%s)\n" x y;
+ new frontendHandler lst)
+ !input_file_list in
+ let _ = new backendHandler !Globals.backend felst in
+ Fdwatcher.start_watch ()
end
$(OCAMLOPT) $(OCAMLOPTFLAGS) -c -o $@ $<
%.o: %.c
- $(CC) -I /usr/lib/ocaml $(CFLAGS) -c -o $@ $<
+ $(CC) -I /usr/lib/ocaml -I /usr/lib64/ocaml $(CFLAGS) -c -o $@ $<
test.inotify: inotify.cmxa test.inotify.ml
$(OCAMLOPT) -o $@ unix.cmxa $+
--- /dev/null
+open Unix
+
+external splice : Unix.file_descr -> Unix.file_descr -> int -> int
+ = "stub_splice"
+
+external tee : Unix.file_descr -> Unix.file_descr -> int -> int
+ = "stub_tee"
--- /dev/null
+/* This module allows data between vsys clients and servers to be copied in kernel -
+ * and some of these copies to be eliminated through page rewrites */
+
+#define SPLICE_SYSCALL 313
+#define TEE_SYSCALL 315
+#define SPLICE_F_NONBLOCK 0x02
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include <caml/custom.h>
+#include <caml/fail.h>
+#include <caml/signals.h>
+
+CAMLprim value stub_splice(value fd_in, value fd_out, value len)
+{
+ CAMLparam3(fd_in, fd_out, len);
+ long ret;
+ ret = syscall(SPLICE_SYSCALL, Int_val(fd_in), NULL, Int_val(fd_out),NULL, Int_val(len), SPLICE_F_NONBLOCK);
+ if (ret == -1 && errno!=EAGAIN) {
+ caml_failwith("Splice system call returned -1");
+ }
+ CAMLreturn(Val_int(ret));
+}
+
+CAMLprim value stub_tee(value fd_in, value fd_out, value len)
+{
+ CAMLparam3(fd_in, fd_out, len);
+ long ret;
+ ret = syscall(TEE_SYSCALL,Int_val(fd_in), Int_val(fd_out), Int_val(len), SPLICE_F_NONBLOCK);
+ if (ret == -1 && errno!=EAGAIN) {
+ caml_failwith(strerror(errno));
+ }
+ CAMLreturn(Val_int(ret));
+}
--- /dev/null
+Description:
+
+Subtest #1 -
+
+Create a new vsys entry, expect it to show up in a slice
+
+Subtest #2 -
+
+Connect to the entry, receive output, validate it and repeat the process 100
+times.
+
+Subtest #3 -
+
+Clean up the entry and expect it to disappear from within the slice.
+
--- /dev/null
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main()
+{
+ FILE *fp = NULL, *fp_in = NULL;
+ FILE *out_fp = NULL, *diff_fp = NULL;
+ const char* topcmd = "fe/test.out";
+ const char* top_in_file = "fe/test.in";
+ char buf[4096];
+ int fd_in = -1, fd_out;
+ int res;
+ int flag,flag2;
+ int count = 1;
+ struct timeval tv={.tv_sec=5,.tv_usec=0};
+
+ while (count < 1000000) {
+ fd_set readSet;
+ int res;
+ int nlines=0;
+
+ //usleep(200);
+ printf("(%d)", count);fflush(stdout);
+ if ((fd_out = open(topcmd, O_RDONLY | O_NONBLOCK)) < 0) {
+ fprintf(stderr, "error executing top\n");
+ exit(-1);
+ }
+
+ //printf("((0))");fflush(stdout);
+ while ((fd_in = open(top_in_file, O_WRONLY| O_NONBLOCK)) < 0) {
+ fprintf(stderr, "Waiting for %s (%s)\n", top_in_file,strerror(errno));
+ usleep (50);
+ }
+
+ //printf("(1)");
+ if ((flag = fcntl(fd_out, F_GETFL)) == -1) {
+ printf("fcntl get failed\n");
+ exit(-1);
+ }
+ //printf("(2)");
+
+ //printf("(3)");
+ if ((flag2 = fcntl(fd_in, F_GETFL)) == -1) {
+ printf("fcntl get failed\n");
+ exit(-1);
+ }
+ //printf("(4)");
+
+
+ while (1) {
+ FD_ZERO(&readSet);
+ FD_SET(fd_out, &readSet);
+
+ //printf("(5)");
+ res = select(fd_out + 1, &readSet, NULL, NULL, NULL);
+ //printf("(6)");
+ if (res < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ printf(".");
+ continue;
+ }
+ fprintf(stderr,"select failed errno=%d errstr=%s\n", errno, strerror(errno));
+ exit(-1);
+ }
+ break; /* we're done */
+ }
+
+ //printf("(7)");
+ if (fcntl(fd_out, F_SETFL, flag & ~O_NONBLOCK) == -1) {
+ printf("fcntl set failed\n");
+ exit(-1);
+ }
+ //printf("(8)");
+
+ //printf("(9)");
+ if ((flag = fcntl(fd_out, F_GETFL)) == -1) {
+ printf("fcntl get failed\n");
+ exit(-1);
+ }
+ //printf("(10)");
+
+
+ //printf("(11)");
+ if (fcntl(fd_in, F_SETFL, flag2 & ~O_NONBLOCK) == -1) {
+ printf("fcntl set failed\n");
+ exit(-1);
+ }
+
+ //printf("(11)");
+ if ((flag2 = fcntl(fd_in, F_GETFL)) == -1) {
+ printf("fcntl get failed\n");
+ exit(-1);
+ }
+ //printf("(12)");
+
+ if (flag & O_NONBLOCK == 0) {
+ printf("fd_out still nonblocking\n");
+ exit(-1);
+ }
+
+ if (flag & O_NONBLOCK == 0) {
+ printf("fd_in still nonblocking\n");
+ exit(-1);
+ }
+ if ((fp = fdopen(fd_out, "r")) == NULL) {
+ printf("fdopen failed\n");
+ exit(-1);
+ }
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ nlines++;
+ }
+
+ if (nlines<5) {
+ printf("Test returned different results - run again to verify\n");
+ exit(-1);
+ }
+
+ fclose(fp);
+ close(fd_in);
+ close(fd_out);
+ count++;
+ }
+ printf("test successful.\n");
+ exit(0);
+
+}
--- /dev/null
+#!/usr/bin/perl
+
+# Subtest #1 Create new vsys entry
+
+print "Creating entries...\t";
+
+$vsys_entry="#!/bin/bash\n\ncat /etc/passwd";
+$vsys_entry_acl = "/vservers/pl_netflow pl_netflow";
+
+open ACL,">/vsys/test.acl" || die ("Could not create acl for test entry.");
+print ACL $vsys_entry_acl;
+close ACL;
+
+open FIL,">/vsys/test" || die ("Could not create test entry.");
+print FIL $vsys_entry;
+close $vsys_entry;
+
+chmod 0755,"/vsys/test";
+
+# Check if it has shown up
+
+(-f "/vservers/pl_netflow/test.in") || die ("in file didn't show up in the slice");
+(-f "/vservers/pl_netflow/test.out") || die ("out file didn't show up in the slice");
+
+# OK, SUBTEST #1 SUCCEEDED
+print "(success)\n";
+
+# Subtest #2
+
+print "Multiple-connection test...\t";
+system("su -c ./vsys_conctest pl_netflow -");
+($? && die ("Multiple-connection test failed\n"));
+
+
+# OK, SUBTEST #2 SUCCEEDED
+print "(success)\n";
+
+# Subtest #3
+unlink "/vsys/test.acl";
+unlink "/vsys/test";
+
+(-f "/vservers/pl_netflow/test.in" || -f "/vservers/pl_netflow/test.out") && die ("cleanup failed");
+
#!/bin/bash
-# vsys initscript
-# Author: sapanb
+#
+# chkconfig: 345 84 02
+# description: Vsys file descriptor abritrator startup.
+#
+# Sapan Bhatia <sapanb@cs.princeton.edu>
+#
+# $Id$
+# $HeadURL$
+#
+name="vsys"
-backend="/vsys"
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+if [ -f /etc/sysconfig/$name ]; then
+ . /etc/sysconfig/$name
+fi
+
+backend=${BACKEND-/vsys}
+
+conf=${CONF-/etc/$name.conf}
+pidfile=${PIDFILE-/var/run/$name.pid}
+lockfile=${LOCKFILE-/var/lock/subsys/$name}
+RETVAL=0
+
+vsys=${VSYS- "/usr/bin/vsys -failsafe -backend $backend -conffile $conf -daemon"}
case "$1" in
start)
- echo -n "Starting vsys:"
+ echo -n "Starting $name:"
if [ ! -d $backend ]; then mkdir $backend; fi
- find /vservers -maxdepth 1 -type d | perl -e 'while (<>) {if (/(\/vservers\/(.*_.*))/) {$dir=$1;if (not (-d "$dir/vsys")) {mkdir "$dir/vsys";}}}'
- frontends=`find /vservers -maxdepth 1 -type d | perl -e 'while (<>) {if (/(\/vservers\/(.*_.*))/) {$dir=$1;$slice=$2;printf "-frontend $dir/vsys $slice "}}'`
- vsys_command="/usr/bin/vsys -backend $backend $frontends"
- echo $vsys_command
- $vsys_command
+ daemon --check=vsys $vsys
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch ${lockfile}
;;
stop)
- echo -n "Stopping $prog:"
- killall vsys
- exit 0
+ echo -n "Stopping $name:"
+ killproc $name
+ #killproc $name - Why were there 2 instances of this? :-|
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && rm -f ${lockfile} ${pidfile}
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ RETVAL=$?
;;
*)
- echo $"Usage: $0 {start|stop}"
+ echo $"Usage: $0 {start|stop|restart}"
exit 1
;;
esac
-# Source function library.
-. /etc/rc.d/init.d/functions
--- /dev/null
+/vservers/pl_netflow/vsys pl_netflow
--- /dev/null
+/var/log/netflow.log {
+ copytruncate
+ compress
+ daily
+ notifempty
+ rotate 5
+ missingok
+}
#
# RPM spec file
#
-# $Id: vsys.spec,v 1.40 2007/04/03 02:08:55 mef Exp $
+# $Id$
#
+%define url $URL$
+
%define name vsys
-%define version 0.6
-%define release 2%{?pldistro:.%{pldistro}}%{?date:.%{date}}
+%define version 0.7
+%define taglevel 18
+
+%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
Vendor: PlanetLab
Packager: PlanetLab Central <support@planet-lab.org>
-Distribution: PlanetLab 4.0
-URL: http://cvs.planet-lab.org/cvs/vsys
+Distribution: PlanetLab %{plrelease}
+URL: %(echo %{url} | cut -d ' ' -f 2)
Summary: Vsys filesystem
Name: %{name}
#Requires:
BuildRequires: inotify-tools-devel
BuildRequires: ocaml
-BuildRequires: ocaml-ocamldocs
+BuildRequires: ocaml-docs
Source0: vsys-%{version}.tar.gz
%install
mkdir -p $RPM_BUILD_ROOT/usr/bin
mkdir -p $RPM_BUILD_ROOT/etc/init.d
+mkdir -p $RPM_BUILD_ROOT/vsys
+cp factory/* $RPM_BUILD_ROOT/vsys
cp vsys $RPM_BUILD_ROOT/usr/bin
cp vsys-initscript $RPM_BUILD_ROOT/etc/init.d/vsys
+cp vsys.conf $RPM_BUILD_ROOT/etc
+
+install -D -m 644 vsys.logrotate $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/vsys
%clean
rm -rf $RPM_BUILD_ROOT
%files
/usr/bin/vsys
/etc/init.d/vsys
+/vsys/*
+%config(noreplace) /etc/vsys.conf
+%{_sysconfdir}/logrotate.d/vsys
%post
chkconfig --add vsys
chkconfig vsys on
+if [ "$PL_BOOTCD" != "1" ] ; then
+ service vsys restart
+fi
%postun
%changelog
+* Thu Jul 17 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-18
+- Change for someone at Imperial.ac.uk, who wants access to Netflow data.
+
+* Tue Jul 15 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-17
+- * Don't kill vsys twice on restarts, do it only once
+- * Restart vsys following a reinstall
+
+* Wed Jul 02 2008 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-0.7-16
+- Usability changes that are necessary for the stability of CoMon
+
+* Wed Jun 25 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-15
+- added patch to pl-ps needed by slicestat
+-
+-
+
+* Mon Jun 23 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-14
+- This change is an attempt to fix unexpected blocking after many days of uptime, reported by KyoungSoo.
+
+* Thu Jun 19 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-13
+- accept '-' in filenames also
+-
+
+* Wed Jun 18 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-12
+- don't overwrite the config file that already exists.
+-
+
+* Wed Jun 18 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-11
+- Suppress some temp file that RPM creates frmo showing up as a vsys script.
+-
+-
+
+* Wed Jun 18 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-10
+- Changed a policy in vsys. When an acl is empty, the script doesn't show up in ANY slice. The previous behavior was for
+- it to show up in all slices.
+-
+-
+
+* Wed Jun 18 2008 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-0.7-9
+- Added a vsys script for CoMon.
+-
+
+* Mon Jun 16 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-8
+- ignore non-existent directories after restart.
+-
+
+* Fri May 16 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-7
+- added logrotate configuration to package.
+-
+
+* Mon May 12 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-6
+- Added two new scripts for CoMon on 4.2
+-
+
+* Tue May 06 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-5
+-
+- Corrected directory that the script mounts to the correct one:
+- /var/local/fprobe
+-
+
+* Wed Apr 23 2008 Stephen Soltesz <soltesz@cs.princeton.edu> - vsys-0.7-4
+- Pulling the latest changes for the 4.2rc2 release
+-
+
+* Fri Feb 15 2008 Faiyaz Ahmed <faiyaza@cs.princeton.edu> - vsys-0.7-2 vsys-0.7-3
+- * daemonization, writing to a logfile, and saving the pid
+-
+
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <dirent.h>
+void pipe_handler (int sig) {
+ printf("SIGPIPE");
+}
+
int main(int argc, char **argv, char **envp)
{
if (argc<2) {
- printf("Usage: vsyssh <vsys entry> <cmd>\n");
+ printf("Usage: vsyssh <vsys entry> [cmd]\n");
exit(1);
}
else {
int vfd0,vfd1;
char *inf,*outf;
+ struct timeval tv;
+
+ signal(SIGPIPE,pipe_handler);
inf=(char *)malloc(strlen(argv[1])+3);
- outf=(char *)malloc(strlen(argv[2])+4);
+ outf=(char *)malloc(strlen(argv[1])+4);
strcpy(inf,argv[1]);
- strcpy(outf,argv[2]);
+ strcpy(outf,argv[1]);
strcat(inf,".in");
strcat(outf,".out");
+ vfd0 = open(outf,O_RDONLY|O_NONBLOCK);
+ printf("Out file: %d\n",vfd0);
vfd1 = open(inf,O_WRONLY);
- vfd0 = open(outf,O_RDONLY);
+ printf("In file: %d\n",vfd1);
if (vfd0==-1 || vfd1 == -1) {
- printf("Error opening vsys entry %s\n", argv[1]);
+ printf("Error opening vsys entry %s (%s)\n", argv[1],strerror(errno));
exit(1);
}
-
if (argc<3) {
fd_set set;
FD_ZERO(&set);
- FD_SET(0,&set);
- FD_SET(vfd0,&set);
- while (1) {
+ FD_SET(0, &set);
+ FD_SET(vfd0, &set);
+
+ while (1)
+ {
int ret;
- ret = select(2, &set, NULL, NULL, NULL);
+ printf("vsys>");fflush(stdout);
+ FD_SET(0, &set);
+ FD_SET(vfd0, &set);
+ ret = select(vfd0+1, &set, NULL, NULL, NULL);
if (FD_ISSET(0,&set)) {
char lineread[2048];
int ret;
ret=read(0,lineread,2048);
+ lineread[ret]='\0';
+ printf ("writing %s\n",lineread);
write(vfd1,lineread,ret);
FD_CLR(0,&set);
- }
- else if (FD_ISSET(vfd0,&set)) {
+ } if (FD_ISSET(vfd0,&set)) {
char lineread[2048];
int ret;
ret=read(vfd0,lineread,2048);