2 Defines handlers for events related to the backend directory, where the
3 scripts are stored. Eg. a new script results in a new part of pipes in
4 the frontend etc. These handlers are defined in the backendHandler
7 @author Sapan Bhatia <sapanb\@cs.princeton.edu>
22 (** Turn an absolute path into a relative path. *)
23 let delete_prefix prefix str =
24 let len = String.length str in
25 let plen = String.length prefix in
26 if (String.sub str 0 plen <> prefix)
28 (* XXX can a user make this happen? *)
31 Relpath(String.sub str (plen+1) (len-plen-1))
33 let rec list_check lst elt =
36 | car::cdr -> if (car==elt) then true else list_check cdr elt
39 (** The backendhandler class: defines event handlers for events in
40 the backend backend directory.
41 @param dir_root The location of the backend in the server context (eg. root context for vservers)
42 @param frontend_list List of frontends to serve with this backend
44 class backendHandler dir_root (frontend_lst: frontendHandler list) =
45 let mk_rel_path = delete_prefix dir_root in object(this)
47 (** Regular expression that defines a legal script name. Filter out
48 * temporary files using this *)
49 val file_regexp = Str.regexp "[a-zA-Z][a-zA-Z0-9_\.]*"
50 val acl_file_regexp = Str.regexp ".*acl$"
52 val dir_regexp = Str.regexp "^dir_";
53 val acl_regexp = Str.regexp ".*_.*";
55 (** Somebody created a new directory *)
56 (* XXX Race condition here *)
57 method private new_dir slice_list fqp func =
58 let s = Unix.stat fqp in
62 frontend#mkdir (mk_rel_path fqp) (s.st_perm);
63 Dirwatcher.add_watch fqp [S_Create;S_Delete] (Some(func))
66 fprintf logfd "Could not create %s. Looks like a slice shot itself in the foot\n" fqp;flush logfd;
70 (** Somebody copied in a new script *)
71 (* XXX Race condition here *)
72 method private new_script slice_list fqp =
73 let s = Unix.stat fqp in
74 List.iter (fun frontend->
75 frontend#mkentry (mk_rel_path fqp) fqp (s.st_perm)) slice_list
77 method private make_filter acl_fqp =
78 let filter = Hashtbl.create 16 in
80 let acl_file = open_in acl_fqp in
81 let rec read_acl cur_filter =
83 try Some(input_line acl_file)
89 Hashtbl.add cur_filter item true;
96 (** Gets called every time there's an inotify event at the backend
97 @param dirname Name of the backend directory
98 @param evlist Description of what happened
99 @param fname Name of the file that the event applies to
101 method handle_dir_event dirname evlist fname =
102 let fqp = String.concat "/" [dirname;fname] in
103 if ((Str.string_match file_regexp fname 0) && not (Str.string_match acl_file_regexp fname 0)) then
105 (* Filter frontend list based on acl *)
106 let acl_fqp = String.concat "." [fqp;"acl"] in
107 let acl_filter = this#make_filter acl_fqp in
109 match acl_filter with
110 | None -> frontend_lst
111 | Some(filter) -> List.filter (fun fe->Hashtbl.mem filter (fe#get_slice_name ())) frontend_lst
113 let is_event = list_check evlist in
114 if (is_event Create) then
116 if (is_event Isdir) then
118 this#new_dir slice_list fqp this#handle_dir_event
121 (* It's a new script *)
124 if (Str.string_match dir_regexp fname 0) then
125 let fqp = String.concat "/" [dirname;String.sub fname 4 ((String.length fname)-4+1)] in
126 let real_fqp = String.concat "/" [dirname;fname] in
127 this#new_dir fqp this#handle_spool_event;
128 Hashtbl.add spools fqp real_fqp
130 this#new_script slice_list fqp
133 else if (is_event Delete) then
135 if (is_event Isdir) then
137 (*this#rm_watch fqp;*)
138 List.iter (fun frontend->
139 frontend#rmdir (mk_rel_path fqp)) slice_list
141 else List.iter (fun frontend ->
142 frontend#unlink (mk_rel_path fqp)) slice_list
145 else (* regex not matched *)
148 (** Initializer - build the initial tree based on the contents of /vsys *)
150 let rec build_initial_tree dir =
151 let dir_handle = opendir dir in
152 let cont = ref true in
155 let curfile = readdir dir_handle in
156 let fqp = String.concat "/" [dir;curfile] in
157 let acl_fqp = String.concat "." [fqp;"acl"] in
158 let acl_filter = this#make_filter acl_fqp in
160 match acl_filter with
161 | None -> frontend_lst
162 | Some(filter) -> List.filter (fun fe->Hashtbl.mem filter (fe#get_slice_name ())) frontend_lst
164 if (Str.string_match file_regexp curfile 0 && not (Str.string_match acl_file_regexp curfile 0)) then
165 let s = Unix.stat fqp in
169 this#new_dir slice_list fqp this#handle_dir_event;
170 build_initial_tree fqp;
172 this#new_script slice_list fqp
174 fprintf logfd "Don't know what to do with %s\n" curfile;flush logfd
181 build_initial_tree dir_root;
182 Dirwatcher.add_watch dir_root [S_Create;S_Delete] (Some(this#handle_dir_event));