File: launch.ml

package info (click to toggle)
advi 1.6.0-6
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 17,416 kB
  • ctags: 2,825
  • sloc: ml: 12,261; sh: 1,500; ansic: 935; makefile: 738; perl: 57; tcl: 10
file content (261 lines) | stat: -rw-r--r-- 9,008 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
(***********************************************************************)
(*                                                                     *)
(*                             Active-DVI                              *)
(*                                                                     *)
(*                   Projet Cristal, INRIA Rocquencourt                *)
(*                                                                     *)
(*  Copyright 2002 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the GNU Lesser General Public License.          *)
(*                                                                     *)
(*  Jun Furuse, Didier Rmy and Pierre Weis.                           *)
(*  Contributions by Roberto Di Cosmo, Didier Le Botlan,               *)
(*  Xavier Leroy, and Alan Schmitt.                                    *)
(*                                                                     *)
(*  Based on Mldvi by Alexandre Miquel.                                *)
(***********************************************************************)

(* $Id: launch.ml,v 1.36 2004/03/07 14:09:37 weis Exp $ *)

type app_name = string;;
type app_command = string;;
type geometry = string;;
type argument = string;;

(* Embedded applications function handlers (thunks). *)
let embeds = ref [];;
let persists = ref [];;
let unmap_embeds = ref [];;

let add_embed f = embeds := f :: !embeds
and add_persist f = persists := f :: !persists
and add_unmap_embed f = unmap_embeds := f :: !unmap_embeds;;

(* Execute thunks of a list of thunks in reverse order. *)
let execute fs = List.iter (fun f -> f ()) (List.rev fs);;

(* Evaluate f arg, while temporary unmapping persistent apps. *)
let unmapping_persistent_apps f arg =
  execute !unmap_embeds;
  let res = f arg in
  execute !persists;
  res;;

(* Unmap persistent apps windows (apps are still running). *)
let unmap_persistent_apps () =
  execute !unmap_embeds;
  unmap_embeds := [];;

(* Really launch embedded apps. *)
let launch_embedded_apps () =
  execute !embeds; embeds := [];
  execute !persists; persists := [];;

(* Unix command line parser *)
let parse_shell_command = Rc.argv_of_string;;

(* Handling forking problems: only father process can call the at_exit
   function, sons of the main process must leave without calling it.
   Otherwise we would attempt to kill embedded processes twice,
   leading to bus errors or bad exception handling (fatal errors). *)
let advi_process = Unix.getpid ();;

let exit code =
  (* at_exit code must be called only by the ADVI process.
     If it is one of the forked processes, it must DIE IMMEDIATELY:
     no cleaning is allowed. *)
  if Unix.getpid () = advi_process then Pervasives.exit code
  else (* SUICIDE *) Unix.kill (Unix.getpid ()) 9;;

(* The safety policy to launch applications. *)
type policy =
   | Safer              (* No application is launched. *)
   | Exec               (* Application are automatically launched. *)
   | Ask                (* The user is prompted, whenever an
                           application has to be launched. *)
;;

(* Policy assignment. *)
let get_policy, set_policy =
 let policy = ref Ask in
 (fun () -> !policy),
 (function
  | Safer -> policy := Safer
  | Exec -> policy := Exec
  | Ask -> policy := Ask);;

Options.add
  "-exec"
  (Arg.Unit
    (fun () ->
      if get_policy () <> Exec then Misc.warning "Setting policy to -exec";
      set_policy Exec))
  "  set the security policy to \"Exec\" mode, i.e.\
  \n\t all embedded applications are automatically executed.\
  \n\t Unless explicitely required, this mode does not apply.";;

Options.add
  "-safer"
  (Arg.Unit
    (fun () ->
      if get_policy () <> Safer then Misc.warning "Setting policy to -safer";
      set_policy Safer))
  "  set the security policy to \"Safer\" mode, i.e.\
  \n\t external applications are simply ignored.\
  \n\t Unless explicitely required, this mode does not apply.";;

Options.add
  "-ask"
  (Arg.Unit
    (fun () ->
      if get_policy () <> Ask then Misc.warning "Setting policy to -ask";
      set_policy Ask))
  "  set the security policy to \"Ask\" mode, i.e.\
  \n\t launching an external application requires explicit confirmation\
  \n\t (this is the default policy).";;

let cannot_execute_command command_invocation =
    Misc.warning
      (Printf.sprintf
         "Attempt to launch the embedded command:\n\n\
          \t%s\n\n\
          For security reasons, it was not executed.\n\
          Hence the presentation could be strange or incomplete.\n\
          To enable execution of embedded applications,\n\
          please rerun Active-DVI with option -ask or -exec."
         command_invocation);;

