-module(oaspec_ffi). -export([find_executable/1, run_executable/2]). %% Find an executable on PATH. Returns {ok, Path} or {error, nil}. -spec find_executable(binary()) -> {ok, binary()} | {error, nil}. find_executable(Name) -> case os:find_executable(binary_to_list(Name)) of false -> {error, nil}; Path -> {ok, list_to_binary(Path)} end. %% Run an executable with arguments. Returns the exit code as an integer. %% Uses spawn_executable to avoid shell injection. -spec run_executable(binary(), list(binary())) -> integer(). run_executable(Executable, Args) -> Port = open_port( {spawn_executable, binary_to_list(Executable)}, [exit_status, stderr_to_stdout, binary, {args, [binary_to_list(A) || A <- Args]}] ), collect_exit(Port). collect_exit(Port) -> receive {Port, {data, _}} -> collect_exit(Port); {Port, {exit_status, Code}} -> Code after 60000 -> catch port_close(Port), 1 end.