summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2025-01-06 12:07:25 -0600
committerJohn Estabrook <jestabro@vyos.io>2025-01-15 19:08:27 -0600
commit88dfcd5775ca7e14d9bf896d226b832b05b1a4ed (patch)
tree3e28103ecc99dc3031d4e816c133bb4eb6cfeeba /src
parent2948c7fa86dc3e7eba4f731f5dce8fbb03de6ad2 (diff)
downloadvyos1x-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.ml45
-rw-r--r--src/internal.mli4
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