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
open Lwt.Syntax
open Os
let ( / ) = Filename.concat
let user_exists ~user =
let+ s = pread ["sudo"; "dscl"; "."; "list"; "/Users"] in
List.exists (Astring.String.equal user) (Astring.String.cuts ~sep:"\n" s)
let create_new_user ~username ~home_dir ~uid ~gid =
let* exists = user_exists ~user:username in
if exists then Lwt.return_ok ()
else
let user = "/Users" / username in
let pp s ppf = Fmt.pf ppf "[ Mac ] %s\n" s in
let dscl = [ "dscl"; "."; "-create"; user ] in
sudo_result ~pp:(pp "UniqueID") (dscl @ [ "UniqueID"; uid ]) >>!= fun _ ->
sudo_result ~pp:(pp "PrimaryGroupID") (dscl @ [ "PrimaryGroupID"; gid ])
>>!= fun _ ->
sudo_result ~pp:(pp "UserShell") (dscl @ [ "UserShell"; "/bin/bash" ])
>>!= fun _ ->
sudo_result ~pp:(pp "NFSHomeDirectory") (dscl @ [ "NFSHomeDirectory"; home_dir ])
let delete_user ~user =
let* exists = user_exists ~user in
match exists with
| false ->
Log.info (fun f -> f "Not deleting %s as they don't exist" user);
Lwt_result.return ()
| true ->
let user = "/Users" / user in
let pp s ppf = Fmt.pf ppf "[ Mac ] %s\n" s in
let delete = ["dscl"; "."; "-delete"; user ] in
sudo_result ~pp:(pp "Deleting") delete
let descendants ~pid =
Lwt.catch
(fun () ->
let+ s = pread ["sudo"; "pgrep"; "-P"; string_of_int pid ] in
let pids = Astring.String.cuts ~sep:"\n" s in
List.filter_map int_of_string_opt pids)
(fun _ -> Lwt.return [])
let kill ~pid =
let pp _ ppf = Fmt.pf ppf "[ KILL ]" in
let delete = ["kill"; "-9"; string_of_int pid ] in
let* t = sudo_result ~pp:(pp "KILL") delete in
match t with
| Ok () -> Lwt.return ()
| Error (`Msg m) ->
Log.warn (fun f -> f "Failed to kill process %i because %s" pid m);
Lwt.return ()
let kill_all_descendants ~pid =
let rec kill_all pid : unit Lwt.t =
let* ds = descendants ~pid in
let* () = Lwt_list.iter_s kill_all ds in
kill ~pid
in
kill_all pid
let copy_template ~base ~local =
let pp s ppf = Fmt.pf ppf "[ %s ]" s in
sudo_result ~pp:(pp "RSYNC") ["rsync"; "-avq"; base ^ "/"; local]
let change_home_directory_for ~user ~home_dir =
["dscl"; "."; "-create"; "/Users/" ^ user ; "NFSHomeDirectory"; home_dir ]
let update_scoreboard ~uid ~scoreboard ~home_dir =
["ln"; "-Fhs"; home_dir; scoreboard ^ "/" ^ string_of_int uid]
let remove_link ~uid ~scoreboard =
[ "rm"; scoreboard ^ "/" ^ string_of_int uid ]
let get_tmpdir ~user =
["sudo"; "-u"; user; "-i"; "getconf"; "DARWIN_USER_TEMP_DIR"]