feat(exec): spill long command lines into response files
This commit is contained in:
4 files changed
+53
-5
No files matched your search
+36
@@ -82,3 +82,39 @@ let which name =
|
||||
| Some path ->
|
||||
String.split_on_char ':' path
|
||||
|> List.exists (fun dir -> dir <> "" && Sys.file_exists (Filename.concat dir name))
|
||||
|
||||
(* execve measures the arguments and the environment together against ARG_MAX,
|
||||
so what a command line may use is the limit less the environment it inherits.
|
||||
Staying under a fraction of that leaves room for the pointer table and for an
|
||||
environment that grows between the check and the spawn. *)
|
||||
let arg_max =
|
||||
lazy
|
||||
(match capture [| "getconf"; "ARG_MAX" |] with
|
||||
| 0, out -> ( match int_of_string_opt (String.trim out) with Some n when n > 0 -> n | _ -> 131072)
|
||||
| _ -> 131072
|
||||
| exception _ -> 131072)
|
||||
|
||||
let entry_size s = String.length s + 1 + 8
|
||||
|
||||
let budget =
|
||||
lazy
|
||||
(let env = Array.fold_left (fun n s -> n + entry_size s) 0 (Unix.environment ()) in
|
||||
max 8192 ((Lazy.force arg_max - env) * 7 / 8))
|
||||
|
||||
let too_long cmd = Array.fold_left (fun n s -> n + entry_size s) 0 cmd > Lazy.force budget
|
||||
|
||||
(* A GNU response file holds one argument per line, quoted so that spaces and
|
||||
backslashes in a path survive the second round of parsing. The compiler
|
||||
drivers and binutils expand @file before they read anything else, so the tool
|
||||
sees the same argument list either way. *)
|
||||
let quote_arg s =
|
||||
let b = Buffer.create (String.length s + 2) in
|
||||
Buffer.add_char b '"';
|
||||
String.iter (fun c -> if c = '"' || c = '\\' then Buffer.add_char b '\\'; Buffer.add_char b c) s;
|
||||
Buffer.add_char b '"';
|
||||
Buffer.contents b
|
||||
|
||||
let response path cmd =
|
||||
let args = Array.to_list (Array.sub cmd 1 (Array.length cmd - 1)) in
|
||||
Fs.write path (String.concat "\n" (List.map quote_arg args) ^ "\n");
|
||||
[| cmd.(0); "@" ^ path |]
|
||||
Reference in new issue
Block a user