diff options
| author | John Estabrook <jestabro@vyos.io> | 2025-01-06 12:07:25 -0600 |
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2025-01-15 19:08:27 -0600 |
| commit | 88dfcd5775ca7e14d9bf896d226b832b05b1a4ed (patch) | |
| tree | 3e28103ecc99dc3031d4e816c133bb4eb6cfeeba /src | |
| parent | 2948c7fa86dc3e7eba4f731f5dce8fbb03de6ad2 (diff) | |
| download | vyos1x-config-88dfcd5775ca7e14d9bf896d226b832b05b1a4ed.tar.gz vyos1x-config-88dfcd5775ca7e14d9bf896d226b832b05b1a4ed.zip | |
T7046: add proper locks and checks on internal rep
Diffstat (limited to 'src')
| -rw-r--r-- | src/internal.ml | 45 | ||||
| -rw-r--r-- | src/internal.mli | 4 |
2 files changed, 45 insertions, 4 deletions
diff --git a/src/internal.ml b/src/internal.ml index 0c761e0..a57f3db 100644 --- a/src/internal.ml +++ b/src/internal.ml @@ -1,3 +1,6 @@ +exception Read_error of string +exception Write_error of string + module type T = sig type t @@ -10,20 +13,54 @@ module type FI = functor (M: T) -> sig val write_internal : M.t -> string -> unit val read_internal : string -> M.t + val replace_internal : string -> string -> unit end module Make : FI = functor (M: T) -> struct let write_internal x file_name = let yt = M.to_yojson x in let ys = Yojson.Safe.to_string yt in - let oc = open_out file_name in - Printf.fprintf oc "%s" ys; close_out oc + let fd = Unix.openfile file_name [Unix.O_CREAT;Unix.O_WRONLY] 0o664 in + let () = + try + Unix.lockf fd Unix.F_TLOCK 0 + with _ -> + Unix.close fd; raise (Write_error "write lock unavailable") + in + let oc = Unix.out_channel_of_descr fd in + let () = Unix.ftruncate fd 0 in + let () = Printf.fprintf oc "%s" ys in + let () = Unix.fsync fd in + let () = Unix.lockf fd Unix.F_ULOCK 0 in + close_out_noerr oc let read_internal file_name = - let ic = open_in file_name in + let fd = + try + Unix.openfile file_name [Unix.O_RDONLY] 0o664 + with Unix.Unix_error (e,f,p) -> + let out = + Printf.sprintf "%s %s: %s" (Unix.error_message e) f p + in raise (Read_error out) + in + let () = + try + Unix.lockf fd Unix.F_TEST 0 + with _ -> + Unix.close fd; raise (Read_error "read lock unavailable") + in + let ic = Unix.in_channel_of_descr fd in let ys = really_input_string ic (in_channel_length ic) in let yt = Yojson.Safe.from_string ys in let ct_res = M.of_yojson yt in let ct = Result.value ct_res ~default:M.default in - close_in ic; ct + close_in_noerr ic; ct + + let replace_internal dst src = + let tmp = src ^ ".tmp" in + try + let () = FileUtil.cp ~force:Force [src] tmp in + let () = FileUtil.rm ~force:Force [dst] in + FileUtil.mv ~force:Force tmp dst + with _ -> raise (Write_error "replace error") end diff --git a/src/internal.mli b/src/internal.mli index 33918c7..a82232d 100644 --- a/src/internal.mli +++ b/src/internal.mli @@ -1,3 +1,6 @@ +exception Read_error of string +exception Write_error of string + module type T = sig type t @@ -10,6 +13,7 @@ module type FI = functor (M : T) -> sig val write_internal : M.t -> string -> unit val read_internal : string -> M.t + val replace_internal : string -> string -> unit end module Make : FI |
