summaryrefslogtreecommitdiff
path: root/src/util.erl
blob: 2125d5ee4cf8871e5b18b7e9ac49a434f4e7d542 (plain)
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
%%% Copyright (c) 2014, NORDUnet A/S.
%%% See LICENSE for licensing information.

-module(util).
-export([tempfilename/1, fsync/1, exit_with_error/3,
         check_error/3, write_tempfile_and_rename/3,
         spawn_and_wait/1]).

-spec tempfilename(string()) -> string().
tempfilename(Base) ->
    {MegaSecs, Secs, MicroSecs} = now(),
    Filename = io_lib:format("~s-~s-~p.~p", [Base, os:getpid(),
			     MegaSecs * 1000000 + Secs, MicroSecs]),
    Filename.

-spec fsync([string()]) -> ok.
fsync(Paths) ->
     case fsyncport:fsyncall(Paths) of
         ok ->
             ok;
         {error, Error} ->
             exit_with_error(fsync, Error, "Error in fsync")
     end.

-spec exit_with_error(atom(), atom(), string()) -> no_return().
exit_with_error(Operation, Error, ErrorMessage) ->
    io:format("~s(~w): ~w~n", [ErrorMessage, Operation, Error]),
    exit({fileerror, Operation, Error, ErrorMessage}).

-spec check_error(any(), atom(), string()) -> ok.
check_error(ReturnValue, Operation, ErrorMessage) ->
    case ReturnValue of
        ok ->
            ok;
        {error, Error} ->
            exit_with_error(Operation, Error, ErrorMessage)
    end.

-spec write_tempfile_and_rename(string(), string(), binary()) -> ok.
write_tempfile_and_rename(Name, NurseryName, Content) ->
    case file:open(NurseryName, [write, exclusive]) of
        {ok, File} ->
            ok = file:write(File, Content),
            file:close(File),
	    check_error(file:rename(NurseryName, Name), rename,
                        "Error when renaming tempfile to final file");
        {error, eexist} ->
	    %% Should not happen, file name should be unique
            exit_with_error(writefile, eexist,
                            "File existed when creating tempfile");
        {error, Error} ->
            exit_with_error(writefile, Error,
                            "Error when creating tempfile")
    end.

spawn_and_wait(Fun) ->
    ParentPid = self(),
    ChildPid = spawn_link(fun () ->
                                  try
                                      Result = Fun(),
                                      ParentPid ! {result, self(), Result}
                                  catch
                                      Type:What ->
                                          [CrashFunction | Stack] = erlang:get_stacktrace(),
                                          lager:error("Crashed process: ~p ~p~n  ~p~n  ~p~n", [Type, What, CrashFunction, Stack]),
                                          ParentPid ! {result, self(), crash}
                                  end
                          end),
    receive
        {result, ChildPid, Result} ->
            Result
    end.