efl
380 строк · 10.5 Кб
1#ifdef HAVE_CONFIG_H2# include "elementary_config.h"3#endif4#include <stdio.h>5#include <stdlib.h>6#include <errno.h>7#include <string.h>8#include <sys/types.h>9#include <sys/socket.h>10#include <sys/un.h>11#ifdef HAVE_ENVIRON12# define _GNU_SOURCE 113#endif14#include <unistd.h>15#include <sys/stat.h>16#include <fcntl.h>17#include <signal.h>18#include <sys/wait.h>19
20#include <Elementary.h>21
22#ifdef HAVE_ENVIRON23extern char **environ;24#endif25
26static double restart_time = 0.0;27
28#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))29
30static struct sigaction old_sigint;31static struct sigaction old_sigterm;32static struct sigaction old_sigquit;33static struct sigaction old_sigalrm;34static struct sigaction old_sigusr1;35static struct sigaction old_sigusr2;36static struct sigaction old_sighup;37static struct sigaction old_sigchld;38static struct sigaction old_sigsegv;39static struct sigaction old_sigill;40static struct sigaction old_sigfpe;41static struct sigaction old_sigbus;42static struct sigaction old_sigabrt;43static int _log_dom = -1;44
45#define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)46#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)47#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)48#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)49#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)50
51static void52post_fork(void *data EINA_UNUSED)53{
54sigaction(SIGINT, &old_sigint, NULL);55sigaction(SIGTERM, &old_sigterm, NULL);56sigaction(SIGQUIT, &old_sigquit, NULL);57sigaction(SIGALRM, &old_sigalrm, NULL);58sigaction(SIGUSR1, &old_sigusr1, NULL);59sigaction(SIGUSR2, &old_sigusr2, NULL);60sigaction(SIGHUP, &old_sighup, NULL);61sigaction(SIGCHLD, &old_sigchld, NULL);62sigaction(SIGSEGV, &old_sigsegv, NULL);63sigaction(SIGILL, &old_sigill, NULL);64sigaction(SIGFPE, &old_sigfpe, NULL);65sigaction(SIGBUS, &old_sigbus, NULL);66sigaction(SIGABRT, &old_sigabrt, NULL);67if ((_log_dom > -1) && (_log_dom != EINA_LOG_DOMAIN_GLOBAL))68{69eina_log_domain_unregister(_log_dom);70_log_dom = -1;71}72}
73
74static void75child_handler(int x EINA_UNUSED, siginfo_t *info EINA_UNUSED, void *data EINA_UNUSED)76{
77int status;78while (waitpid(-1, &status, WNOHANG) > 0);79}
80
81static void82crash_handler(int x EINA_UNUSED, siginfo_t *info EINA_UNUSED, void *data EINA_UNUSED)83{
84double t;85
86ERR("crash detected. restarting.");87t = ecore_time_get();88if ((t - restart_time) <= 2.0)89{90CRI("crash too fast - less than 2 seconds. abort restart");91exit(-1);92}93ecore_app_restart();94}
95
96static void97handle_run(int fd, unsigned long bytes)98{
99unsigned char *buf = NULL;100int i;101char **argv = NULL;102char **envir = NULL;103char *cwd;104int argc, envnum;105unsigned long off;106
107if (bytes < 1)108{109CRI("no bytes to quicklaunch");110return;111}112DBG("Starting building up process.");113_elm_startup_time = ecore_time_unix_get();114
115buf = alloca(bytes);116if (read(fd, buf, bytes) != (int)bytes)117{118CRI("cannot read %i bytes of args and environment data", (int)bytes);119close(fd);120return;121}122close(fd);123buf[bytes - 1] = 0;124
125argc = ((unsigned long *)(buf))[0];126envnum = ((unsigned long *)(buf))[1];127
128if (argc <= 0)129{130CRI("no executable specified");131return;132}133
134argv = alloca(argc * sizeof(char *));135#ifdef HAVE_ENVIRON136if (envnum > 0) envir = alloca(envnum * sizeof(char *));137#endif138off = ((unsigned long *)(buf))[2 + argc + envnum] - sizeof(unsigned long);139cwd = (char *)(buf + off);140
141for (i = 0; i < argc; i++)142{143off = ((unsigned long *)(buf))[2 + i] - sizeof(unsigned long);144argv[i] = (char *)(buf + off);145}146
147#ifdef HAVE_ENVIRON148if (envir)149{150#ifdef HAVE_CLEARENV151clearenv();152#else153environ = NULL;154#endif155for (i = 0; i < envnum; i++)156{157off = ((unsigned long *)(buf))[2 + argc + i] - sizeof(unsigned long);158envir[i] = (char *)(buf + off);159putenv(envir[i]);160}161}162#endif163
164INF("Requested to run '%s' with %i arguments and %i environment.",165argv[0], argc - 1, envnum);166// Try new form before trying old form167if (!efl_quicklaunch_prepare(argc, argv, cwd))168{169WRN("Failed to prepare with new EFL_MAIN macro, switching to legacy.");170elm_quicklaunch_prepare(argc, argv, cwd);171}172
173elm_quicklaunch_fork(argc, argv, cwd, post_fork, NULL);174elm_quicklaunch_cleanup();175}
176
177int
178main(int argc, char **argv)179{
180int sock, socket_unix_len;181struct stat st;182struct sockaddr_un socket_unix;183struct linger lin;184char buf[PATH_MAX];185struct sigaction action;186const char *domain;187int ret = 0;188size_t len;189
190if (!eina_init())191{192fprintf(stderr, "ERROR: failed to init eina.");193exit(-1);194}195_log_dom = eina_log_domain_register196("elementary_quicklaunch", EINA_COLOR_CYAN);197if (_log_dom < 0)198{199EINA_LOG_ERR("could not register elementary_quicklaunch log domain.");200_log_dom = EINA_LOG_DOMAIN_GLOBAL;201}202
203if (!(domain = getenv("ELM_QUICKLAUNCH_DOMAIN")))204{205domain = getenv("WAYLAND_DISPLAY");206if (!domain) domain = getenv("DISPLAY");207if (!domain) domain = "unknown";208}209eina_vpath_resolve_snprintf(buf, sizeof(buf), "(:usr.run:)/elm-ql-%i", getuid());210if (stat(buf, &st) < 0)211{212ret = mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);213if (ret < 0)214{215CRI("cannot create directory '%s'", buf);216exit(-1);217}218}219eina_vpath_resolve_snprintf(buf, sizeof(buf), "(:usr.run:)/elm-ql-%i/%s", getuid(), domain);220unlink(buf);221sock = socket(AF_UNIX, SOCK_STREAM, 0);222if (sock < 0)223{224CRI("cannot create socket for socket for '%s': %s",225buf, strerror(errno));226exit(-1);227}228if (!eina_file_close_on_exec(sock, EINA_TRUE))229{230CRI("cannot set close on exec socket for '%s' (fd=%d): %s",231buf, sock, strerror(errno));232exit(-1);233}234lin.l_onoff = 1;235lin.l_linger = 0;236if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)237{238CRI("cannot set linger for socket for '%s' (fd=%d): %s",239buf, sock, strerror(errno));240exit(-1);241}242socket_unix.sun_family = AF_UNIX;243len = strlen(buf);244if (len > sizeof(socket_unix.sun_path))245{246CRI("socket path '%s' is too long for buffer", buf);247exit(-1);248}249memcpy(socket_unix.sun_path, buf, len);250if (len < sizeof(socket_unix.sun_path)) socket_unix.sun_path[len] = 0;251socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);252if (bind(sock, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)253{254CRI("cannot bind socket for '%s' (fd=%d): %s",255buf, sock, strerror(errno));256exit(-1);257}258if (listen(sock, 4096) < 0)259{260CRI("listen(sock=%d, 4096): %s", sock, strerror(errno));261exit(-1);262}263elm_quicklaunch_mode_set(EINA_TRUE);264elm_quicklaunch_init(argc, argv);265restart_time = ecore_time_get();266
267memset(&action, 0, sizeof(struct sigaction));268action.sa_handler = SIG_DFL;269action.sa_sigaction = NULL;270action.sa_flags = SA_RESTART | SA_SIGINFO;271sigemptyset(&action.sa_mask);272sigaction(SIGINT, &action, &old_sigint);273
274action.sa_handler = SIG_DFL;275action.sa_sigaction = NULL;276action.sa_flags = SA_RESTART | SA_SIGINFO;277sigemptyset(&action.sa_mask);278sigaction(SIGTERM, &action, &old_sigterm);279
280action.sa_handler = SIG_DFL;281action.sa_sigaction = NULL;282action.sa_flags = SA_RESTART | SA_SIGINFO;283sigemptyset(&action.sa_mask);284sigaction(SIGQUIT, &action, &old_sigquit);285
286action.sa_handler = SIG_DFL;287action.sa_sigaction = NULL;288action.sa_flags = SA_RESTART | SA_SIGINFO;289sigemptyset(&action.sa_mask);290sigaction(SIGALRM, &action, &old_sigalrm);291
292action.sa_handler = SIG_DFL;293action.sa_sigaction = NULL;294action.sa_flags = SA_RESTART | SA_SIGINFO;295sigemptyset(&action.sa_mask);296sigaction(SIGUSR1, &action, &old_sigusr1);297
298action.sa_handler = SIG_DFL;299action.sa_sigaction = NULL;300action.sa_flags = SA_RESTART | SA_SIGINFO;301sigemptyset(&action.sa_mask);302sigaction(SIGUSR2, &action, &old_sigusr2);303
304action.sa_handler = SIG_DFL;305action.sa_sigaction = NULL;306action.sa_flags = SA_RESTART | SA_SIGINFO;307sigemptyset(&action.sa_mask);308sigaction(SIGHUP, &action, &old_sighup);309
310action.sa_handler = NULL;311action.sa_sigaction = child_handler;312action.sa_flags = SA_RESTART | SA_SIGINFO;313sigemptyset(&action.sa_mask);314sigaction(SIGCHLD, &action, &old_sigchld);315
316action.sa_handler = NULL;317action.sa_sigaction = crash_handler;318action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;319sigemptyset(&action.sa_mask);320sigaction(SIGSEGV, &action, &old_sigsegv);321
322action.sa_handler = NULL;323action.sa_sigaction = crash_handler;324action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;325sigemptyset(&action.sa_mask);326sigaction(SIGILL, &action, &old_sigill);327
328action.sa_handler = NULL;329action.sa_sigaction = crash_handler;330action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;331sigemptyset(&action.sa_mask);332sigaction(SIGFPE, &action, &old_sigfpe);333
334action.sa_handler = NULL;335action.sa_sigaction = crash_handler;336action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;337sigemptyset(&action.sa_mask);338sigaction(SIGBUS, &action, &old_sigbus);339
340action.sa_handler = NULL;341action.sa_sigaction = crash_handler;342action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;343sigemptyset(&action.sa_mask);344sigaction(SIGABRT, &action, &old_sigabrt);345
346for (;;)347{348int fd;349struct sockaddr_un client;350socklen_t slen;351
352slen = sizeof(struct sockaddr_un);353fd = accept(sock, (struct sockaddr *)&client, &slen);354
355DBG("Accepting connection.");356elm_quicklaunch_sub_init(argc, argv);357// don't seed since we are doing this AFTER launch request358// elm_quicklaunch_seed();359if (fd >= 0)360{361unsigned long bytes;362int num;363
364num = read(fd, &bytes, sizeof(unsigned long));365if (num == sizeof(unsigned long))366handle_run(fd, bytes);367}368while (elm_quicklaunch_sub_shutdown() > 0);369}370elm_quicklaunch_shutdown();371
372if ((_log_dom > -1) && (_log_dom != EINA_LOG_DOMAIN_GLOBAL))373{374eina_log_domain_unregister(_log_dom);375_log_dom = -1;376}377eina_shutdown();378
379return 0;380}
381