void *user_data);
typedef int (*loader_terminate_cb)(int argc, char **argv, void *user_data);
+typedef void (*hydra_precreate_cb)(void *user_data);
+typedef void (*hydra_create_cb)(void *user_data);
+typedef void (*hydra_fork_cb)(void *user_data);
+typedef int (*hydra_terminate_cb)(void *user_data);
+
typedef void (*loader_receiver_cb)(int fd);
typedef void (*loader_loop_begin_cb)(void *user_data);
typedef void (*loader_loop_quit_cb)(void *user_data);
loader_terminate_cb terminate;
} loader_lifecycle_callback_s;
+typedef struct {
+ hydra_precreate_cb precreate;
+ hydra_create_cb create;
+ hydra_fork_cb fork;
+ hydra_terminate_cb terminate;
+} hydra_lifecycle_callback_s;
+
typedef struct {
loader_loop_begin_cb loop_begin;
loader_loop_quit_cb loop_quit;
loader_lifecycle_callback_s *callbacks,
loader_adapter_s *adapter, void *user_data);
+int launchpad_hydra_main(int argc, char **argv,
+ hydra_lifecycle_callback_s *hydra_callbacks,
+ loader_lifecycle_callback_s *callbacks,
+ loader_adapter_s *adapter, void *user_data);
+
/*
* @par Description
* Set program scheduling priority.
#define SOCKET_PATH "/run/aul"
#define LAUNCHPAD_LOADER_SOCKET_NAME ".launchpad-type"
+#define HYDRA_LOADER_SOCKET_NAME ".hydra-loader"
#define MAX_PENDING_CONNECTIONS 10
#define MAX_LOCAL_BUFSZ 128
#define AUL_SOCK_MAXBUFF 131071
LOADER_ARG_PATH,
LOADER_ARG_TYPE,
LOADER_ARG_ID,
+ LOADER_ARG_HYDRA,
LOADER_ARG_EXTRA,
LOADER_ARG_DUMMY,
};
+enum hydra_cmd {
+ LAUNCH_CANDIDATE,
+};
+
typedef struct _app_pkt_t {
int cmd;
int len;
app_pkt_t *_accept_recv_pkt_raw(int fd, int *clifd, struct ucred *cr);
int _send_pkt_raw(int client_fd, app_pkt_t *pkt);
int _connect_to_launchpad(int type, int id);
+int _connect_to_launchpad_hydra(int type, int id);
int _set_sock_option(int fd, int cli);
void _set_env(appinfo_t *menu_info, bundle *kb);
char **_create_argc_argv(bundle *kb, int *margc);
int activation_method;
int deactivation_method;
unsigned int ttl;
+ bool is_hydra;
} loader_info_t;
typedef void (*loader_info_foreach_cb)(loader_info_t *info, void *data);
#define EXEC_CANDIDATE_WAIT 1
#define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
#define CANDIDATE_NONE 0
+#define HYDRA_NONE 0
#define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock"
#define LAUNCHPAD_LOGGER_SOCK ".launchpad-logger-sock"
#define LOADER_PATH_DEFAULT "/usr/bin/launchpad-loader"
typedef struct {
int type;
bool prepared;
- int pid;
+ int pid; /* for hydra this pid is not the pid of hydra itself */
+ /* but pid of non-hydra candidate, which was forked from hydra */
+ int hydra_pid;
int loader_id;
int caller_pid;
int send_fd;
+ int hydra_fd;
int last_exec_time;
guint source;
guint timer;
unsigned int ttl;
guint live_timer;
int state;
+ bool is_hydra;
} candidate_process_context_t;
typedef struct {
int detection_method, int activation_method,
int deactivation_method, unsigned int ttl, int timeout_val,
int threshold_max, int threshold_min, bool on_boot,
- bool app_exists);
+ bool app_exists, bool is_hydra);
static int __remove_slot(int type, int loader_id);
static int __add_default_slots(void);
static gboolean __handle_idle_checker(gpointer data);
return NULL;
}
+static candidate_process_context_t *__find_hydra_slot_from_pid(int pid)
+{
+ candidate_process_context_t *cpc;
+ GList *iter = candidate_slot_list;
+
+ while (iter) {
+ cpc = (candidate_process_context_t *)iter->data;
+ if (cpc->is_hydra && pid == cpc->hydra_pid)
+ return cpc;
+
+ iter = g_list_next(iter);
+ }
+
+ return NULL;
+}
+
static candidate_process_context_t *__find_slot_from_caller_pid(int caller_pid)
{
candidate_process_context_t *cpc;
return -1;
}
-static int __listen_candidate_process(int type, int loader_id)
+static int __listen_addr(struct sockaddr_un *addr)
{
- struct sockaddr_un addr;
int fd = -1;
-
- _D("[launchpad] enter, type: %d", type);
-
- memset(&addr, 0x00, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
- SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME,
- type, loader_id);
-
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
_E("Socket error");
goto error;
}
- unlink(addr.sun_path);
+ unlink(addr->sun_path);
- _D("bind to %s", addr.sun_path);
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ _D("bind to %s", addr->sun_path);
+ if (bind(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un)) < 0) {
_E("bind error");
goto error;
}
- _D("listen to %s", addr.sun_path);
+ _D("listen to %s", addr->sun_path);
if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) {
_E("listen error");
goto error;
return -1;
}
+static int __listen_candidate_process(int type, int loader_id)
+{
+ struct sockaddr_un addr;
+
+ _D("[launchpad] enter, type: %d", type);
+
+ memset(&addr, 0x00, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
+ SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME,
+ type, loader_id);
+
+ return __listen_addr(&addr);
+}
+
+static int __listen_hydra_process(int type, int loader_id)
+{
+ struct sockaddr_un addr;
+
+ _D("[launchpad] enter, type: %d", type);
+
+ memset(&addr, 0x00, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
+ SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
+ type, loader_id);
+
+ return __listen_addr(&addr);
+}
+
static int __get_loader_id(bundle *kb)
{
const char *val;
}
}
+static int __hydra_send_request(int fd, enum hydra_cmd cmd)
+{
+ int sent = 0;
+ int size = sizeof(cmd);
+ int send_ret = 0;
+
+ while (sent != size) {
+ send_ret = send(fd, (char *)&cmd + sent,
+ size - sent, MSG_NOSIGNAL);
+ if (send_ret == -1) {
+ _E("send error! (%d)", errno);
+ return -1;
+ }
+
+ sent += send_ret;
+ _D("send(%d: ret: %d) : %d / %d",
+ fd, send_ret, sent, size);
+ }
+
+ return 0;
+}
+
+static int __hydra_send_launch_candidate_request(int fd)
+{
+ SECURE_LOGD("Send launch cmd to hydra, fd: %d", fd);
+ return __hydra_send_request(fd, LAUNCH_CANDIDATE);
+}
+
static int __prepare_candidate_process(int type, int loader_id)
{
int pid;
char type_str[2] = {0, };
char loader_id_str[10] = {0, };
char argbuf[LOADER_ARG_LEN];
- char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};
+ char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
candidate_process_context_t *cpt = __find_slot(type, loader_id);
if (cpt == NULL)
return -1;
+ if (cpt->is_hydra && cpt->hydra_pid != HYDRA_NONE)
+ return __hydra_send_launch_candidate_request(cpt->hydra_fd);
+
_D("prepare candidate process / type:%d", type);
memset(argbuf, ' ', LOADER_ARG_LEN);
argbuf[LOADER_ARG_LEN - 1] = '\0';
argv[LOADER_ARG_PATH] = cpt->loader_path;
argv[LOADER_ARG_TYPE] = type_str;
argv[LOADER_ARG_ID] = loader_id_str;
+ argv[LOADER_ARG_HYDRA] = cpt->is_hydra ? "1" : "0";
argv[LOADER_ARG_EXTRA] = cpt->loader_extra;
pid = __fork_app_process(__exec_loader_process, argv);
return -1;
}
- cpt->pid = pid;
- __set_live_timer(cpt);
+ if (cpt->is_hydra) {
+ cpt->hydra_pid = pid;
+ } else {
+ cpt->pid = pid;
+ __set_live_timer(cpt);
+ }
return 0;
}
__reset_slot(cpc);
}
+static void __dispose_hydra_process(candidate_process_context_t *cpc)
+{
+ if (!cpc)
+ return;
+
+ __dispose_candidate_process(cpc);
+
+ _D("Dispose hydra process %d", cpc->type);
+ if (cpc->hydra_pid > 0) {
+ _D("kill process %d", cpc->hydra_pid);
+ __kill_process(cpc->hydra_pid);
+ cpc->hydra_pid = HYDRA_NONE;
+ }
+
+ if (cpc->hydra_fd > 0) {
+ close(cpc->hydra_fd);
+ cpc->hydra_fd = -1;
+ }
+}
+
static int __send_launchpad_loader(candidate_process_context_t *cpc,
app_pkt_t *pkt, const char *app_path, int clifd)
{
return G_SOURCE_CONTINUE;
}
+static gboolean __handle_hydra_client_event(gpointer data)
+{
+ loader_context_t *lc = (loader_context_t *)data;
+ int type = lc->type;
+ int loader_id = lc->loader_id;
+ gushort revents = lc->gpollfd->revents;
+ candidate_process_context_t *cpc = __find_slot(type, loader_id);
+
+ if (cpc == NULL)
+ return G_SOURCE_REMOVE;
+
+ if (revents & (G_IO_HUP | G_IO_NVAL)) {
+ SECURE_LOGE("Type %d hydra process was " \
+ "(POLLHUP|POLLNVAL), pid: %d",
+ cpc->type, cpc->hydra_pid);
+ cpc->hydra_pid = HYDRA_NONE;
+ __dispose_hydra_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
static gboolean __handle_loader_event(gpointer data)
{
loader_context_t *lc = (loader_context_t *) data;
if (!cpc->prepared) {
ret = __accept_candidate_process(fd, &client_fd, &client_pid);
if (ret >= 0) {
+ /* for hydra need to set pid to pid of non-hydra candidate, */
+ /* which is connecting now */
+ if (cpc->is_hydra)
+ cpc->pid = client_pid;
+
cpc->prepared = true;
cpc->send_fd = client_fd;
return G_SOURCE_CONTINUE;
}
+static gboolean __handle_hydra_event(gpointer data)
+{
+ loader_context_t *lc = (loader_context_t *) data;
+ int fd = lc->gpollfd->fd;
+ int type = lc->type;
+ int loader_id = lc->loader_id;
+ int client_fd;
+ int client_pid;
+ int ret;
+
+ candidate_process_context_t *cpc = __find_slot(type, loader_id);
+
+ if (cpc == NULL)
+ return G_SOURCE_REMOVE;
+
+ if (!cpc->prepared) {
+ ret = __accept_candidate_process(fd, &client_fd, &client_pid);
+ if (ret >= 0) {
+ cpc->hydra_fd = client_fd;
+
+ SECURE_LOGD("Type %d hydra process was connected," \
+ " pid: %d", type, cpc->hydra_pid);
+
+ cpc->source = __poll_fd(client_fd, G_IO_IN | G_IO_HUP,
+ __handle_hydra_client_event, type,
+ loader_id);
+ if (cpc->source == 0)
+ close(client_fd);
+ }
+ } else {
+ __refuse_candidate_process(fd);
+ _E("Refused hydra process connection");
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
static gboolean __handle_sigchild(gpointer data)
{
candidate_process_context_t *cpc;
struct signalfd_siginfo siginfo;
ssize_t s;
char *appid;
+ int pid;
do {
s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
_signal_process_sigchld(&siginfo);
+ pid = siginfo.ssi_code != SI_QUEUE ? siginfo.ssi_pid : siginfo.ssi_int;
+
appid = g_hash_table_lookup(__pid_table,
- GINT_TO_POINTER(siginfo.ssi_pid));
+ GINT_TO_POINTER(pid));
if (appid) {
- security_manager_cleanup_app(appid, siginfo.ssi_uid, siginfo.ssi_pid);
+ security_manager_cleanup_app(appid, siginfo.ssi_uid, pid);
g_hash_table_remove(__pid_table,
- GINT_TO_POINTER(siginfo.ssi_pid));
+ GINT_TO_POINTER(pid));
}
- cpc = __find_slot_from_pid(siginfo.ssi_pid);
+ cpc = __find_slot_from_pid(pid);
if (cpc != NULL) {
cpc->pid = CANDIDATE_NONE;
__dispose_candidate_process(cpc);
__prepare_candidate_process(cpc->type, cpc->loader_id);
+ } else {
+ cpc = __find_hydra_slot_from_pid(pid);
+ if (cpc != NULL) {
+ cpc->hydra_pid = HYDRA_NONE;
+ __dispose_hydra_process(cpc);
+ __prepare_candidate_process(cpc->type, cpc->loader_id);
+ }
}
- cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
+ cpc = __find_slot_from_caller_pid(pid);
while (cpc) {
__remove_slot(LAUNCHPAD_TYPE_DYNAMIC, cpc->loader_id);
- cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
+ cpc = __find_slot_from_caller_pid(pid);
}
} while (s > 0);
DEFAULT_CPU_THRESHOLD_MAX,
DEFAULT_CPU_THRESHOLD_MIN,
false,
- true);
+ true, 0);
__set_timer(cpc);
return lid;
}
int activation_method, int deactivation_method,
unsigned int ttl, int timeout_val,
int threshold_max, int threshold_min,
- bool on_boot, bool app_exists)
+ bool on_boot, bool app_exists, bool is_hydra)
{
candidate_process_context_t *cpc;
int fd = -1;
cpc->type = type;
cpc->prepared = false;
cpc->pid = CANDIDATE_NONE;
+ cpc->hydra_pid = HYDRA_NONE;
cpc->caller_pid = caller_pid;
cpc->loader_id = loader_id;
cpc->send_fd = -1;
+ cpc->hydra_fd = -1;
cpc->last_exec_time = 0;
cpc->source = 0;
cpc->timer = 0;
cpc->deactivation_method = deactivation_method;
cpc->ttl = ttl;
cpc->live_timer = 0;
+ cpc->is_hydra = is_hydra;
if ((cpc->deactivation_method & METHOD_OUT_OF_MEMORY) &&
__is_low_memory())
return NULL;
}
+ if (is_hydra) {
+ fd = __listen_hydra_process(cpc->type, cpc->loader_id);
+ if (fd == -1) {
+ _E("[launchpad] Listening the socket to " \
+ "the type %d hydra process failed.",
+ cpc->type);
+ free(cpc);
+ return NULL;
+ }
+
+ pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_hydra_event,
+ cpc->type, cpc->loader_id);
+ if (pollfd == 0) {
+ close(fd);
+ free(cpc);
+ return NULL;
+ }
+ }
+
candidate_slot_list = g_list_append(candidate_slot_list, cpc);
return cpc;
info->cpu_threshold_max,
info->cpu_threshold_min,
false,
- info->app_exists);
+ info->app_exists, info->is_hydra);
if (cpc == NULL)
return;
info->cpu_threshold_max,
info->cpu_threshold_min,
info->on_boot,
- info->app_exists);
+ info->app_exists, info->is_hydra);
if (cpc == NULL)
return;
return fd;
}
+int _connect_to_launchpad_hydra(int type, int id)
+{
+ char path[PATH_MAX];
+ int fd;
+ int send_ret;
+ pid_t client_pid;
+
+
+ _D("[hydra] enter, type: %d", type);
+
+ snprintf(path, sizeof(path), "%s/daemons/%d/%s%d-%d",
+ SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
+ type, id);
+ fd = __create_client_socket(path);
+ if (fd < 0)
+ return -1;
+
+ client_pid = getpid();
+ send_ret = send(fd, &client_pid, sizeof(client_pid), MSG_NOSIGNAL);
+ _D("send(%d) : %d", client_pid, send_ret);
+ if (send_ret == -1) {
+ _E("send error");
+ close(fd);
+ return -1;
+ }
+
+ SECURE_LOGD("[hydra] done, connect fd: %d", fd);
+ return fd;
+}
+
#ifdef TIZEN_FEATURE_SET_PERSONALITY_32
static void __set_execution_domain(void)
{
#include <buxton2.h>
#include <vconf.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
#include "launchpad_common.h"
#include "launchpad.h"
#include "preexec.h"
#define AUL_PR_NAME 16
+static hydra_lifecycle_callback_s *__hydra_callbacks;
static loader_lifecycle_callback_s *__loader_callbacks;
static loader_adapter_s *__loader_adapter;
static void *__loader_user_data;
static bundle *__bundle;
static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
static int __loader_id;
+static pid_t __candidate_pid = -1;
+static struct sigaction __prev_sigchld;
static void __at_exit_to_release_bundle(void)
{
}
}
+static void __hydra_receiver_cb(int fd)
+{
+ char err_str[MAX_LOCAL_BUFSZ] = { 0, };
+ enum hydra_cmd cmd = -1;
+ int len;
+ pid_t pid;
+ int r;
+
+ _D("[hydra] ECORE_FD_READ");
+
+retry_recv:
+ len = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL);
+ if (len < 0)
+ if (errno == EINTR)
+ goto retry_recv;
+
+ if (len < sizeof(cmd)) {
+ _E("[hydra] failed to recv: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ goto err;
+ }
+
+ _D("[hydra] success recv cmd: %d", cmd);
+
+ switch (cmd) {
+ case LAUNCH_CANDIDATE:
+ _D("[hydra] launch new child");
+ break;
+ default:
+ _E("[hydra] unknown command from launchpad: %d", cmd);
+ goto err;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ _E("[hydra] unable to fork: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ } else if (pid > 0) {
+ SECURE_LOGD("[hydra] forked candidate with pid=%d", pid);
+
+ __candidate_pid = pid;
+
+ return;
+ } else {
+ if (sigaction(SIGCHLD, &__prev_sigchld, NULL)) {
+ _E("[hydra] sigaction failed: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ exit(-1);
+ }
+
+ if (__hydra_callbacks->fork)
+ __hydra_callbacks->fork(__loader_user_data);
+
+ /* child, exit loop and start initialization */
+ __loader_adapter->remove_fd(__loader_user_data, fd);
+ close(fd);
+
+ __loader_adapter->loop_quit(__loader_user_data);
+
+ if (__hydra_callbacks->terminate)
+ __hydra_callbacks->terminate(__loader_user_data);
+
+ r = launchpad_loader_main(__argc, __argv, __loader_callbacks,
+ __loader_adapter, __loader_user_data);
+ if (r != 0)
+ _E("[hydra] launchpad_loader_main failed. Error: %d", r);
+
+ exit(r);
+ }
+
+err:
+ __loader_adapter->remove_fd(__loader_user_data, fd);
+ close(fd);
+ exit(-1);
+}
+
static void __update_lang(keynode_t *node, void *user_data)
{
char *lang = vconf_keynode_get_str(node);
return __bundle;
}
+static void sigchld_hdl(int code, siginfo_t *siginfo, void *context)
+{
+ pid_t child_pid;
+ union sigval val;
+ bool is_group_leader = !kill(-siginfo->si_pid, 0);
+
+ while ((child_pid = waitpid(-1, NULL, WNOHANG)) > 0) {
+ /* sigqueue to launchpad getppid() with data=child_pid */
+ if (child_pid == __candidate_pid)
+ __candidate_pid = -1;
+
+ if (is_group_leader)
+ kill(-child_pid, SIGKILL);
+
+ val.sival_int = child_pid;
+ sigqueue(getppid(), SIGCHLD, val);
+ }
+
+ if (__prev_sigchld.sa_flags & SA_SIGINFO) {
+ if (__prev_sigchld.sa_sigaction)
+ __prev_sigchld.sa_sigaction(code, siginfo, context);
+ } else if (__prev_sigchld.sa_handler &&
+ __prev_sigchld.sa_handler != SIG_IGN &&
+ __prev_sigchld.sa_handler != SIG_DFL) {
+ __prev_sigchld.sa_handler(code);
+ }
+}
+
API int launchpad_loader_main(int argc, char **argv,
loader_lifecycle_callback_s *callbacks,
loader_adapter_s *adapter, void *user_data)
{
- if (argc < 3) {
+ int is_hydra;
+
+ if (argc < 4) {
_E("too few argument.");
return -1;
}
+ is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
+
+ if (is_hydra) {
+ _D("Cannot run in hydra mode");
+ return -1;
+ }
+
__loader_type = argv[LOADER_ARG_TYPE][0] - '0';
if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
_E("invalid argument. (type: %d)", __loader_type);
{
return _set_priority(prio);
}
+
+API int launchpad_hydra_main(int argc, char **argv,
+ hydra_lifecycle_callback_s *hydra_callbacks,
+ loader_lifecycle_callback_s *callbacks,
+ loader_adapter_s *adapter, void *user_data)
+{
+ char err_str[MAX_LOCAL_BUFSZ] = { 0, };
+ int is_hydra;
+ int loader_type;
+ int loader_id;
+ int client_fd;
+ pid_t pid;
+ struct sigaction new_act;
+
+ if (argc < 4) {
+ _E("[hydra] too few argument.");
+ return -1;
+ }
+
+ is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
+ argv[LOADER_ARG_HYDRA] = "0";
+ _D("[hydra] mode: %d", is_hydra);
+
+ loader_type = argv[LOADER_ARG_TYPE][0] - '0';
+ if (loader_type < 0 || loader_type >= LAUNCHPAD_TYPE_MAX) {
+ _E("[hydra] invalid argument. (type: %d)", loader_type);
+ return -1;
+ }
+
+ loader_id = atoi(argv[LOADER_ARG_ID]);
+
+ if (hydra_callbacks == NULL) {
+ _E("[hydra] invalid argument. hydra_callback is null");
+ return -1;
+ }
+
+ if (adapter == NULL) {
+ _E("[hydra] invalid argument. adapter is null");
+ return -1;
+ }
+
+ if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
+ || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
+ _E("[hydra] invalid argument. adapter callback is null");
+ return -1;
+ }
+
+ if (hydra_callbacks->precreate)
+ hydra_callbacks->precreate(user_data);
+
+ if (!is_hydra) {
+ _D("Run in non hydra mode");
+ return launchpad_loader_main(argc, argv, callbacks,
+ adapter, user_data);
+ }
+
+ if (hydra_callbacks->create)
+ hydra_callbacks->create(user_data);
+
+ /* Set sigchld handler after calling create, because it can overwrite */
+ /* our handler */
+ memset(&new_act, 0, sizeof(new_act));
+ new_act.sa_sigaction = sigchld_hdl;
+ new_act.sa_flags |= SA_SIGINFO;
+
+ if (sigaction(SIGCHLD, &new_act, &__prev_sigchld)) {
+ _E("[hydra] sigaction failed: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ return -1;
+ }
+
+ /* initial fork to prepare first loader */
+ _D("[hydra] initial fork");
+
+ pid = fork();
+ if (pid < 0) {
+ _E("[hydra] unable to fork: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ return -1;
+ } else if (pid == 0) {
+ if (sigaction(SIGCHLD, &__prev_sigchld, NULL)) {
+ _E("[hydra] sigaction failed: %s",
+ strerror_r(errno, err_str, sizeof(err_str)));
+ return -1;
+ }
+
+ if (hydra_callbacks->fork)
+ hydra_callbacks->fork(user_data);
+
+ return launchpad_loader_main(argc, argv, callbacks,
+ adapter, user_data);
+ } else {
+ __hydra_callbacks = hydra_callbacks;
+ __loader_callbacks = callbacks;
+ __loader_adapter = adapter;
+ __loader_user_data = user_data;
+ __candidate_pid = pid;
+ __argc = argc;
+ __argv = argv;
+
+ __preexec_init(argc, argv);
+
+ /* Set new session ID & new process group ID*/
+ /* In linux, child can set new session ID without check permission */
+ /* TODO : should be add to check permission in the kernel*/
+ setsid();
+
+ malloc_trim(0);
+
+ client_fd = _connect_to_launchpad_hydra(loader_type, loader_id);
+ if (client_fd == -1) {
+ _D("[hydra] connecting to launchpad process was failed.");
+ return -1;
+ }
+
+ __loader_adapter->add_fd(__loader_user_data, client_fd,
+ __hydra_receiver_cb);
+
+ __loader_adapter->loop_begin(__loader_user_data);
+
+ if (__hydra_callbacks->terminate)
+ return __hydra_callbacks->terminate(__loader_user_data);
+
+ return -1;
+ }
+
+ return 0;
+}
\ No newline at end of file
pid_t child_pid;
pid_t child_pgid;
- child_pgid = getpgid(info->ssi_pid);
- _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
- child_pgid, info->ssi_signo, info->ssi_status);
-
- while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
- if (child_pid == child_pgid)
- killpg(child_pgid, SIGKILL);
- __sigchild_action(child_pid);
+ if (info->ssi_code != SI_QUEUE) {
+ child_pgid = getpgid(info->ssi_pid);
+ _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
+ child_pgid, info->ssi_signo, info->ssi_status);
+
+ while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ if (child_pid == child_pgid)
+ killpg(child_pgid, SIGKILL);
+ __sigchild_action(child_pid);
+ }
+ } else {
+ _D("queued signal: dead_pid = %d signo = %d", info->ssi_int,
+ info->ssi_signo);
+ __sigchild_action(info->ssi_int);
}
}
#define TAG_CPU_THRESHOLD_MAX "CPU_THRESHOLD_MAX"
#define TAG_CPU_THRESHOLD_MIN "CPU_THRESHOLD_MIN"
#define TAG_ON_BOOT "ON_BOOT"
+#define TAG_HYDRA "HYDRA"
#define VAL_ON "ON"
#define VAL_OFF "OFF"
info->activation_method = 0;
info->deactivation_method = 0;
info->ttl = 600; /* 10 minutes */
+ info->is_hydra = false;
return info;
}
} else if (strcasecmp(TAG_ON_BOOT, tok1) == 0) {
if (tok2 && strcasecmp(VAL_OFF, tok2) == 0)
cur_info->on_boot = false;
+ } else if (strcasecmp(TAG_HYDRA, tok1) == 0) {
+ if (strcasecmp(VAL_ON, tok2) == 0) {
+ cur_info->is_hydra = 1;
+ } else {
+ cur_info->is_hydra = 0;
+ }
}
}