Skip to content

Instantly share code, notes, and snippets.

@niamtokik
Created May 12, 2017 05:57
Show Gist options
  • Save niamtokik/1a8788b66b0be4cbf337d3c4df659f03 to your computer and use it in GitHub Desktop.
Save niamtokik/1a8788b66b0be4cbf337d3c4df659f03 to your computer and use it in GitHub Desktop.
%
% extract namespace information from linux procfs.
%
-module(namespace).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
-record(pid, { id :: integer(),
cgroup = 0 :: integer(),
ipc = 0 :: integer(),
mnt = 0 :: integer(),
net = 0 :: integer(),
pid = 0 :: integer(),
user = 0 :: integer(),
uts = 0 :: integer() }).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
procfs() ->
"/proc".
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
procfs(Pid) when is_integer(Pid) ->
procfs(erlang:integer_to_list(Pid));
procfs(Pid) ->
procfs() ++ "/" ++ Pid.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
procfs(Pid, cgroup) ->
procfs(Pid, erlang:atom_to_list(cgroup));
procfs(Pid, pid) ->
procfs(Pid, erlang:atom_to_list(pid));
procfs(Pid, user) ->
procfs(Pid, erlang:atom_to_list(user));
procfs(Pid, net) ->
procfs(Pid, erlang:atom_to_list(net));
procfs(Pid, uts) ->
procfs(Pid, erlang:atom_to_list(uts));
procfs(Pid, ipc) ->
procfs(Pid, erlang:atom_to_list(ipc));
procfs(Pid, mnt) ->
procfs(Pid, erlang:atom_to_list(mnt));
procfs(Pid, Namespace)
when is_list(Namespace) ->
procfs(Pid) ++ "/ns/" ++ Namespace.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
read_namespace(Link) ->
try file:read_link(Link)
of
{ok, Data} -> namespace_parser(Data);
_ -> ""
catch
error:Reason -> {error, Reason}
end.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
read_namespace(Pid, Namespace) ->
read_namespace(procfs(Pid,Namespace)).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_parser("cgroup:[" ++ Namespace) ->
{cgroup, namespace_parser(Namespace, [])};
namespace_parser("ipc:[" ++ Namespace) ->
{ipc, namespace_parser(Namespace, [])};
namespace_parser("mnt:[" ++ Namespace) ->
{mnt, namespace_parser(Namespace, [])};
namespace_parser("net:[" ++ Namespace) ->
{net, namespace_parser(Namespace, [])};
namespace_parser("pid:[" ++ Namespace) ->
{pid, namespace_parser(Namespace, [])};
namespace_parser("user:[" ++ Namespace) ->
{user, namespace_parser(Namespace, [])};
namespace_parser("uts:[" ++ Namespace) ->
{uts, namespace_parser(Namespace, [])};
namespace_parser(_) ->
{error, not_namespace}.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_parser([$]], Buf) ->
erlang:list_to_integer(lists:reverse(Buf));
namespace_parser([H|T], Buf)
when H >= $0 andalso H =< $9 ->
namespace_parser(T, [H] ++ Buf).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_read_link(Link) ->
try file:read_link(Link)
of
{ok, Data} -> namespace_link_extract(Data);
_Else -> _Else
catch
error:Reason -> {error, Reason}
end.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_link_extract_test() ->
TEST001_IN=namespace_link_extract("cgroup:[4026531835]"),
TEST001_OUT={cgroup, 4026531835},
?assertEqual(TEST001_IN, TEST001_OUT),
TEST002_IN=namespace_link_extract("ipc:[4026531839]"),
TEST002_OUT={ipc, 4026531839},
?assertEqual(TEST002_IN, TEST002_OUT),
TEST003_IN=namespace_link_extract("mnt:[4026531840]"),
TEST003_OUT={mnt, 4026531840},
?assertEqual(TEST003_IN, TEST003_OUT),
TEST004_IN=namespace_link_extract("net:[4026531957]"),
TEST004_OUT={net, 4026531957},
?assertEqual(TEST004_IN, TEST004_OUT),
TEST005_IN=namespace_link_extract("pid:[4026531836]"),
TEST005_OUT={pid, 4026531836},
?assertEqual(TEST005_IN, TEST005_OUT),
TEST006_IN=namespace_link_extract("user:[4026531837]"),
TEST006_OUT={user, 4026531837},
?assertEqual(TEST006_IN, TEST006_OUT),
TEST007_IN=namespace_link_extract("uts:[4026531838]"),
TEST007_OUT={uts, 4026531838},
?assertEqual(TEST007_IN, TEST007_OUT).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_link_extract("cgroup:[" ++ NS) ->
{cgroup, namespace_link_extract(NS)};
namespace_link_extract("ipc:[" ++ NS) ->
{ipc, namespace_link_extract(NS)};
namespace_link_extract("mnt:[" ++ NS) ->
{mnt, namespace_link_extract(NS)};
namespace_link_extract("net:[" ++ NS) ->
{net, namespace_link_extract(NS)};
namespace_link_extract("pid:[" ++ NS) ->
{pid,namespace_link_extract(NS)};
namespace_link_extract("user:[" ++ NS) ->
{user, namespace_link_extract(NS)};
namespace_link_extract("uts:[" ++ NS) ->
{uts, namespace_link_extract(NS)};
namespace_link_extract(NS) when is_list(NS) ->
erlang:list_to_integer(namespace_link_extract(NS, [])).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
namespace_link_extract([$]], Buf) ->
lists:reverse(Buf);
namespace_link_extract([H|T], Buf)
when H >= $0 andalso H =< $9 ->
namespace_link_extract(T, [H] ++ Buf).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
is_process(Path) ->
try erlang:list_to_integer(Path)
of
_ -> true
catch
throw:_ -> false;
error:_ -> false
end.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
get_pids_as_list() ->
{ok, Directories} = file:read_dir("/proc"),
[ File || File <- Directories, is_process(File) =:= true ].
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
get_ns(Pid) when is_integer(Pid) ->
get_ns(erlang:integer_to_list(Pid));
get_ns(Pid) when is_list(Pid)->
{ok, Files} = file:list_dir("/proc/" ++ Pid ++ "/ns"),
lists:map(fun namespace_read_link/1, Files).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
pid_to_record(Pid) when is_list(Pid) ->
pid_to_record(erlang:list_to_integer(Pid));
pid_to_record(Pid) when is_integer(Pid) ->
#pid{ id = Pid }.
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
ns_to_record(PidStruct) ->
Pid = PidStruct#pid.id,
lists:foldr(fun ns_to_record/2, PidStruct, get_ns(Pid)).
%%--------------------------------------------------------------------
%%
%%--------------------------------------------------------------------
ns_to_record({cgroup, Value}, PidStruct) ->
PidStruct#pid{ cgroup = Value };
ns_to_record({ipc, Value}, PidStruct) ->
PidStruct#pid{ ipc = Value };
ns_to_record({mnt, Value}, PidStruct) ->
PidStruct#pid{ mnt = Value };
ns_to_record({net, Value}, PidStruct) ->
PidStruct#pid{ net = Value };
ns_to_record({pid, Value}, PidStruct) ->
PidStruct#pid{ pid = Value };
ns_to_record({uts, Value}, PidStruct) ->
PidStruct#pid{ uts = Value }.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment