From: Sapan Bhatia Date: Mon, 3 Mar 2008 23:14:36 +0000 (+0000) Subject: Finished patching things. X-Git-Tag: vsys-0.7-4~20 X-Git-Url: http://git.onelab.eu/?p=vsys.git;a=commitdiff_plain;h=16c8bb31dd971b7fab00dbb17a75bb08cee463c6 Finished patching things. --- diff --git a/directfifowatcher.ml b/directfifowatcher.ml index 0ff74b3..7fa9192 100644 --- a/directfifowatcher.ml +++ b/directfifowatcher.ml @@ -3,6 +3,13 @@ * - 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 @@ -12,39 +19,68 @@ open Dirwatcher open Printf open Splice -let backend_prefix = ref "" -let direct_fifo_table: (string,(string*string) option) Hashtbl.t = Hashtbl.create 1024 +let close_if_open fd = (try (ignore(close fd);) with _ -> ()) + + +let direct_fifo_table: (string,(string*string*string*Unix.file_descr) option) Hashtbl.t = Hashtbl.create 1024 +let pidmap: (int,string) Hashtbl.t = Hashtbl.create 1024 let rec list_check lst elt = match lst with | [] -> false | car::cdr -> if (car==elt) then true else list_check cdr elt +let openentry_int fifoin = + let fdin = + try openfile fifoin [O_RDONLY;O_NONBLOCK] 0o777 with + e->fprintf logfd "Error opening and connecting FIFO: %s,%o\n" fifoin 0o777;flush logfd;raise e + in + fdin + + +(** Open fifos for a session. SHOULD NOt shutdown vsys if the fifos don't exist *) +let openentry_in root_dir fqp_in backend_spec = + Dirwatcher.mask_watch root_dir; + let fd_in = openentry_int fqp_in in + Dirwatcher.unmask_watch root_dir [S_Open]; + 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_in 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_in dir fifoin (fqp,slice_name) + | None -> () + (* vsys is activated when a client opens an in file *) -let connect_file mask_events fqp_out = +let connect_file fqp_in = (* Do we care about this file? *) let entry_info = try - Hashtbl.find direct_fifo_table fqp_out with _ -> None in + Hashtbl.find direct_fifo_table fqp_in with _ -> None in match entry_info with - | Some(execpath,slice_name) -> + | Some(_,execpath,slice_name,fifo_fdin) -> fprintf logfd "Executing %s for slice %s\n" execpath slice_name;flush logfd; begin - let len = String.length fqp_out in - let fqp = String.sub fqp_out 0 (len-4) in - mask_events true; - let fqp_in = String.concat "." [fqp;"in"] in - let fifo_fdin = - try openfile fqp_in [O_RDONLY;O_NONBLOCK] 0o777 with - e->fprintf logfd "Error opening and connecting FIFO: %s\n" fqp_in;flush logfd;raise e - in + 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 _->fprintf logfd "%s Output pipe not open, using stdout in place of %s\n" slice_name fqp_out;flush logfd;stdout in - try ignore(create_process execpath [|execpath;slice_name|] fifo_fdin fifo_fdout fifo_fdout); with e -> begin fprintf logfd "Error executing service: %s\n" execpath;flush logfd end; - close fifo_fdin; - close fifo_fdout; - mask_events false; + 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) ->Hashtbl.add pidmap pid fqp_in + | None ->fprintf logfd "Error executing service: %s\n" execpath;flush logfd;reopenentry fqp_in + ); + ignore(sigprocmask SIG_UNBLOCK [Sys.sigchld]); end | None -> () @@ -71,28 +107,40 @@ let mkentry fqp abspath perm uname = with 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. SHOULD NOt shutdown vsys if the fifos don't exist *) -let openentry fqp backend_spec = - let fqp_in = String.concat "." [fqp;"out"] in - Hashtbl.replace direct_fifo_table fqp_in (Some(backend_spec)) (** Close fifos that just got removed *) let closeentry fqp = - let fqp_in = String.concat "." [fqp;"out"] in - Hashtbl.remove direct_fifo_table fqp_in + 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 direct_fifo_handler wd dirname evlist fname = - let mask_events flag = - if (flag) then Dirwatcher.mask_events wd else Dirwatcher.unmask_events wd - in - let is_event = list_check evlist in - if (is_event Open) then - let fqp_out = String.concat "/" [dirname;fname] in - connect_file mask_events fqp_out +let sigchld_handle s = + let pid,_=Unix.waitpid [Unix.WNOHANG] 0 in + try + let fqp_in = Hashtbl.find pidmap pid in + printf "Reopening fifo\n";flush Pervasives.stdout; + reopenentry fqp_in + with _ -> () -let add_dir_watch fqp = +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) then + let fqp_in = String.concat "/" [dirname;fname] in + begin + connect_file fqp_in; + add_dir_watch dirname + end let del_dir_watch fqp = (* XXX Dirwatcher.del_watch fqp *) () + +let initialize () = + Sys.set_signal Sys.sigchld (Sys.Signal_handle sigchld_handle) diff --git a/dirwatcher.ml b/dirwatcher.ml index 643830e..4131023 100644 --- a/dirwatcher.ml +++ b/dirwatcher.ml @@ -1,5 +1,5 @@ (** Watches directories for events. Agnostic to vsys semantics of backends and -frontends *) + frontends *) open Inotify open Fdwatcher open Printf @@ -8,79 +8,78 @@ open Globals (* I don't know if a wd corresponding to a deleted directory is evicted or just * leaks - fix implementation of rmdir accordingly *) - -type 'a handlertype = Nohandler | Activehandler of 'a | Maskedhandler of 'a - let wdmap = Hashtbl.create 1024 +let masks = 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 handle_dir_event dirname evlist str = - let fname = String.concat "/" [dirname;str] in - fprintf logfd "File: %s. " fname;List.iter - (fun e -> - fprintf logfd "Event: %s\n" (string_of_event e)) - evlist; - flush logfd + let fname = String.concat "/" [dirname;str] in + fprintf logfd "File: %s. " fname;List.iter + (fun e -> + fprintf logfd "Event: %s\n" (string_of_event e)) + evlist; + flush logfd let add_watch dir events handler = - let wd = Inotify.add_watch fd dir events in - Hashtbl.add wdmap wd (dir,Activehandler(handler)) - -let mask_events wd = - let (dirname,handler) = try Hashtbl.find wdmap wd with Not_found->("",Nohandler) - in - match handler with - | Activehandler(func)-> - Hashtbl.replace wdmap wd (dirname,Maskedhandler(func)) - | _ -> - () - -let unmask_events wd = - let (dirname,handler) = try Hashtbl.find wdmap wd with Not_found->("",Nohandler) + let evcheck = list_check events in + let oneshot = if (evcheck S_Oneshot) then true else false in - match handler with - | Maskedhandler(func)-> - Hashtbl.replace wdmap wd (dirname,Activehandler(func)) - | _ -> - () + let wd = Inotify.add_watch fd dir events in + Hashtbl.add masks dir (wd,handler); + Hashtbl.add wdmap wd (dir,Some(handler),oneshot) +let mask_watch dir = + try + let wd,_ = Hashtbl.find masks dir in + Inotify.rm_watch fd wd; + Hashtbl.remove wdmap wd + with _ -> + () - (* XXX -let del_watch dir = - fprintf logfd "Removing watch for %s\n" dir;flush logfd; - let wd = Inotify.rm_watch fd dir in - Hashtbl.remove wdmap wd - *) +let unmask_watch dir events = + let _,handler = Hashtbl.find masks dir in + try + Hashtbl.remove masks dir; + add_watch dir events handler + with Not_found -> () 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->("",Nohandler) - in - ( - match handler with - | Nohandler->fprintf logfd "Unhandled watch descriptor\n";flush logfd - | Activehandler(handler)->handler wd dirname evlist purestr - | Maskedhandler(_)->() - ) - | _ -> ()) - evs + 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,oneshot) = + try Hashtbl.find wdmap wd with Not_found->("",None,false) + in + printf "Received event: %s " dirname; + List.iter (fun l->printf "%s " (string_of_event l)) evlist; + printf "\n";flush Pervasives.stdout; + if (oneshot) then Hashtbl.remove wdmap wd; + ( + match handler with + | None->fprintf logfd "Unhandled watch descriptor\n";flush logfd + | Some(handler)->handler wd dirname evlist purestr + ) + | _ -> ()) + evs let initialize () = Fdwatcher.add_fd (None,fd) (None,fd) receive_event diff --git a/frontend.ml b/frontend.ml index 335782a..43c2ffa 100644 --- a/frontend.ml +++ b/frontend.ml @@ -24,7 +24,7 @@ object(this) let res = Directfifowatcher.mkentry fqp abspath realperm slice_name in match res with | Success -> - Directfifowatcher.openentry fqp (abspath,slice_name) + Directfifowatcher.openentry root_dir fqp (abspath,slice_name) | _ -> () (** A new directory was created at the backend, make a corresponding directory @@ -77,5 +77,21 @@ object(this) fprintf logfd "Hm. %s disappeared or not empty. Looks like slice %s shot itself in the foot\n" fqp (this#get_slice_name ());flush logfd initializer - Directfifowatcher.add_dir_watch root_dir + 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(_,_,_) -> + try + Unix.mkdir root_dir 0o700; + with _ -> (); + Directfifowatcher.add_dir_watch root_dir end diff --git a/main.ml b/main.ml index 534f915..a70a473 100644 --- a/main.ml +++ b/main.ml @@ -43,6 +43,8 @@ let _ = end; Dirwatcher.initialize (); + Directfifowatcher.initialize (); + if (!Globals.conffile <> "") then begin let frontends = Conffile.read_frontends !Globals.conffile in diff --git a/vsyssh/vsyssh.c b/vsyssh/vsyssh.c index b77d7f2..58625f5 100644 --- a/vsyssh/vsyssh.c +++ b/vsyssh/vsyssh.c @@ -66,6 +66,8 @@ int main(int argc, char **argv, char **envp) 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); } if (FD_ISSET(vfd0,&set)) {