Created
May 12, 2017 05:57
-
-
Save niamtokik/1a8788b66b0be4cbf337d3c4df659f03 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| % | |
| % 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