Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85628072
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6fa8f22
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+calling_from_make:
+ mix compile
+
+UNAME := $(shell uname)
+
+CFLAGS ?= -Wall -Werror -Wno-unused-parameter -pedantic -std=c99 -O3
+
+ifeq ($(UNAME), Darwin)
+ TARGET_CFLAGS ?= -fPIC -undefined dynamic_lookup -dynamiclib -Wextra
+endif
+
+ifeq ($(UNAME), Linux)
+ TARGET_CFLAGS ?= -fPIC -shared
+endif
+
+
+all: priv/exile.so
+
+priv/exile.so: c_src/exile.c
+ mkdir -p priv
+ $(CC) -I$(ERL_INTERFACE_INCLUDE_DIR) $(TARGET_CFLAGS) $(CFLAGS) c_src/exile.c -o priv/exile.so
+
+clean:
+ @rm -rf priv/exile.so
diff --git a/priv/.clang-format b/c_src/.clang-format
similarity index 100%
rename from priv/.clang-format
rename to c_src/.clang-format
diff --git a/priv/exile_nif.c b/c_src/exile.c
similarity index 94%
rename from priv/exile_nif.c
rename to c_src/exile.c
index effb6aa..bd004b2 100644
--- a/priv/exile_nif.c
+++ b/c_src/exile.c
@@ -1,278 +1,279 @@
#include "erl_nif.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define ERL_TRUE enif_make_atom(env, "true")
#define ERL_FALSE enif_make_atom(env, "false")
#define ERL_OK(__TERM__) \
enif_make_tuple2(env, enif_make_atom(env, "ok"), __TERM__)
#define ERL_ERROR(__TERM__) \
enif_make_tuple2(env, enif_make_atom(env, "error"), __TERM__)
static const int PIPE_READ = 0;
static const int PIPE_WRITE = 1;
static const int MAX_ARGUMENTS = 20;
static const int MAX_ARGUMENT_LEN = 1024;
enum exec_status {
SUCCESS,
PIPE_CREATE_ERROR,
PIPE_FLAG_ERROR,
FORK_ERROR,
PIPE_DUP_ERROR
};
typedef struct ExecResults {
enum exec_status status;
int err;
pid_t pid;
int pipe_in;
int pipe_out;
} ExecResult;
static int set_flag(int fd, int flags) {
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags);
}
static void close_all(int pipes[3][2]) {
for (int i = 0; i < 3; i++) {
if (pipes[i][PIPE_READ])
close(pipes[i][PIPE_READ]);
if (pipes[i][PIPE_WRITE])
close(pipes[i][PIPE_WRITE]);
}
}
#define RETURN_ERROR(__ERR__) \
do { \
fprintf(stderr, "error in start_proccess(), %s:%d %s\n", __FILE__, \
__LINE__, strerror(errno)); \
result.status = __ERR__; \
result.err = errno; \
close_all(pipes); \
return result; \
} while (0);
static ExecResult start_proccess(char *args[], bool stderr_to_console) {
ExecResult result;
pid_t pid;
int pipes[3][2] = {{0, 0}, {0, 0}, {0, 0}};
if (pipe(pipes[STDIN_FILENO]) == -1 || pipe(pipes[STDOUT_FILENO]) == -1 ||
pipe(pipes[STDERR_FILENO]) == -1) {
RETURN_ERROR(PIPE_CREATE_ERROR)
}
if (set_flag(pipes[STDIN_FILENO][PIPE_READ], O_CLOEXEC) < 0 ||
set_flag(pipes[STDOUT_FILENO][PIPE_WRITE], O_CLOEXEC) < 0 ||
set_flag(pipes[STDIN_FILENO][PIPE_WRITE], O_CLOEXEC | O_NONBLOCK) < 0 ||
set_flag(pipes[STDOUT_FILENO][PIPE_READ], O_CLOEXEC | O_NONBLOCK) < 0 ||
set_flag(pipes[STDERR_FILENO][PIPE_READ], O_CLOEXEC | O_NONBLOCK) < 0 ||
set_flag(pipes[STDERR_FILENO][PIPE_WRITE], O_CLOEXEC | O_NONBLOCK) < 0) {
RETURN_ERROR(PIPE_FLAG_ERROR)
}
switch (pid = fork()) {
case -1:
RETURN_ERROR(FORK_ERROR)
case 0:
close(STDIN_FILENO);
close(STDOUT_FILENO);
if (dup2(pipes[STDIN_FILENO][PIPE_READ], STDIN_FILENO) < 0)
RETURN_ERROR(PIPE_DUP_ERROR)
if (dup2(pipes[STDOUT_FILENO][PIPE_WRITE], STDOUT_FILENO) < 0)
RETURN_ERROR(PIPE_DUP_ERROR)
if (stderr_to_console != true) {
close(STDERR_FILENO);
int dev_null = open("/dev/null", O_WRONLY);
if (dup2(dev_null, STDERR_FILENO) < 0)
RETURN_ERROR(PIPE_DUP_ERROR)
close(dev_null);
}
close_all(pipes);
execvp(args[0], args);
perror("execvp(): failed");
default:
close(pipes[STDIN_FILENO][PIPE_READ]);
close(pipes[STDOUT_FILENO][PIPE_WRITE]);
result.pid = pid;
result.pipe_in = pipes[STDIN_FILENO][PIPE_WRITE];
result.pipe_out = pipes[STDOUT_FILENO][PIPE_READ];
result.status = SUCCESS;
return result;
}
}
static ERL_NIF_TERM exec_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
char _temp[MAX_ARGUMENTS][MAX_ARGUMENT_LEN];
char *exec_args[MAX_ARGUMENTS + 1];
- char *arg = NULL;
bool stderr_to_console = true;
unsigned int args_len;
if (enif_get_list_length(env, argv[0], &args_len) != true)
return enif_make_badarg(env);
if (args_len > MAX_ARGUMENTS)
return enif_make_badarg(env);
ERL_NIF_TERM head, tail, list = argv[0];
- for (int i = 0; i < args_len; i++) {
+ for (unsigned int i = 0; i < args_len; i++) {
if (enif_get_list_cell(env, list, &head, &tail) != true)
return enif_make_badarg(env);
if (enif_get_string(env, head, _temp[i], sizeof(_temp[i]), ERL_NIF_LATIN1) <
1)
return enif_make_badarg(env);
exec_args[i] = _temp[i];
list = tail;
}
exec_args[args_len] = NULL;
int temp;
if (enif_get_int(env, argv[1], &temp) != true)
return enif_make_badarg(env);
stderr_to_console = temp == 1 ? true : false;
ExecResult result = start_proccess(exec_args, stderr_to_console);
ERL_NIF_TERM ret;
switch (result.status) {
case SUCCESS:
ret = enif_make_tuple3(env, enif_make_int(env, result.pid),
enif_make_int(env, result.pipe_in),
enif_make_int(env, result.pipe_out));
return ERL_OK(ret);
default:
ret = enif_make_int(env, result.err);
return ERL_ERROR(ret);
}
}
static ERL_NIF_TERM write_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pipe_in;
enif_get_int(env, argv[0], &pipe_in);
if (argc != 2)
enif_make_badarg(env);
ErlNifBinary bin;
- bool is_success = enif_inspect_binary(env, argv[1], &bin);
+ if (enif_inspect_binary(env, argv[1], &bin) != true)
+ return enif_make_badarg(env);
+
int result = write(pipe_in, bin.data, bin.size);
if (result >= 0) {
return ERL_OK(enif_make_int(env, result));
} else if (errno == EAGAIN) {
return ERL_ERROR(enif_make_int(env, errno));
} else {
perror("write()");
return ERL_ERROR(enif_make_int(env, errno));
}
}
static ERL_NIF_TERM close_pipe(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pipe;
enif_get_int(env, argv[0], &pipe);
int result = close(pipe);
if (result == 0) {
return enif_make_atom(env, "ok");
} else {
perror("close()");
return ERL_ERROR(enif_make_int(env, errno));
}
}
static ERL_NIF_TERM read_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pipe_out, bytes;
enif_get_int(env, argv[0], &pipe_out);
enif_get_int(env, argv[1], &bytes);
if (bytes > 65535 || bytes < 1)
enif_make_badarg(env);
char buf[bytes];
int result = read(pipe_out, buf, sizeof(buf));
if (result >= 0) {
ErlNifBinary bin;
enif_alloc_binary(result, &bin);
memcpy(bin.data, buf, result);
return ERL_OK(enif_make_binary(env, &bin));
} else if (errno == EAGAIN) {
return ERL_ERROR(enif_make_int(env, errno));
} else {
perror("read()");
return ERL_ERROR(enif_make_int(env, errno));
}
}
static ERL_NIF_TERM is_alive(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pid;
enif_get_int(env, argv[0], &pid);
int result = kill(pid, 0);
if (result == 0) {
return ERL_TRUE;
} else {
return ERL_FALSE;
}
}
static ERL_NIF_TERM terminate_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pid;
enif_get_int(env, argv[0], &pid);
return enif_make_int(env, kill(pid, SIGTERM));
}
static ERL_NIF_TERM kill_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pid;
enif_get_int(env, argv[0], &pid);
return enif_make_int(env, kill(pid, SIGKILL));
}
static ERL_NIF_TERM wait_proc(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
int pid, status;
enif_get_int(env, argv[0], &pid);
int wpid = waitpid(pid, &status, WNOHANG);
if (wpid != pid) {
perror("waitpid()");
}
return enif_make_tuple2(env, enif_make_int(env, wpid),
enif_make_int(env, status));
}
static ErlNifFunc nif_funcs[] = {
- {"exec_proc", 2, exec_proc}, {"write_proc", 2, write_proc},
- {"read_proc", 2, read_proc}, {"close_pipe", 1, close_pipe},
- {"terminate_proc", 1, terminate_proc}, {"wait_proc", 1, wait_proc},
- {"kill_proc", 1, kill_proc}, {"is_alive", 1, is_alive},
+ {"exec_proc", 2, exec_proc, 0}, {"write_proc", 2, write_proc, 0},
+ {"read_proc", 2, read_proc, 0}, {"close_pipe", 1, close_pipe, 0},
+ {"terminate_proc", 1, terminate_proc, 0}, {"wait_proc", 1, wait_proc, 0},
+ {"kill_proc", 1, kill_proc, 0}, {"is_alive", 1, is_alive, 0},
};
ERL_NIF_INIT(Elixir.Exile.ProcessHelper, nif_funcs, NULL, NULL, NULL, NULL)
diff --git a/lib/exile/process_helper.ex b/lib/exile/process_helper.ex
index e105f17..cc5fec2 100644
--- a/lib/exile/process_helper.ex
+++ b/lib/exile/process_helper.ex
@@ -1,39 +1,24 @@
defmodule Exile.ProcessHelper do
@on_load :load_nifs
def load_nifs do
- :erlang.load_nif('./priv/exile_nif', 0)
+ nif_path = :filename.join(:code.priv_dir(:exile), "exile")
+ :erlang.load_nif(nif_path, 0)
end
- def exec_proc(_cmd, _stderr_to_console) do
- raise "NIF exec_proc/0 not implemented"
- end
+ def exec_proc(_cmd, _stderr_to_console), do: :erlang.nif_error(:nif_library_not_loaded)
- def write_proc(_pipe, _bin) do
- raise "NIF write_proc/2 not implemented"
- end
+ def write_proc(_pipe, _bin), do: :erlang.nif_error(:nif_library_not_loaded)
- def read_proc(_pipe, _bytes) do
- raise "NIF read_proc/0 not implemented"
- end
+ def read_proc(_pipe, _bytes), do: :erlang.nif_error(:nif_library_not_loaded)
- def close_pipe(_pipe) do
- raise "NIF close_pipe/1 not implemented"
- end
+ def close_pipe(_pipe), do: :erlang.nif_error(:nif_library_not_loaded)
- def kill_proc(_pid) do
- raise "NIF kill_proc/1 not implemented"
- end
+ def kill_proc(_pid), do: :erlang.nif_error(:nif_library_not_loaded)
- def terminate_proc(_pid) do
- raise "NIF terminate_proc/1 not implemented"
- end
+ def terminate_proc(_pid), do: :erlang.nif_error(:nif_library_not_loaded)
- def wait_proc(_pid) do
- raise "NIF wait_proc/1 not implemented"
- end
+ def wait_proc(_pid), do: :erlang.nif_error(:nif_library_not_loaded)
- def is_alive(_pid) do
- raise "NIF is_alive/1 not implemented"
- end
+ def is_alive(_pid), do: :erlang.nif_error(:nif_library_not_loaded)
end
diff --git a/mix.exs b/mix.exs
index f79dae4..ff4e6ce 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,28 +1,30 @@
defmodule Exile.MixProject do
use Mix.Project
def project do
[
app: :exile,
version: "0.1.0",
elixir: "~> 1.7",
start_permanent: Mix.env() == :prod,
+ compilers: [:elixir_make] ++ Mix.compilers(),
+ make_targets: ["all"],
+ make_clean: ["clean"],
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
- # {:dep_from_hexpm, "~> 0.3.0"},
- # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
+ {:elixir_make, "~> 0.6", runtime: false}
]
end
end
diff --git a/mix.lock b/mix.lock
new file mode 100644
index 0000000..a7f64e0
--- /dev/null
+++ b/mix.lock
@@ -0,0 +1,3 @@
+%{
+ "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Aug 8, 9:24 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1723058
Default Alt Text
(12 KB)
Attached To
Mode
R14 exile
Attached
Detach File
Event Timeline
Log In to Comment