From ede67e4f894cf6acc1563e804167a4909c00a18e Mon Sep 17 00:00:00 2001 From: malc Date: Wed, 21 Jan 2015 02:37:38 +0300 Subject: [PATCH] Avoid using standard process management --- main.ml | 107 ++++++++++++++++++++++++++++----------------------------------- utils.ml | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 60 deletions(-) diff --git a/main.ml b/main.ml index 8476bcd..8f59b8e 100644 --- a/main.ml +++ b/main.ml @@ -1625,25 +1625,10 @@ let getpassword () = let passcmd = getenvwithdef "LLPP_ASKPASS" conf.passcmd in if emptystr passcmd then E.s - else - match Unix.open_process_in passcmd with - | (exception exn) -> - showtext '!' - (Printf.sprintf - "getpassword: open_process_in failed: %s" (exntos exn)); - E.s - | ic -> - let s = try input_line ic with End_of_file -> E.s in - let s = - match Unix.close_process_in ic with - | (exception exn) -> - showtext '!' - (Printf.sprintf "getpassword: close_process_in failed: %s" - (exntos exn)); - E.s - | _ -> s - in - s + else getcmdoutput + (fun s -> + showtext '!' @@ "error getting password: " ^ s; + dolog "%s" s) passcmd; ;; let act cmds = @@ -4232,35 +4217,43 @@ let getusertext s = ); let execstr = editor ^ " " ^ tmppath in let s = - match Unix.system execstr with + match popen execstr [] with | (exception exn) -> showtext '!' @@ - Printf.sprintf "Unix.system(%S) failed: %s" execstr (exntos exn); - E.s - | Unix.WEXITED 0 -> filelines tmppath - | Unix.WEXITED n -> - showtext '!' @@ - Printf.sprintf "editor process(%s) exited abnormally: %d" - execstr n; - E.s - | Unix.WSIGNALED n -> - showtext '!' @@ - Printf.sprintf "editor process(%s) was killed by signal %d" - execstr n; - E.s - | Unix.WSTOPPED n -> - showtext '!' @@ - Printf.sprintf "editor(%s) process was stopped by signal %d" - execstr n; + Printf.sprintf "popen(%S) failed: %s" execstr (exntos exn); E.s + | pid -> + match Unix.waitpid [] pid + with + | (exception exn) -> + showtext '!' @@ + Printf.sprintf "waitpid(%d) failed: %s" pid (exntos exn); + E.s + | (_pid, status) -> + match status with + | Unix.WEXITED 0 -> filelines tmppath + | Unix.WEXITED n -> + showtext '!' @@ + Printf.sprintf "editor process(%s) exited abnormally: %d" + execstr n; + E.s + | Unix.WSIGNALED n -> + showtext '!' @@ + Printf.sprintf "editor process(%s) was killed by signal %d" + execstr n; + E.s + | Unix.WSTOPPED n -> + showtext '!' @@ + Printf.sprintf "editor(%s) process was stopped by signal %d" + execstr n; + E.s in match Unix.unlink tmppath with - | (exception exn) -> - showtext '!' @@ - Printf.sprintf "failed to ulink %S: %s" - tmppath (exntos exn); - s - | () -> s + | (exception exn) -> + showtext '!' @@ Printf.sprintf "failed to ulink %S: %s" + tmppath (exntos exn); + s + | () -> s ;; let enterannotmode opaque slinkindex = @@ -4815,23 +4808,17 @@ let save () = if emptystr conf.savecmd then error "don't know where to save modified document" else - let command = Str.global_replace percentsre state.path conf.savecmd in - match Unix.open_process_in command with - | (exception exn) -> - showtext '!' - (Printf.sprintf "savecmd open_process_in failed: %s" - (exntos exn)); - | ic -> - let path = try input_line ic with End_of_file -> E.s in - let path = - match Unix.close_process_in ic with - | (exception exn) -> - error "error obtaining save path: %s" (exntos exn) - | _ -> path - in - let tmp = path ^ ".tmp" in - savedoc tmp; - Unix.rename tmp path; + let savecmd = Str.global_replace percentsre state.path conf.savecmd in + let path = + getcmdoutput + (fun s -> error "failed to obtain path to the saved copy: %s" s) + savecmd + in + if not (emptystr path) + then + let tmp = path ^ ".tmp" in + savedoc tmp; + Unix.rename tmp path; ;; let viewkeyboard key mask = diff --git a/utils.ml b/utils.ml index 416564e..f03777d 100644 --- a/utils.ml +++ b/utils.ml @@ -213,3 +213,64 @@ let withoutlastutf8 s = in String.sub s 0 first; ;; + +let fdcontents fd = + let l = 4096 in + let b = Buffer.create l in + let s = Bytes.create l in + let rec loop () = + let n = tempfailureretry (Unix.read fd s 0) l in + if n = 0 + then Buffer.contents b + else ( + Buffer.add_subbytes b s 0 n; + loop () + ) + in + loop () +;; + +let getcmdoutput errstr cmd = + let error fmt = Printf.kprintf errstr fmt in + let clofail s e = error "failed to close %s: %s" s e in + match Unix.pipe () with + | (exception exn) -> + error "pipe failed: %s" (exntos exn); + E.s + | (r, w) -> + match popen cmd [r, -1; w, 1] with + | (exception exn) -> + error "exec %S failed: %s" cmd (exntos exn); + E.s + | pid -> + Ne.clo w @@ clofail "write end of the pipe"; + let s = + match Unix.waitpid [] pid with + | (exception exn) -> + error "waitpid on %S %d failed: %s" cmd pid (exntos exn); + E.s + | _pid, Unix.WEXITED 0 -> + begin + match fdcontents r with + | (exception exn) -> + error "failed to read output of %S: %s" cmd (exntos exn); + E.s + | s -> + let l = String.length s in + if l > 0 && s.[l-1] = '\n' + then String.sub s 0 (l-1) + else s + end; + | _pid, Unix.WEXITED n -> + error "%S exited with error code %d" cmd n; + E.s + | _pid, Unix.WSIGNALED n -> + error "%S was killed with signal %d" cmd n; + E.s + | _pid, Unix.WSTOPPED n -> + error "%S was stopped by signal %d" cmd n; + E.s + in + Ne.clo r @@ clofail "read end of the pipe"; + s +;; -- 2.11.4.GIT