(* Opening a terminal to ask something to the user. *)
open Gterm;;

let ask_user t s1 s2 s3 =
 vtab t 16; htab t 15; print_str t s1;
 vtab t 12; htab t 10; print_str t s2;
 vtab t 8; htab t 15;
 let answer = Gterm.ask t s3 in
 match answer with
 | "yes" -> true
 | _ -> false;;

let ask_to_launch command command_invocation =
 let ncol, nlines = 80, 24 in
 let bw = 25 in

 let sx, sy = Graphics.text_size "X" in
 let wt, ht = sx * ncol, sy * nlines in
 let xc, yc =
  (Graphics.size_x () - wt - 1) / 2, (Graphics.size_y () - ht - 1) / 2 in

 let t =
   make_term_gen
     Graphics.green Graphics.black
     bw Graphics.red Graphics.black
     0x6FFFFF
     xc yc ncol nlines in
 Gterm.set_title t (Printf.sprintf "Active-DVI alert for %s" command);

 unmapping_persistent_apps (fun () ->
   draw_term t;
   ask_user t
    "Attempt to launch the following command"
    command_invocation
    "Do you want to execute it ? <yes>[no] ") ();;

let ask_before f arg =
  let cursor = GraphicsY11.get_cursor () in
  GraphicsY11.set_cursor GraphicsY11.Cursor_question_arrow;
  let res = f arg in
  GraphicsY11.set_cursor cursor;
  Misc.push_key_event '' GraphicsY11.control;
  res;;

let ask_before_launching command command_invocation =
  ask_before (ask_to_launch command) command_invocation;;

let can_execute_table = Hashtbl.create 11;;

let can_execute command_invocation command_tokens =
  match get_policy () with
  | Exec -> true
  | Safer -> false
  | Ask ->
     let command = command_tokens.(0) in
     try Hashtbl.find can_execute_table command with
     | Not_found ->
         let b = ask_before_launching command command_invocation in
         Hashtbl.add can_execute_table command b;
         b;;

let can_execute_command command_invocation =
  let command_tokens = parse_shell_command command_invocation in
  can_execute command_invocation command_tokens;;

let execute_command can_exec command_invocation command_tokens =
  if can_exec then Unix.execvp command_tokens.(0) command_tokens
  else cannot_execute_command command_invocation;;

let fork_proc command_invocation command_tokens =
  let can_exec = can_execute command_invocation command_tokens in
  let pid = Unix.fork () in
  if pid = 0 then
    begin (* child *)
      try
        execute_command can_exec command_invocation command_tokens;
        exit 0
      with
      | Unix.Unix_error (e, _, arg) ->
          Misc.warning (Printf.sprintf "%s: %s" (Unix.error_message e) arg);
          exit 127
    end;
  pid;;

let fork_process command_invocation =
  let command_tokens = parse_shell_command command_invocation in
  fork_proc command_invocation command_tokens;;

(* Support for no launching at all during an arbitrary function call. *)
let without_launching f x =
  let p = get_policy () in
  let restore () = set_policy p in
  try set_policy Safer; let r = f x in restore (); r
  with x -> restore (); raise x;;

(* Support for automatic launching during an arbitrary function call. *)
let with_launching f x =
  let p = get_policy () in
  let restore () = set_policy p in
  try set_policy Exec; let r = f x in restore (); r
  with x -> restore (); raise x;;

(* Fork the process that executes this function (cloning :). *)
let fork_me geom arg =
  with_launching
  fork_process (Printf.sprintf "%s %s %s" Sys.argv.(0) geom arg);;

(* Support for white run via -n option *)

let white_run, set_white_run =
  let white_run_flag = ref false in
  (fun () -> !white_run_flag),
  (fun () -> white_run_flag := true);;

let add_white_run_command, dump_white_run_commands =
  let white_run_commands = ref [] in
  (fun command -> white_run_commands := command :: !white_run_commands),
  (fun () ->
    let unique l =
      List.fold_right
        (fun c acc ->
          match acc with
          | [] -> [c]
          | c' :: r as cl -> if c = c' then cl else c :: cl)
        (List.sort compare l) [] in
    let comms = unique !white_run_commands in
    List.iter (fun c -> prerr_endline c) comms);;

Options.add
  "-n"
  (Arg.Unit (fun () -> set_white_run ()))
  "  ask Active-DVI to run in \"fake mode\", i.e.\
  \n\t to just echo the name of embedded commands\
  \n\t (there is no previewing nor embedded commands execution).";;