summaryrefslogtreecommitdiff
path: root/lib/os_mon/src/disksup.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/os_mon/src/disksup.erl')
-rw-r--r--lib/os_mon/src/disksup.erl210
1 files changed, 177 insertions, 33 deletions
diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl
index ecf3928d89..8df01f9eb9 100644
--- a/lib/os_mon/src/disksup.erl
+++ b/lib/os_mon/src/disksup.erl
@@ -22,7 +22,7 @@
%% API
-export([start_link/0]).
--export([get_disk_data/0,
+-export([get_disk_data/0, get_disk_info/0, get_disk_info/1,
get_check_interval/0, set_check_interval/1,
get_almost_full_threshold/0, set_almost_full_threshold/1]).
-export([dummy_reply/1, param_type/2, param_default/1]).
@@ -46,6 +46,12 @@ start_link() ->
get_disk_data() ->
os_mon:call(disksup, get_disk_data, infinity).
+get_disk_info() ->
+ os_mon:call(disksup, get_disk_info, infinity).
+
+get_disk_info(Path) ->
+ os_mon:call(disksup, {get_disk_info, Path}, infinity).
+
get_check_interval() ->
os_mon:call(disksup, get_check_interval, infinity).
set_check_interval(Value) ->
@@ -68,6 +74,10 @@ set_almost_full_threshold(Float) ->
dummy_reply(get_disk_data) ->
[{"none", 0, 0}];
+dummy_reply(get_disk_info) ->
+ [{"none", 0, 0, 0}];
+dummy_reply({get_disk_info, Path}) ->
+ [{Path, 0, 0, 0}];
dummy_reply(get_check_interval) ->
case os_mon:get_env(disksup, disk_space_check_interval) of
{TimeUnit, Time} ->
@@ -149,6 +159,12 @@ init([]) ->
handle_call(get_disk_data, _From, State) ->
{reply, State#state.diskdata, State};
+handle_call(get_disk_info, _From, #state{os = OS, port = Port} = State) ->
+ {reply, get_disk_info(OS, Port), State};
+
+handle_call({get_disk_info, Path}, _From, #state{os = OS, port = Port} = State) ->
+ {reply, get_disk_info(Path, OS, Port), State};
+
handle_call(get_check_interval, _From, State) ->
{reply, State#state.timeout, State};
handle_call({set_check_interval, {TimeUnit, Time}}, _From, State) ->
@@ -261,6 +277,134 @@ find_cmd(Cmd, Path) ->
Found
end.
+%%-- Run "df" based on OS ----------------------------------------------
+run_df(OS, Port) ->
+ run_df("", OS, Port).
+
+run_df(Path, {unix, solaris}, Port) ->
+ my_cmd("/usr/bin/df -lk " ++ Path, Port);
+run_df(Path, {unix, irix}, Port) ->
+ my_cmd("/usr/sbin/df -lk " ++ Path, Port);
+run_df(Path, {unix, linux}, Port) ->
+ Df = find_cmd("df", "/bin"),
+ my_cmd(Df ++ " -lk -x squashfs " ++ Path, Port);
+run_df(Path, {unix, posix}, Port) ->
+ my_cmd("df -k -P " ++ Path, Port);
+run_df(Path, {unix, dragonfly}, Port) ->
+ my_cmd("/bin/df -k -t ufs,hammer " ++ Path, Port);
+run_df(Path, {unix, freebsd}, Port) ->
+ my_cmd("/bin/df -k -l " ++ Path, Port);
+run_df(Path, {unix, openbsd}, Port) ->
+ my_cmd("/bin/df -k -l " ++ Path, Port);
+run_df(Path, {unix, netbsd}, Port) ->
+ my_cmd("/bin/df -k -t ffs " ++ Path, Port);
+run_df(Path, {unix, sunos4}, Port) ->
+ my_cmd("df " ++ Path, Port);
+run_df(Path, {unix, darwin}, Port) ->
+ my_cmd("/bin/df -i -k -t ufs,hfs,apfs " ++ Path, Port).
+
+%%--Get disk info-------------------------------------------------------
+%% We use as many absolute paths as possible below as there may be stale
+%% NFS handles in the PATH which cause these commands to hang.
+get_disk_info(OS, Port) ->
+ get_disk_info("", OS, Port).
+
+get_disk_info(Path, OS, Port) ->
+ case do_get_disk_info(Path, OS, Port) of
+ [] -> dummy_reply({get_disk_info, Path});
+ DiskInfo -> DiskInfo
+ end.
+
+do_get_disk_info("", {win32, _}, not_used) ->
+ Result = os_mon_sysinfo:get_disk_info(),
+ disk_info_win32(Result);
+do_get_disk_info(DriveRoot, {win32, _}, not_used) ->
+ Result = os_mon_sysinfo:get_disk_info(DriveRoot),
+ disk_info_win32(Result);
+do_get_disk_info(Path, {unix, solaris}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, irix}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_irix(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, linux}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, posix}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, dragonfly}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, freebsd}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, openbsd}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, netbsd}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, sunos4}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_solaris(skip_to_eol(Result));
+do_get_disk_info(Path, {unix, darwin}=OS, Port) ->
+ Result = run_df(Path, OS, Port),
+ disk_info_susv3(skip_to_eol(Result)).
+
+disk_info_win32([]) ->
+ [];
+disk_info_win32([H|T]) ->
+ case io_lib:fread("~s~s~d~d~d", H) of
+ {ok, [Drive, "DRIVE_FIXED", BAvail, BTot, _TotFree], _RestStr} ->
+ KiBTotal = BTot div 1024,
+ KiBAvailable = BAvail div 1024,
+ BUsed = BTot - BAvail,
+ Capacity = trunc(math:ceil(100 * (BUsed / BTot))),
+ [{Drive, KiBTotal, KiBAvailable, Capacity} | disk_info_win32(T)];
+ {ok, _, _RestStr} ->
+ disk_info_win32(T);
+ _Other ->
+ []
+ end.
+
+% This code works for Linux and FreeBSD as well
+disk_info_solaris("") ->
+ [];
+disk_info_solaris("\n") ->
+ [];
+disk_info_solaris(Str) ->
+ case parse_df(Str, posix) of
+ {ok, {KiBTotal, KiBAvailable, Capacity, MntOn}, RestStr} ->
+ [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_solaris(RestStr)];
+ _Other ->
+ disk_info_solaris(skip_to_eol(Str))
+ end.
+
+%% Irix: like Linux with an extra FS type column and no '%'.
+disk_info_irix("") -> [];
+disk_info_irix("\n") -> [];
+disk_info_irix(Str) ->
+ case io_lib:fread("~s~s~d~d~d~d~s", Str) of
+ {ok, [_FS, _FSType, KiBAvailable, Capacity, _Avail, KiBTotal, MntOn], RestStr} ->
+ [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_irix(RestStr)];
+ _Other ->
+ disk_info_irix(skip_to_eol(Str))
+ end.
+
+% Parse per SUSv3 specification, notably recent OS X
+disk_info_susv3("") ->
+ [];
+disk_info_susv3("\n") ->
+ [];
+disk_info_susv3(Str) ->
+ case parse_df(Str, susv3) of
+ {ok, {KiBTotal, KiBAvailable, Capacity, MntOn}, RestStr} ->
+ [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_susv3(RestStr)];
+ _Other ->
+ disk_info_susv3(skip_to_eol(Str))
+ end.
+
%%--Check disk space----------------------------------------------------
%% We use as many absolute paths as possible below as there may be stale
@@ -268,36 +412,35 @@ find_cmd(Cmd, Path) ->
check_disk_space({win32,_}, not_used, Threshold) ->
Result = os_mon_sysinfo:get_disk_info(),
check_disks_win32(Result, Threshold);
-check_disk_space({unix, solaris}, Port, Threshold) ->
- Result = my_cmd("/usr/bin/df -lk", Port),
+check_disk_space({unix, solaris}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, irix}, Port, Threshold) ->
- Result = my_cmd("/usr/sbin/df -lk",Port),
+check_disk_space({unix, irix}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_irix(skip_to_eol(Result), Threshold);
-check_disk_space({unix, linux}, Port, Threshold) ->
- Df = find_cmd("df", "/bin"),
- Result = my_cmd(Df ++ " -lk -x squashfs", Port),
+check_disk_space({unix, linux}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, posix}, Port, Threshold) ->
- Result = my_cmd("df -k -P", Port),
+check_disk_space({unix, posix}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, dragonfly}, Port, Threshold) ->
- Result = my_cmd("/bin/df -k -t ufs,hammer", Port),
+check_disk_space({unix, dragonfly}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, freebsd}, Port, Threshold) ->
- Result = my_cmd("/bin/df -k -l", Port),
+check_disk_space({unix, freebsd}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, openbsd}, Port, Threshold) ->
- Result = my_cmd("/bin/df -k -l", Port),
+check_disk_space({unix, openbsd}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, netbsd}, Port, Threshold) ->
- Result = my_cmd("/bin/df -k -t ffs", Port),
+check_disk_space({unix, netbsd}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, sunos4}, Port, Threshold) ->
- Result = my_cmd("df", Port),
+check_disk_space({unix, sunos4}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
-check_disk_space({unix, darwin}, Port, Threshold) ->
- Result = my_cmd("/bin/df -i -k -t ufs,hfs,apfs", Port),
+check_disk_space({unix, darwin}=OS, Port, Threshold) ->
+ Result = run_df(OS, Port),
check_disks_susv3(skip_to_eol(Result), Threshold).
% This code works for Linux and FreeBSD as well
@@ -307,14 +450,14 @@ check_disks_solaris("\n", _Threshold) ->
[];
check_disks_solaris(Str, Threshold) ->
case parse_df(Str, posix) of
- {ok, {KB, Cap, MntOn}, RestStr} ->
+ {ok, {KiBTotal, _KiBAvailable, Capacity, MntOn}, RestStr} ->
if
- Cap >= Threshold ->
+ Capacity >= Threshold ->
set_alarm({disk_almost_full, MntOn}, []);
true ->
clear_alarm({disk_almost_full, MntOn})
end,
- [{MntOn, KB, Cap} |
+ [{MntOn, KiBTotal, Capacity} |
check_disks_solaris(RestStr, Threshold)];
_Other ->
check_disks_solaris(skip_to_eol(Str),Threshold)
@@ -369,15 +512,15 @@ parse_df_take_word_percent(Input) ->
%% and capacity), skip % sign, (optionally for susv3 can also skip IUsed, IFree
%% and ICap% fields) then take remaining characters as the mount path
-spec parse_df(string(), posix | susv3) ->
- {error, parse_df} | {ok, {integer(), integer(), list()}, string()}.
+ {error, parse_df} | {ok, {integer(), integer(), integer(), list()}, string()}.
parse_df(Input0, Flavor) ->
%% Format of Posix/Linux df output looks like Header + Lines
%% Filesystem 1024-blocks Used Available Capacity Mounted on
%% udev 2467108 0 2467108 0% /dev
Input1 = parse_df_skip_word(Input0), % skip device path field
- {KbStr, Input2} = parse_df_take_word(Input1), % take Kb field
+ {KiBTotalStr, Input2} = parse_df_take_word(Input1), % take Kb field
Input3 = parse_df_skip_word(Input2), % skip Used field
- Input4 = parse_df_skip_word(Input3), % skip Avail field
+ {KiBAvailableStr, Input4} = parse_df_take_word(Input3),
% take Capacity% field; drop a % sign following the capacity
{CapacityStr, Input5} = parse_df_take_word_percent(Input4),
@@ -401,9 +544,10 @@ parse_df(Input0, Flavor) ->
Remaining = lists:dropwhile(fun(X) -> not parse_df_is_not_eol(X) end,
Input7),
try
- Kb = erlang:list_to_integer(KbStr),
+ KiBTotal = erlang:list_to_integer(KiBTotalStr),
+ KiBAvailable = erlang:list_to_integer(KiBAvailableStr),
Capacity = erlang:list_to_integer(CapacityStr),
- {ok, {Kb, Capacity, MountPath}, Remaining}
+ {ok, {KiBTotal, KiBAvailable, Capacity, MountPath}, Remaining}
catch error:badarg ->
{error, parse_df}
end.
@@ -415,14 +559,14 @@ check_disks_susv3("\n", _Threshold) ->
[];
check_disks_susv3(Str, Threshold) ->
case parse_df(Str, susv3) of
- {ok, {KB, Cap, MntOn}, RestStr} ->
+ {ok, {KiBTotal, _KiBAvailable, Capacity, MntOn}, RestStr} ->
if
- Cap >= Threshold ->
+ Capacity >= Threshold ->
set_alarm({disk_almost_full, MntOn}, []);
true ->
clear_alarm({disk_almost_full, MntOn})
end,
- [{MntOn, KB, Cap} |
+ [{MntOn, KiBTotal, Capacity} |
check_disks_susv3(RestStr, Threshold)];
_Other ->
check_disks_susv3(skip_to_eol(Str),Threshold)