e system - add new uber setuid tool to replace all the previous ones

so e has had a bit of a mess of setuid root tools to do things that
are essential to maintaing a functioning desktop/laptop/tablet/phone
like device like shutting it down or suspending or sqizzling the cpu
governor or messing with the backlight or... you get the idea.

this has been spread around enlightenment_sys and other special
purpose tools. this now unifies it into a single "always there"
enlightenment_system backend setuid root slave process whose job it is
to do all these things via a stdio protocol in an organized way. this
means latency to do something is lower, but at the expense of
consuming ram and a lurking process. unfortunately the lurking will be
needed soon when i add ddc support to make it even vaguely efficient,
so it's a cost i guess we have to pay now. we'll need this in future
as well for some stats collection and more.

still need to port existing code to use this instead of the existing stuff,
and then remove of the old stuff.
This commit is contained in:
Carsten Haitzler 2020-01-12 21:38:54 +00:00
parent dda50e8d87
commit f57572b678
19 changed files with 2673 additions and 0 deletions

View File

@ -86,3 +86,6 @@ if get_option('install-enlightenment-menu')
) )
endif endif
install_data('system.conf',
install_dir: join_paths(dir_sysconf, 'enlightenment')
)

67
data/etc/system.conf Normal file
View File

@ -0,0 +1,67 @@
# Enlightenment System access control file
#
# This should be installed as /etc/enlightenment/system.conf if you wish to
# limit access to enlightenment_system setuid tool. The tool will load this
# file, if it exists, and abort any kind of execution if the file would not
# permit the calling user to use it. If this file does not exist, then any
# user or group will be permitted to run this tool and access its features.
# This file will be installed
# This file is read in order from top to bottom - the first rule to MATCH
# will be used for a user or a group, and nothing after that is read.
# Any user or group NOT matched by an allow or a deny will be ALLOWED to
# perform the action by default (system administrators should be aware of
# this and implement whatever policies they see fit). Generally speaking
# a user of a workstation, desktop or laptop is intended to have such abilities
# to perform these actions, thus the default of allow. For multi-user systems
# the system administrator is considered capable enough to restrict what they
# see they need to.
# A WARNING to admins: do NOT allow access for users to this system remotely
# UNLESS you fully trust them or you have locked down permissions to halt/reboot
# suspend etc. here first. You have been warned.
# FORMAT:
#
# user: username allow: halt reboot suspend hibernate
# group: groupname deny: *
# group: * deny: *
# user: * allow: suspend
# user: billy allow: halt reboot
# group: staff deny: halt suspend hibernate
# ... etc. ...
#
# user and group name can use glob matches (* == all for example) like the
# shell. as can action names allowed or denied.
# root is allowed to do anything - but it needs to be here explicitly anyway
user: root allow: *
# members of operator, staff and admin groups should be able to do all
group: operator allow: *
group: staff allow: *
group: admin allow: *
group: sys allow: *
group: wheel allow: *
group: adm allow: *
# common "user" groups for "console users" on desktops/laptops
group: dialout allow: *
group: disk allow: *
group: adm allow: *
group: cdrom allow: *
group: floppy allow: *
group: audio allow: *
group: dip allow: *
group: plugdev allow: *
group: netdev allow: *
group: bluetooth allow: *
group: video allow: *
group: voice allow: *
group: fax allow: *
group: tty allow: *
group: colord allow: *
group: input allow: *
group: sudo allow: *
# deny everyone else by default
user: * deny: *

View File

@ -147,6 +147,13 @@ config_h.set_quoted('PACKAGE_NAME' , proj)
config_h.set_quoted('BINDIR' , dir_bin) config_h.set_quoted('BINDIR' , dir_bin)
config_h.set_quoted('DATADIR' , dir_data) config_h.set_quoted('DATADIR' , dir_data)
if cc.has_header('sys/prctl.h') == true
config_h.set('HAVE_PRCTL' , '1')
endif
if cc.has_header('sys/procctl.h') == true
config_h.set('HAVE_PROCCTL' , '1')
endif
if cc.has_function('setenv') == true if cc.has_function('setenv') == true
config_h.set('HAVE_SETENV' , '1') config_h.set('HAVE_SETENV' , '1')
endif endif

View File

@ -109,6 +109,7 @@
#include "e_widget_color_well.h" #include "e_widget_color_well.h"
#include "e_color_dialog.h" #include "e_color_dialog.h"
#include "e_sys.h" #include "e_sys.h"
#include "e_system.h"
#include "e_obj_dialog.h" #include "e_obj_dialog.h"
#include "e_filereg.h" #include "e_filereg.h"
#include "e_widget_aspect.h" #include "e_widget_aspect.h"

View File

@ -790,6 +790,15 @@ main(int argc, char **argv)
e_desk_init(); e_desk_init();
e_exehist_init(); e_exehist_init();
TS("E_System Init");
if (!e_system_init())
{
e_error_message_show(_("Enlightenment cannot initialize the Privelege System access system.\n"));
_e_main_shutdown(-1);
}
TS("E_System Init Done");
_e_main_shutdown_push(e_system_shutdown);
TS("E_Powersave Init"); TS("E_Powersave Init");
if (!e_powersave_init()) if (!e_powersave_init())
{ {

320
src/bin/e_system.c Normal file
View File

@ -0,0 +1,320 @@
#include "e.h"
typedef struct
{
char cmd[24];
int size;
} Message_Head;
typedef struct
{
void (*func) (void *data, const char *params);
void *data;
Eina_Bool delete_me : 1;
} Handler;
static Ecore_Exe *_system_exe = NULL;
static Ecore_Event_Handler *_handler_del = NULL;
static Ecore_Event_Handler *_handler_data = NULL;
static Eina_Binbuf *_msg_buf = NULL;
static Eina_Hash *_handlers = NULL;
static int _handlers_busy = 0;
static Ecore_Timer *_error_dialog_timer = NULL;
static double _last_spawn = 0.0;
static int _respawn_count = 0;
static Eina_Bool
_cb_dialog_timer(void *data EINA_UNUSED)
{
_error_dialog_timer = NULL;
e_util_dialog_show(_("Error in Enlightenment System Service"),
_("Enlightenment cannot successfully start<br>"
"the enlightenment_system service."));
return EINA_FALSE;
}
static void
_system_spawn_error(void)
{
if (_error_dialog_timer) ecore_timer_del(_error_dialog_timer);
_error_dialog_timer = ecore_timer_add(5.0, _cb_dialog_timer, NULL);
}
static void
_system_spawn(void)
{
char buf[PATH_MAX];
double t = ecore_time_get();
if ((t - _last_spawn) < 10.0) _respawn_count++;
else _respawn_count = 0;
if (_respawn_count > 5) return;
snprintf(buf, sizeof(buf),
"%s/enlightenment/utils/enlightenment_system", e_prefix_lib_get());
_system_exe = ecore_exe_pipe_run
(buf, ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, NULL);
if (!_system_exe) _system_spawn_error();
}
static Eina_Bool
_system_message_read(void)
{
Message_Head *head;
const char *data = (const char *)eina_binbuf_string_get(_msg_buf);
size_t len = eina_binbuf_length_get(_msg_buf);
Eina_Binbuf *buf2;
if (!data) return EINA_FALSE;
if (len < sizeof(Message_Head)) return EINA_FALSE;
head = (Message_Head *)data;
if (len < (sizeof(Message_Head) + head->size)) return EINA_FALSE;
if (_handlers)
{
Eina_List *list, *l, *ll, *plist;
Handler *h;
int del_count = 0;
_handlers_busy++;
list = plist = eina_hash_find(_handlers, head->cmd);
EINA_LIST_FOREACH(list, l, h)
{
if (!h->delete_me)
{
if (head->size == 0) h->func(h->data, NULL);
else
{
if ((data + sizeof(Message_Head))[head->size - 1] == 0)
h->func(h->data,
(const char *)(data + sizeof(Message_Head)));
}
}
}
_handlers_busy--;
if (_handlers_busy == 0)
{
EINA_LIST_FOREACH_SAFE(list, l, ll, h)
{
if (h->delete_me)
{
list = eina_list_remove_list(list, l);
del_count++;
free(h);
}
}
}
if (del_count > 0)
{
eina_hash_del(_handlers, head->cmd, plist);
eina_hash_add(_handlers, head->cmd, list);
}
}
buf2 = eina_binbuf_new();
if (buf2)
{
eina_binbuf_append_length
(buf2,
(const unsigned char *)data + sizeof(Message_Head) + head->size,
len - (sizeof(Message_Head) + head->size));
eina_binbuf_free(_msg_buf);
_msg_buf = buf2;
}
return EINA_TRUE;
}
static Eina_Bool
_cb_exe_del(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Del *ev = event;
if (ev->exe != _system_exe) return ECORE_CALLBACK_PASS_ON;
if ((ev->exit_code == 3) || (ev->exit_code == 5) ||
(ev->exit_code == 7) || (ev->exit_code == 9) ||
(ev->exit_code == 11))
{
// didn't run because it literally refused....
_system_spawn_error();
}
else
{
// it died for some other reason - restart it - maybe crashed?
if (_msg_buf) eina_binbuf_free(_msg_buf);
_msg_buf = eina_binbuf_new();
_system_spawn();
}
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
_cb_exe_data(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Data *ev = event;
if (ev->exe != _system_exe) return ECORE_CALLBACK_PASS_ON;
// this is dumb, but it will work as this is avery low bandwidth
// i/o channel to/from the child exe stdin/out
if (_msg_buf)
{
eina_binbuf_append_length(_msg_buf, ev->data, ev->size);
while (_msg_buf && _system_message_read());
}
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
_handler_list_free(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
{
Eina_List *list = data;
Handler *h;
EINA_LIST_FREE(list, h) free(h);
return EINA_TRUE;
}
/* externally accessible functions */
EINTERN int
e_system_init(void)
{
// XXX:
//
// if exe_data - parse/get data
// ... per message - call registered cb's for that msg
_handler_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _cb_exe_del, NULL);
_handler_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _cb_exe_data, NULL);
_msg_buf = eina_binbuf_new();
_handlers = eina_hash_string_superfast_new(NULL);
_system_spawn();
return 1;
}
EINTERN int
e_system_shutdown(void)
{
if (_msg_buf) eina_binbuf_free(_msg_buf);
if (_handler_del) ecore_event_handler_del(_handler_del);
if (_handler_data) ecore_event_handler_del(_handler_data);
if (_system_exe)
{
ecore_exe_interrupt(_system_exe);
ecore_exe_quit(_system_exe);
ecore_exe_terminate(_system_exe);
ecore_exe_kill(_system_exe);
ecore_exe_free(_system_exe);
}
if (_handlers)
{
eina_hash_foreach(_handlers, _handler_list_free, NULL);
eina_hash_free(_handlers);
}
if (_error_dialog_timer) ecore_timer_del(_error_dialog_timer);
_msg_buf = NULL;
_handler_del = NULL;
_handler_data = NULL;
_system_exe = NULL;
_handlers = NULL;
_error_dialog_timer = NULL;
return 1;
}
E_API void
e_system_send(const char *cmd, const char *fmt, ...)
{
char *buf = NULL, stack_buf[4096];
Message_Head head;
size_t len = strlen(cmd);
int printed = 0;
va_list ap;
if (!_system_exe)
{
ERR("Trying to send system command to non-existent process");
return;
}
if (len > 23)
{
ERR("Trying to send command of length %i (max 23)", (int)len);
return;
}
if (fmt)
{
buf = stack_buf;
va_start(ap, fmt);
printed = vsnprintf(stack_buf, sizeof(stack_buf), fmt, ap);
va_end(ap);
if ((size_t)printed >= (sizeof(stack_buf) - 1))
{
buf = malloc(printed + 1);
if (!buf) goto end;
va_start(ap, fmt);
printed = vsnprintf(buf, printed + 1, fmt, ap);
va_end(ap);
}
}
memset(head.cmd, 0, sizeof(head.cmd));
memcpy(head.cmd, cmd, len);
if (printed > 0) head.size = printed + 1;
else head.size = 0;
ecore_exe_send(_system_exe, &head, sizeof(head));
if ((buf) && (head.size > 0))
{
ecore_exe_send(_system_exe, buf, head.size);
}
end:
if (buf != stack_buf) free(buf);
}
E_API void
e_system_handler_add(const char *cmd, void (*func) (void *data, const char *params), void *data)
{
Eina_List *list;
Handler *h;
if (!_handlers)
{
ERR("Trying to add system handler to NULL handler hash");
return;
}
h = calloc(1, sizeof(Handler));
if (!h) return;
h->func = func;
h->data = data;
list = eina_hash_find(_handlers, cmd);
eina_hash_del(_handlers, cmd, list);
list = eina_list_append(list, h);
eina_hash_add(_handlers, cmd, list);
}
E_API void
e_system_handler_del(const char *cmd, void (*func) (void *data, const char *params), void *data)
{
Eina_List *list, *l;
Handler *h;
if (!_handlers)
{
ERR("Trying to del system handler to NULL handler hash");
return;
}
list = eina_hash_find(_handlers, cmd);
if (list)
{
eina_hash_del(_handlers, cmd, list);
EINA_LIST_FOREACH(list, l, h)
{
if ((h->func == func) && (h->data == data))
{
if (_handlers_busy > 0)
h->delete_me = EINA_TRUE;
else
{
list = eina_list_remove_list(list, l);
free(h);
}
break;
}
}
eina_hash_add(_handlers, cmd, list);
}
}

15
src/bin/e_system.h Normal file
View File

@ -0,0 +1,15 @@
#ifdef E_TYPEDEFS
#else
#ifndef E_SYSTEM_H
#define E_SYSTEM_H
EINTERN int e_system_init(void);
EINTERN int e_system_shutdown(void);
E_API void e_system_send(const char *cmd, const char *fmt, ...);
E_API void e_system_handler_add(const char *cmd, void (*func) (void *data, const char *params), void *data);
E_API void e_system_handler_del(const char *cmd, void (*func) (void *data, const char *params), void *data);
#endif
#endif

View File

@ -177,6 +177,7 @@ src = [
'e_spectrum.c', 'e_spectrum.c',
'e_startup.c', 'e_startup.c',
'e_sys.c', 'e_sys.c',
'e_system.c',
'e_test.c', 'e_test.c',
'e_theme_about.c', 'e_theme_about.c',
'e_theme.c', 'e_theme.c',
@ -355,6 +356,7 @@ hdr = [
'e_spectrum.h', 'e_spectrum.h',
'e_startup.h', 'e_startup.h',
'e_sys.h', 'e_sys.h',
'e_system.h',
'e_test.h', 'e_test.h',
'e_theme_about.h', 'e_theme_about.h',
'e_theme.h', 'e_theme.h',
@ -582,3 +584,4 @@ if config_h.has('HAVE_WAYLAND') == true
install: true) install: true)
endif endif
subdir('e_fm') subdir('e_fm')
subdir('system')

121
src/bin/system/e_system.h Normal file
View File

@ -0,0 +1,121 @@
#ifndef E_SYSTEM_H
# define E_SYSTEM_H 1
# include "config.h"
# ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
# endif
# ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
# else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
# endif
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# elif !defined alloca
# ifdef __GNUC__
# define alloca __builtin_alloca
# elif defined _AIX
# define alloca __alloca
# elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
# elif !defined HAVE_ALLOCA
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
# endif
# endif
# ifdef __linux__
# include <features.h>
# endif
# ifdef HAVE_ENVIRON
# define _GNU_SOURCE 1
# endif
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <sys/param.h>
# include <sys/resource.h>
# include <utime.h>
# include <dlfcn.h>
# include <math.h>
# include <fcntl.h>
# include <fnmatch.h>
# include <limits.h>
# include <ctype.h>
# include <time.h>
# include <dirent.h>
# include <pwd.h>
# include <grp.h>
# include <glob.h>
# include <locale.h>
# include <errno.h>
# include <signal.h>
# include <inttypes.h>
# include <assert.h>
# include <fcntl.h>
#if defined (__FreeBSD__) || defined (__OpenBSD__)
# include <sys/sysctl.h>
#endif
#ifdef HAVE_PRCTL
# include <sys/prctl.h>
#elif defined(HAVE_PROCCTL)
# include <sys/procctl.h>
#endif
# ifndef _POSIX_HOST_NAME_MAX
# define _POSIX_HOST_NAME_MAX 255
# endif
# include <Eina.h>
# include <Ecore.h>
# include <Ecore_File.h>
# include <Eet.h>
# ifdef HAVE_EEZE
# include <Eeze.h>
# endif
#define ERR(args...) do { fprintf(stderr, "E_SYSTEM_ERR: "); fprintf(stderr, ##args); } while (0)
extern uid_t uid;
extern gid_t gid;
void e_system_inout_init(void);
void e_system_inout_shutdown(void);
void e_system_inout_command_register(const char *cmd, void (*func) (void *data, const char *aprams), void *data);
void e_system_inout_command_send(const char *cmd, const char *fmt, ...);
void e_system_backlight_init(void);
void e_system_backlight_shutdown(void);
void e_system_storage_init(void);
void e_system_storage_shutdown(void);
void e_system_power_init(void);
void e_system_power_shutdown(void);
void e_system_rfkill_init(void);
void e_system_rfkill_shutdown(void);
void e_system_l2ping_init(void);
void e_system_l2ping_shutdown(void);
void e_system_cpufreq_init(void);
void e_system_cpufreq_shutdown(void);
#endif

View File

@ -0,0 +1,321 @@
#include "e_system.h"
typedef struct
{
char *dev;
int val, max, val_set, val_get_count;
Eina_Bool prefer : 1;
Eina_Bool set : 1;
} Light;
static Eina_Lock _devices_lock;
static Eina_List *_devices = NULL;
static Eina_Semaphore _worker_sem;
static void
_light_set(Light *lig, int val)
{ // val == 0->1000
int nval = ((lig->max * val) + 500) / 1000;
if (nval < 0) nval = 0;
else if (nval > lig->max) nval = lig->max;
lig->val = nval;
#ifdef HAVE_EEZE
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/brightness", lig->dev);
int fd = open(buf, O_WRONLY);
if (fd >= 0)
{
char buf2[32];
snprintf(buf2, sizeof(buf2), "%i", lig->val);
if (write(fd, buf2, strlen(buf2)) <= 0)
ERR("Write failed of [%s] to [%s]\n", buf2, buf);
close(fd);
}
#elif defined(__FreeBSD_kernel__)
sysctlbyname(lig->dev, NULL, NULL, &(lig->val), sizeof(lig->val));
#endif
}
static void
_light_get(Light *lig)
{
#ifdef HAVE_EEZE
const char *s;
s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness");
if (s)
{
lig->val = atoi(s);
eina_stringshare_del(s);
}
#elif defined(__FreeBSD_kernel__)
int plen = sizeof(lig->val);
sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0);
#endif
}
static void
_cb_worker(void *data EINA_UNUSED, Ecore_Thread *th)
{
for (;;)
{
Eina_List *l;
Light *lig;
eina_semaphore_lock(&_worker_sem);
eina_lock_take(&_devices_lock);
EINA_LIST_FOREACH(_devices, l, lig)
{
if (lig->val_get_count > 0)
{
_light_get(lig);
while (lig->val_get_count > 0)
{
Light *lig2 = calloc(1, sizeof(Light));
lig->val_get_count--;
if (lig2)
{
lig2->dev = strdup(lig->dev);
lig2->max = lig->max;
if (lig2->dev)
{
lig2->val = lig->val;
ecore_thread_feedback(th, lig2);
}
else free(lig2);
}
}
}
if (lig->set)
{
lig->set = EINA_FALSE;
lig->val = lig->val_set;
_light_set(lig, lig->val);
}
}
eina_lock_release(&_devices_lock);
}
}
static void
_cb_worker_message(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED, void *msg_data)
{
Light *lig = msg_data;
int val = 0;
if (lig->max > 0)
{
val = ((1000 * lig->val) + 500) / lig->max;
if (val < 0) val = 0;
else if (val > 1000) val = 1000;
}
e_system_inout_command_send("bklight-val", "%s %i", lig->dev, val);
free(lig->dev);
free(lig);
}
static void
_cb_worker_end(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
}
static void
_cb_worker_cancel(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
}
static void
_light_add(const char *dev)
{
Light *lig = calloc(1, sizeof(Light));
if (!lig) abort();
lig->dev = strdup(dev);
if (!lig->dev) abort();
lig->val = -1; // uknown
#ifdef HAVE_EEZE
const char *s;
s = eeze_udev_syspath_get_sysattr(lig->dev, "brightness");
if (!s)
{
free(lig->dev);
free(lig);
return;
}
lig->val = atoi(s);
eina_stringshare_del(s);
s = eeze_udev_syspath_get_sysattr(lig->dev, "max_brightness");
if (s)
{
lig->max = atoi(s);
eina_stringshare_del(s);
}
if (lig->max <= 0) lig->max = 255;
lig->prefer = eeze_udev_syspath_check_sysattr(lig->dev, "type", "firmware");
#elif defined(__FreeBSD_kernel__)
int plen = sizeof(lig->val);
sysctlbyname(lig->dev, &(lig->val), &plen, NULL, 0);
lig->max = 100;
#endif
_devices = eina_list_append(_devices, lig);
}
#ifdef HAVE_EEZE
static Eina_Bool
_light_device_include(const char *dev)
{ // filter out known undesireable devices
if (strstr(dev, "::capslock")) return EINA_FALSE;
if (strstr(dev, "::numlock")) return EINA_FALSE;
if (strstr(dev, "::scrolllock")) return EINA_FALSE;
if (strstr(dev, "::compose")) return EINA_FALSE;
if (strstr(dev, "::kana")) return EINA_FALSE;
return EINA_TRUE;
}
#endif
static void
_light_refresh_devices(void)
{
Light *lig;
EINA_LIST_FREE(_devices, lig)
{
free(lig->dev);
free(lig);
}
#ifdef HAVE_EEZE
Eina_List *devs;
const char *s;
devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
EINA_LIST_FREE(devs, s)
{
if (_light_device_include(s)) _light_add(s);
eina_stringshare_del(s);
}
devs = eeze_udev_find_by_filter("leds", NULL, NULL);
EINA_LIST_FREE(devs, s)
{
if (_light_device_include(s)) _light_add(s);
eina_stringshare_del(s);
}
#elif defined(__FreeBSD_kernel__)
// XXX; shouldn't we scan for devices?
_light_add("hw.acpi.video.lcd0.brightness");
#endif
}
static Light *
_light_find(const char *dev)
{
Eina_List *l;
Light *lig;
if (!dev) return NULL;
EINA_LIST_FOREACH(_devices, l, lig)
{
if (!strcmp(lig->dev, dev)) return lig;
}
return NULL;
}
static void
_cb_bklight_list(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{ // reply = "dev1 -|p dev2 -|p ..."
Eina_List *l;
Light *lig;
char *rep = NULL, *p = NULL;
size_t repsize = 0;
eina_lock_take(&_devices_lock);
EINA_LIST_FOREACH(_devices, l, lig)
{
repsize += strlen(lig->dev) + 2 + 1;
}
if (repsize > 0)
{
rep = malloc(repsize);
if (!rep) abort();
p = rep;
EINA_LIST_FOREACH(_devices, l, lig)
{
size_t len = strlen(lig->dev);
memcpy(p, lig->dev, len + 1);
p[len] = ' '; len++;
if (lig->prefer) p[len] = 'p';
else p[len] = '-';
len++;
if (l->next) p[len] = ' ';
else p[len] = '\0';
p += len + 1;
}
}
eina_lock_release(&_devices_lock);
e_system_inout_command_send("bklight-list", "%s", rep);
free(rep);
}
static void
_cb_bklight_refresh(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
eina_lock_take(&_devices_lock);
_light_refresh_devices();
eina_lock_release(&_devices_lock);
}
static void
_cb_bklight_get(void *data EINA_UNUSED, const char *params)
{
Light *lig;
eina_lock_take(&_devices_lock);
lig = _light_find(params);
if (!lig) goto done;
lig->val_get_count++;
eina_semaphore_release(&_worker_sem, 1);
_light_get(lig);
done:
eina_lock_release(&_devices_lock);
}
static void
_cb_bklight_set(void *data EINA_UNUSED, const char *params)
{
Light *lig;
char dev[1024] = "";
int val = 0;
if (!params) return;
if (sscanf(params, "%1023s %i", dev, &val) != 2) return;
eina_lock_take(&_devices_lock);
lig = _light_find(dev);
if (!lig) goto done;
lig->val_set = val;
lig->set = EINA_TRUE;
eina_semaphore_release(&_worker_sem, 1);
done:
eina_lock_release(&_devices_lock);
}
void
e_system_backlight_init(void)
{
_light_refresh_devices();
eina_lock_new(&_devices_lock);
eina_semaphore_new(&_worker_sem, 0);
ecore_thread_feedback_run(_cb_worker, _cb_worker_message,
_cb_worker_end, _cb_worker_cancel,
NULL, EINA_TRUE);
e_system_inout_command_register("bklight-list", _cb_bklight_list, NULL);
e_system_inout_command_register("bklight-refresh", _cb_bklight_refresh, NULL);
e_system_inout_command_register("bklight-get", _cb_bklight_get, NULL);
e_system_inout_command_register("bklight-set", _cb_bklight_set, NULL);
}
void
e_system_backlight_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,163 @@
#include "e_system.h"
#if defined __OpenBSD__
// no local funcs
#elif defined __FreeBSD__
// no local funcs
#else
static int
sys_cpu_setall(const char *control, const char *value)
{
int num = 0;
char buf[4096];
FILE *f;
for (;;)
{
snprintf(buf, sizeof(buf),
"/sys/devices/system/cpu/cpu%i/cpufreq/%s", num, control);
f = fopen(buf, "w");
if (!f) return num;
fprintf(f, "%s", value);
fclose(f);
num++;
}
return 0;
}
static int
sys_cpufreq_set(const char *control, const char *value)
{
char buf[4096];
FILE *f;
snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpufreq/%s", control);
f = fopen(buf, "w");
if (!f)
{
if (sys_cpu_setall(control, value) > 0) return 1;
else return 0;
}
fprintf(f, "%s", value);
fclose(f);
return 1;
}
static int
sys_cpu_pstate(int min, int max, int turbo)
{
FILE *f;
f = fopen("/sys/devices/system/cpu/intel_pstate/min_perf_pct", "w");
if (!f) return 0;
fprintf(f, "%i", min);
fclose(f);
f = fopen("/sys/devices/system/cpu/intel_pstate/max_perf_pct", "w");
if (!f) return 0;
fprintf(f, "%i", max);
fclose(f);
f = fopen("/sys/devices/system/cpu/intel_pstate/no_turbo", "w");
if (!f) return 0;
fprintf(f, "%i", turbo ? 0 : 1);
fclose(f);
return 1;
}
#endif
static void
_cb_cpufreq_freq(void *data EINA_UNUSED, const char *params)
{
// FREQ
int f = atoi(params);
if (f > 0)
{
#if defined __OpenBSD__
int mib[] = {CTL_HW, HW_SETPERF};
size_t len = sizeof(f);
if (sysctl(mib, 2, NULL, 0, &f, len) == 0)
{
e_system_inout_command_send("cpufreq-freq", "ok");
return;
}
#elif defined __FreeBSD__
if (sysctlbyname("dev.cpu.0.freq", NULL, NULL, &f, sizeof(f)) == 0)
{
e_system_inout_command_send("cpufreq-freq", "ok");
return;
}
#else
if (sys_cpu_setall("scaling_setspeed", params) > 0)
{
e_system_inout_command_send("cpufreq-freq", "ok");
return;
}
#endif
}
e_system_inout_command_send("cpufreq-freq", "err");
}
static void
_cb_cpufreq_governor(void *data EINA_UNUSED, const char *params)
{
// NAME
#if defined __OpenBSD__
e_system_inout_command_send("cpufreq-governor", "err");
#elif defined __FreeBSD__
e_system_inout_command_send("cpufreq-governor", "err");
#else
if (sys_cpu_setall("scaling_governor", params) <= 0)
{
ERR("Unable to open governor interface for writing\n");
e_system_inout_command_send("cpufreq-governor", "err");
}
if (!strcmp(params, "ondemand"))
sys_cpufreq_set("ondemand/ignore_nice_load", "0");
else if (!strcmp(params, "conservative"))
sys_cpufreq_set("conservative/ignore_nice_load", "0");
e_system_inout_command_send("cpufreq-governor", "ok");
#endif
}
static void
_cb_cpufreq_pstate(void *data EINA_UNUSED, const char *params)
{
// MIN_PERC MAX_PERC TURBO
#if defined __OpenBSD__
e_system_inout_command_send("cpufreq-pstate", "err");
#elif defined __FreeBSD__
e_system_inout_command_send("cpufreq-pstate", "err");
#else
int min = 0, max = 100, turbo = 1;
if (sscanf(params, "%i %i %i", &min, &max, &turbo) == 3)
{
if (min < 0) min = 0;
else if (min > 100) min = 100;
if (max < 0) max = 0;
else if (max > 100) max = 100;
if (turbo < 0) turbo = 0;
else if (turbo > 1) turbo = 1;
if (sys_cpu_pstate(min, max, turbo) > 0)
e_system_inout_command_send("cpufreq-pstate", "ok");
}
e_system_inout_command_send("cpufreq-pstate", "err");
#endif
}
void
e_system_cpufreq_init(void)
{
e_system_inout_command_register("cpufreq-freq", _cb_cpufreq_freq, NULL);
e_system_inout_command_register("cpufreq-governor", _cb_cpufreq_governor, NULL);
e_system_inout_command_register("cpufreq-pstate", _cb_cpufreq_pstate, NULL);
}
void
e_system_cpufreq_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,171 @@
#include "e_system.h"
typedef struct
{
void (*func) (void *data, const char *params);
void *data;
} Handler;
static Eina_Hash *_cmd_handlers = NULL;
static Ecore_Fd_Handler *_fdh_in = NULL;
//// note: commands are of the form:
// [ 24 bytes] command string including nul byte terminator and 0 padding
// [ 4 bytes] payload size (max size 2gb)
// [ N bytes] payload data (0 or more)...
typedef struct
{
char cmd[24];
int size;
} Message_Head;
static Eina_Bool
_cb_stdio_in_read(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
{
Handler *h;
Message_Head head;
ssize_t ret;
errno = 0;
ret = read(0, &head, sizeof(head));
if (ret < 1)
{
int e = errno;
if ((e == EIO) || (e == EBADF) || (e == EPIPE) ||
(e == EINVAL) || (e == ENOSPC) ||
(!((e == EAGAIN) || (e == EINTR))))
{
ecore_main_loop_quit();
goto done;
}
goto done;
}
else
{
char *buf;
if (head.size < 0)
{
ERR("Invalid message payload size (less than 0)\n");
abort();
}
buf = NULL;
if (head.size > 0)
{
buf = malloc(head.size);
if (!buf)
{
ERR("Out of memory for message of size %i bytes\n", head.size);
abort();
}
ret = read(0, buf, head.size);
if (ret != head.size)
{
ERR("Cannot read full message payload of %i bytes\n", head.size);
abort();
}
}
h = eina_hash_find(_cmd_handlers, head.cmd);
if (h)
{
if ((!buf) || ((buf) && (buf[head.size - 1] == '\0')))
h->func(h->data, buf);
}
free(buf);
}
done:
return EINA_TRUE;
}
void
e_system_inout_init(void)
{
_cmd_handlers = eina_hash_string_superfast_new(free);
_fdh_in = ecore_main_fd_handler_add(0, ECORE_FD_READ,
_cb_stdio_in_read, NULL,
NULL, NULL);
}
void
e_system_inout_shutdown(void)
{
ecore_main_fd_handler_del(_fdh_in);
_fdh_in = NULL;
eina_hash_free(_cmd_handlers);
_cmd_handlers = NULL;
}
void
e_system_inout_command_register(const char *cmd, void (*func) (void *data, const char *params), void *data)
{
Handler *h = malloc(sizeof(Handler));
size_t len = strlen(cmd);
if (!h)
{
ERR("Out of memory registering command handlers\n");
abort();
}
if (len > 23)
{
ERR("Trying to register command of length %i (max 23)\n", (int)len);
abort();
}
h->func = func;
h->data = data;
eina_hash_add(_cmd_handlers, cmd, h);
}
void
e_system_inout_command_send(const char *cmd, const char *fmt, ...)
{
char *buf = NULL, stack_buf[4096];
Message_Head head;
size_t len = strlen(cmd);
int printed = 0;
ssize_t ret;
va_list ap;
if (len > 23)
{
ERR("Trying to send command of length %i (max 23)\n", (int)len);
abort();
}
if (fmt)
{
buf = stack_buf;
va_start(ap, fmt);
printed = vsnprintf(stack_buf, sizeof(stack_buf), fmt, ap);
va_end(ap);
if ((size_t)printed >= (sizeof(stack_buf) - 1))
{
buf = malloc(printed + 1);
if (!buf) goto end;
va_start(ap, fmt);
printed = vsnprintf(buf, printed + 1, fmt, ap);
va_end(ap);
}
}
memset(head.cmd, 0, sizeof(head.cmd));
memcpy(head.cmd, cmd, len);
if (printed > 0) head.size = printed + 1;
else head.size = 0;
ret = write(1, &head, sizeof(head));
if (ret != sizeof(head))
{
ERR("Write of command failed at %lli\n", (long long)ret);
abort();
}
if ((buf) && (head.size > 0))
{
ret = write(1, buf, head.size);
if (ret != (ssize_t)head.size)
{
ERR("Write of command buffer failed at %lli/%llu\n", (long long)ret, (unsigned long long)head.size);
abort();
}
}
end:
if (buf != stack_buf) free(buf);
}

View File

@ -0,0 +1,229 @@
#include "e_system.h"
#ifdef HAVE_BLUETOOTH
# include <bluetooth/bluetooth.h>
# include <bluetooth/l2cap.h>
# include <sys/socket.h>
# include <sys/select.h>
#endif
#define MAX_SZ 500
typedef struct
{
char *dev;
int timeout, result;
} Action;
static void
_l2ping_free(Action *a)
{
free(a->dev);
free(a);
}
#ifdef HAVE_BLUETOOTH
static void
_l2ping_l2addr_init(struct sockaddr_l2 *ad)
{
memset(ad, 0, sizeof(*ad));
ad->l2_family = AF_BLUETOOTH;
}
# define SETUP_FDSET(rfds, wfds, exfds) \
FD_ZERO(&rfds); \
FD_ZERO(&wfds); \
FD_ZERO(&exfds);
# define SETUP_TIMEOUT(tv, a) \
tv.tv_sec = a->timeout / 1000; \
tv.tv_usec = (a->timeout % 1000) * 1000;
#endif
static void
_cb_l2ping(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
#ifdef HAVE_BLUETOOTH
Action *a = data;
char buf1[L2CAP_CMD_HDR_SIZE + MAX_SZ], buf2[L2CAP_CMD_HDR_SIZE + MAX_SZ];
bdaddr_t ba;
l2cap_cmd_hdr *cmd;
struct sockaddr_l2 ad;
double start;
int fd, err, size, i;
fd_set rfds, wfds, exfds;
struct timeval tv;
fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
if (fd < 0)
{
ERR("l2ping: Can't create socket\n");
return;
}
// bind to local address
_l2ping_l2addr_init(&ad);
bacpy(&ba, BDADDR_ANY);
bacpy(&ad.l2_bdaddr, &ba);
if (bind(fd, (struct sockaddr *)&ad, sizeof(ad)) < 0)
{
ERR("l2ping: Can't bind socket\n");
goto err;
}
// connect to remote device
_l2ping_l2addr_init(&ad);
str2ba(a->dev, &ad.l2_bdaddr);
if (connect(fd, (struct sockaddr *)&ad, sizeof(ad)) < 0)
{
ERR("l2ping: Can't connect socket to [%s]\n", a->dev);
goto err;
}
SETUP_FDSET(rfds, wfds, exfds);
FD_SET(fd, &wfds);
SETUP_TIMEOUT(tv, a);
start = ecore_time_get();
err = select(fd + 1, &rfds, &wfds, &exfds, &tv);
if (err == 0)
{
ERR("l2ping: Connect timeout [%s]\n", a->dev);
goto err;
}
// adjust timeout by how long we waited to connect
a->timeout -= (ecore_time_get() - start) * 1000;
if (a->timeout < 1) a->timeout = 1;
size = 44; // use std 44 byte ping size, but no more than MAX_SZ
cmd = (l2cap_cmd_hdr *)buf1;
cmd->ident = 200;
cmd->len = htobs(size);
cmd->code = L2CAP_ECHO_REQ;
// init buffer with some content
// ABCDEF....WXYZABCEF... up to "size" chars
for (i = 0; i < size; i++) buf1[L2CAP_CMD_HDR_SIZE + i] = 'A' + (i % 26);
// get our time just before a send
start = ecore_time_get();
// send the ping
if (send(fd, buf1, L2CAP_CMD_HDR_SIZE + size, 0) <= 0)
{
ERR("l2ping: Send to [%s] failed\n", a->dev);
goto err;
}
// wait for the reply to this ping
for (;;)
{
SETUP_FDSET(rfds, wfds, exfds);
FD_SET(fd, &rfds);
SETUP_TIMEOUT(tv, a);
err = select(fd + 1, &rfds, &wfds, &exfds, &tv);
if (err == 0)
{
ERR("l2ping: Select timeout [%s]\n", a->dev);
goto err;
}
else if (err < 0)
{
ERR("l2ping: Select for [%s] failed\n", a->dev);
goto err;
}
err = recv(fd, buf2, L2CAP_CMD_HDR_SIZE + size, 0);
if (err == 0)
{
ERR("l2ping: Disconnect %s\n", a->dev);
goto err;
}
else if (err < 0)
{
ERR("l2ping: Recv [%s] failed\n", a->dev);
goto err;
}
cmd = (l2cap_cmd_hdr *)buf2;
cmd->len = btohs(cmd->len);
// we only want the 200 ident response packets
if (cmd->ident != 200) continue;
if (cmd->code == L2CAP_COMMAND_REJ)
{
ERR("l2ping: [%s] doesn't do echo\n", a->dev);
goto err;
}
if (cmd->len != size)
{
ERR("l2ping: Size %i echo for [%s] does not match %i\n",
(int)cmd->len, a->dev, (int)size);
goto err;
}
if (memcmp(buf1 + L2CAP_CMD_HDR_SIZE, buf2 + L2CAP_CMD_HDR_SIZE,
size) != 0)
{
ERR("l2ping: Echo response from [%s] does not match sent data\n",
a->dev);
goto err;
}
break;
}
// time it took to send and get our response
a->result = (ecore_time_get() - start) * 1000.0;
err:
close(fd);
#else
ERR("l2ping: Bluetooth support not compiled in\n");
#endif
}
static void
_cb_l2ping_end(void *data, Ecore_Thread *th EINA_UNUSED)
{
Action *a = data;
e_system_inout_command_send("l2ping-ping", "%s %i", a->dev, a->result);
_l2ping_free(a);
}
static void
_cb_l2ping_cancel(void *data, Ecore_Thread *th EINA_UNUSED)
{
Action *a = data;
e_system_inout_command_send("l2ping-ping", "%s %i", a->dev, -1);
_l2ping_free(a);
}
static void
_cb_l2ping_ping(void *data EINA_UNUSED, const char *params)
{
// ADDR TIMEOUT_MS
int timeout = 1;
char dev[1024];
Action *a;
if (sscanf(params, "%s %i", dev, &timeout) != 2) return;
if (timeout < 1) timeout = 1;
else if (timeout > (1000 * 600)) timeout = 1000 * 600;
a = calloc(1, sizeof(Action));
if (!a) return;
a->dev = strdup(dev);
if (!a->dev) goto err;
a->timeout = timeout;
a->result = -1;
if (ecore_thread_feedback_run(_cb_l2ping, NULL,
_cb_l2ping_end, _cb_l2ping_cancel,
a, EINA_TRUE))
return;
err:
_l2ping_free(a);
}
void
e_system_l2ping_init(void)
{
e_system_inout_command_register("l2ping-ping", _cb_l2ping_ping, NULL);
}
void
e_system_l2ping_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,303 @@
#include "e_system.h"
uid_t uid = -1; // uid of person running me
gid_t gid = -1; // gid of person running me
static int
_conf_allow_deny(const char *cmd, const char *glob)
{
if (!strcmp(cmd, "allow:"))
{
if (!strcmp(glob, "*")) return 1; // allow
}
else if (!strcmp(cmd, "deny:"))
{
if (!strcmp(glob, "*")) return -1; // deny
}
return 0; // unknown
}
static void
_etc_enlightenment_system_conf(void)
{
#define MAXGROUPS 1024
int gn, i;
gid_t gl[MAXGROUPS];
char type[32], usergroup[256], cmd[32], glob[256];
Eina_Bool in_usergroup;
FILE *f = fopen("/etc/enlightenment/system.conf", "r");
if (!f) return;
gn = getgroups(MAXGROUPS, gl);
if (gn < 0)
{
ERR("User %i member of too many groups\n", uid);
exit(9);
}
if (fscanf(f, "%31s %255s %31s %255s\n", type, usergroup, cmd, glob) == 4)
{
if (!strcmp(type, "user:"))
{
struct passwd *pw = getpwuid(uid);
in_usergroup = EINA_FALSE;
if (pw)
{
if (!fnmatch(usergroup, pw->pw_name, 0))
in_usergroup = EINA_TRUE;
}
if (in_usergroup)
{
int ok = _conf_allow_deny(cmd, glob);
if (ok == 1) goto allow;
else if (ok == -1) goto deny;
}
}
else if (!strcmp(type, "group:"))
{
struct group *gp;
in_usergroup = EINA_FALSE;
gp = getgrgid(gid);
if (gp)
{
for (i = 0; i < gn; i++)
{
gp = getgrgid(gl[i]);
if (!fnmatch(usergroup, gp->gr_name, 0))
{
in_usergroup = EINA_TRUE;
break;
}
}
}
if (in_usergroup)
{
int ok = _conf_allow_deny(cmd, glob);
if (ok == 1) goto allow;
else if (ok == -1) goto deny;
}
}
}
allow:
fclose(f);
return;
deny:
fclose(f);
ERR("Permission denied to use this tool\n");
exit(11);
}
static void
setuid_setup(void)
{
uid = getuid();
gid = getgid();
if (setuid(0) != 0)
{
ERR("Unable to assume root user privileges\n");
exit(5);
}
if (setgid(0) != 0)
{
ERR("Unable to assume root group privileges\n");
exit(7);
}
// die with parent - special as this is setuid
#ifdef HAVE_PRCTL
prctl(PR_SET_PDEATHSIG, SIGTERM);
#elif defined(HAVE_PROCCTL)
int sig = SIGTERM;
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);
#endif
#ifdef HAVE_UNSETENV
# define NOENV(x) unsetenv(x)
// pass 1 - just nuke known dangerous env vars brutally if possible via
// unsetenv(). if you don't have unsetenv... there's pass 2 and 3
NOENV("IFS");
NOENV("CDPATH");
NOENV("LOCALDOMAIN");
NOENV("RES_OPTIONS");
NOENV("HOSTALIASES");
NOENV("NLSPATH");
NOENV("PATH_LOCALE");
NOENV("COLORTERM");
NOENV("LANG");
NOENV("LANGUAGE");
NOENV("LINGUAS");
NOENV("TERM");
NOENV("LD_PRELOAD");
NOENV("LD_LIBRARY_PATH");
NOENV("SHLIB_PATH");
NOENV("LIBPATH");
NOENV("AUTHSTATE");
NOENV("DYLD_*");
NOENV("KRB_CONF*");
NOENV("KRBCONFDIR");
NOENV("KRBTKFILE");
NOENV("KRB5_CONFIG*");
NOENV("KRB5_KTNAME");
NOENV("VAR_ACE");
NOENV("USR_ACE");
NOENV("DLC_ACE");
NOENV("TERMINFO");
NOENV("TERMINFO_DIRS");
NOENV("TERMPATH");
NOENV("TERMCAP");
NOENV("ENV");
NOENV("BASH_ENV");
NOENV("PS4");
NOENV("GLOBIGNORE");
NOENV("SHELLOPTS");
NOENV("JAVA_TOOL_OPTIONS");
NOENV("PERLIO_DEBUG");
NOENV("PERLLIB");
NOENV("PERL5LIB");
NOENV("PERL5OPT");
NOENV("PERL5DB");
NOENV("FPATH");
NOENV("NULLCMD");
NOENV("READNULLCMD");
NOENV("ZDOTDIR");
NOENV("TMPPREFIX");
NOENV("PYTHONPATH");
NOENV("PYTHONHOME");
NOENV("PYTHONINSPECT");
NOENV("RUBYLIB");
NOENV("RUBYOPT");
# ifdef HAVE_ENVIRON
if (environ)
{
Eina_Bool again;
// go over environment array again and again... safely
do
{
again = EINA_FALSE;
// walk through and find first entry that we don't like */
for (i = 0; environ[i]; i++)
{
// if it begins with any of these, it's possibly nasty */
if ((!strncmp(environ[i], "LD_", 3)) ||
(!strncmp(environ[i], "_RLD_", 5)) ||
(!strncmp(environ[i], "LC_", 3)) ||
(!strncmp(environ[i], "LDR_", 3)))
{
// unset it
char *tmp, *p;
tmp = strdup(environ[i]);
if (!tmp) abort();
p = strchr(tmp, '=');
if (!p) abort();
*p = 0;
NOENV(tmp);
free(tmp);
// and mark our do to try again from the start in case
// unsetenv changes environ ptr
again = EINA_TRUE;
break;
}
}
}
while (again);
}
# endif
#endif
// pass 2 - clear entire environment so it doesn't exist at all. if you
// can't do this... you're possibly in trouble... but the worst is still
// fixed in pass 3
#ifdef HAVE_CLEARENV
clearenv();
#else
# ifdef HAVE_ENVIRON
environ = NULL;
# endif
#endif
// pass 3 - set path and ifs to minimal defaults
putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin");
putenv("IFS= \t\n");
_etc_enlightenment_system_conf();
}
static void
_cb_die(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
char buf[256];
int f;
snprintf(buf, sizeof(buf), "/var/run/enlightenment_sys-%u.lck", uid);
f = open(buf, O_RDONLY);
if (f < 0) exit(0);
exit(0);
}
static void
singleton_setup(void)
{ // only one per uid - kill existing and replace...
char buf[256];
int f;
mode_t um;
snprintf(buf, sizeof(buf), "/var/run/enlightenment_sys-%u.lck", uid);
f = open(buf, O_WRONLY | O_NONBLOCK);
if (f >= 0)
{
if (write(f, buf, 1) == 1)
ERR("Replacing previous enlightenment_system\n");
close(f);
}
unlink(buf);
um = umask(0);
mkfifo(buf, S_IRUSR | S_IWUSR);
umask(um);
ecore_thread_feedback_run(_cb_die, NULL, NULL, NULL, NULL, EINA_TRUE);
}
int
main(int argc EINA_UNUSED, const char **argv EINA_UNUSED)
{
setuid_setup();
ecore_app_no_system_modules();
eina_init();
ecore_init();
ecore_file_init();
#ifdef HAVE_EEZE
eeze_init();
#endif
eet_init();
singleton_setup();
e_system_inout_init();
e_system_backlight_init();
e_system_storage_init();
e_system_power_init();
e_system_rfkill_init();
e_system_l2ping_init();
e_system_cpufreq_init();
ecore_main_loop_begin();
e_system_cpufreq_shutdown();
e_system_l2ping_shutdown();
e_system_rfkill_shutdown();
e_system_power_shutdown();
e_system_storage_shutdown();
e_system_backlight_shutdown();
e_system_inout_shutdown();
eet_shutdown();
#ifdef HAVE_EEZE
eeze_shutdown();
#endif
ecore_file_shutdown();
ecore_shutdown();
eina_shutdown();
return 0;
}

View File

@ -0,0 +1,134 @@
#include "e_system.h"
char *_cmd_halt = NULL;
char *_cmd_reboot = NULL;
char *_cmd_suspend = NULL;
char *_cmd_hibernate = NULL;
static void
_cb_power_halt(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
if (_cmd_halt) ecore_exe_run(_cmd_halt, NULL);
}
static void
_cb_power_reboot(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
if (_cmd_reboot) ecore_exe_run(_cmd_reboot, NULL);
}
static void
_cb_power_suspend(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
if (_cmd_suspend) ecore_exe_run(_cmd_suspend, NULL);
}
static void
_cb_power_hibernate(void *data EINA_UNUSED, const char *params EINA_UNUSED)
{
if (_cmd_hibernate) ecore_exe_run(_cmd_hibernate, NULL);
}
static void
_power_halt_init(void)
{
#if defined (__FreeBSD__) || defined (__OpenBSD__)
_cmd_halt = strdup("shutdown -p now");
#else
if (ecore_file_app_installed("systemctl"))
_cmd_halt = strdup("systemctl poweroff");
else
_cmd_halt = strdup("shutdown -h now");
#endif
// linux systemd: PATH/systemctl poweroff
// bsd: /sbin/shutdown -p no
// * : /sbin/shutdown -h now
}
static void
_power_reboot_init(void)
{
#if defined (__FreeBSD__) || defined (__OpenBSD__)
_cmd_reboot = strdup("shutdown -r now");
#else
if (ecore_file_app_installed("systemctl"))
_cmd_reboot = strdup("systemctl reboot");
else
_cmd_reboot = strdup("shutdown -r now");
#endif
// linux systemd: PATH/systemctl reboot
// *: /sbin/shutdown -r now
}
static void
_power_suspend_init(void)
{
#if defined (__FreeBSD__) || defined (__OpenBSD__)
if (ecore_file_app_installed("zzz"))
_cmd_suspend = strdup("zzz");
#else
if (ecore_file_app_installed("systemctl"))
_cmd_suspend = strdup("systemctl suspend");
else if (ecore_file_app_installed("sleep.sh"))
_cmd_suspend = strdup("sleep.sh");
else if (ecore_file_can_exec("/etc/acpi/sleep.sh"))
_cmd_suspend = strdup("/etc/acpi/sleep.sh force");
else if (ecore_file_app_installed("pm-suspend"))
_cmd_suspend = strdup("pm-suspend");
else if (ecore_file_can_exec("/etc/acpi/pm-suspend"))
_cmd_suspend = strdup("/etc/acpi/pm-suspend");
#endif
// linux systemd: PATH/systemctl suspend
// bsd: /usr/sbin/zzz
// *:
// PATH/sleep.sh
// /etc/acpi/sleep.sh force
// PATH/pm-suspend
// /etc/acpi/pm-suspend
}
static void
_power_hibernate_init(void)
{
#if defined (__FreeBSD__) || defined (__OpenBSD__)
if (ecore_file_app_installed("acpiconf"))
_cmd_hibernate = strdup("acpiconf -s4");
#else
if (ecore_file_app_installed("systemctl"))
_cmd_hibernate = strdup("systemctl hibernate");
else if (ecore_file_app_installed("hibernate.sh"))
_cmd_hibernate = strdup("hibernate.sh");
else if (ecore_file_can_exec("/etc/acpi/hibernate.sh"))
_cmd_hibernate = strdup("/etc/acpi/hibernate.sh force");
else if (ecore_file_app_installed("pm-hibernate"))
_cmd_hibernate = strdup("pm-hibernate");
else if (ecore_file_can_exec("/etc/acpi/pm-hibernate"))
_cmd_hibernate = strdup("/etc/acpi/pm-hibernate");
#endif
// linux systemd: PATH/systemctl hibernate
// bsd: acpiconf -s4
// if exist:
// PATH/hibernate.sh
// /etc/acpi/hibernate.sh force
// PATH/pm-hibernate
// /etc/acpi/pm-hibernate
}
void
e_system_power_init(void)
{
_power_halt_init();
_power_reboot_init();
_power_suspend_init();
_power_hibernate_init();
e_system_inout_command_register("power-halt", _cb_power_halt, NULL);
e_system_inout_command_register("power-reboot", _cb_power_reboot, NULL);
e_system_inout_command_register("power-suspend", _cb_power_suspend, NULL);
e_system_inout_command_register("power-hibernate", _cb_power_hibernate, NULL);
}
void
e_system_power_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,176 @@
#include "e_system.h"
typedef struct
{
char *dev;
Ecore_Event_Handler *handle_del, *handle_data;
Ecore_Exe *exe;
int id;
Eina_Bool block : 1;
Eina_Bool doit : 1;
} Action;
static Eina_Bool
_rfkill_dev_verify(const char *dev)
{
const char *s;
for (s = dev; *s; s++)
{
if (!(((*s >= 'a') && (*s <= 'z')) ||
((*s >= 'A') && (*s <= 'Z')) ||
((*s >= '0') && (*s <= '9')) ||
(*s == '-') || (*s == '+') || (*s == ',') || (*s == '.') ||
(*s == '/') || (*s == ':') || (*s == '=') || (*s == '@')))
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
_rfkill_action_free(Action *a)
{
// a->exe can stay - exe's are auto-freed by ecore on exit
// if (a->exe) ecore_exe_free(a->exe);
if (a->handle_del) ecore_event_handler_del(a->handle_del);
if (a->handle_data) ecore_event_handler_del(a->handle_data);
free(a->dev);
free(a);
}
static Eina_Bool
_cb_rfkill_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
{
Action *a = data;
Ecore_Exe_Event_Del *ev = event;
if (ev->exe != a->exe) return EINA_TRUE;
if (a->id >= 0)
{
if (a->doit)
{
if (a->block)
e_system_inout_command_send("rfkill-block", "%i %s",
ev->exit_code, a->dev);
else
e_system_inout_command_send("rfkill-unblock", "%i %s",
ev->exit_code, a->dev);
_rfkill_action_free(a);
}
else
{
char cmd[1024];
// a->exe can stay - exe's are auto-freed by ecore on exit
// ecore_exe_free(a->exe);
a->exe = NULL;
if (snprintf(cmd, sizeof(cmd), "rfkill %s %i",
a->block ? "block" : "unblock", a->id) <
(int)(sizeof(cmd) - 1))
{
a->doit = EINA_TRUE;
a->exe = ecore_exe_pipe_run(cmd,
ECORE_EXE_NOT_LEADER |
ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_WRITE |
ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL);
if (!a->exe) _rfkill_action_free(a);
}
else _rfkill_action_free(a);
}
}
else
{
if (a->block)
e_system_inout_command_send("rfkill-block", "%i %s",
123, a->dev);
else
e_system_inout_command_send("rfkill-unblock", "%i %s",
123, a->dev);
_rfkill_action_free(a);
}
return EINA_TRUE;
}
static Eina_Bool
_cb_rfkill_exe_data(void *data, int ev_type EINA_UNUSED, void *event)
{
Action *a = data;
Ecore_Exe_Event_Data *ev = event;
int i;
if (ev->exe != a->exe) return EINA_TRUE;
if (a->id >= 0) return EINA_TRUE;
for (i = 0; ev->lines[i].line; i++)
{
int id;
char dev[1024];
id = -1;
if (sscanf(ev->lines[i].line, "%i %*s %1023s %*s %*s", &id, dev) == 2)
{
if (!strcmp(a->dev, dev))
{
a->id = id;
// wait for exit to spawn rfkill again...
break;
}
}
}
return EINA_TRUE;
}
static void
_rfkill_do(Eina_Bool block, const char *dev)
{
Action *a = calloc(1, sizeof(Action));
if (!a) return;
a->dev = strdup(dev);
if (!a->dev) goto err;
a->id = -1;
a->block = block;
a->handle_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_cb_rfkill_exe_del, a);
a->handle_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
_cb_rfkill_exe_data, a);
if ((!a->handle_del) || (!a->handle_data)) goto err;
// stage 1 - run to get list of devices and id's to know what id to use
a->exe = ecore_exe_pipe_run("rfkill",
ECORE_EXE_NOT_LEADER |
ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_WRITE |
ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL);
if (!a->exe) goto err;
return;
err:
ERR("Can't run rfkill\n");
_rfkill_action_free(a);
}
static void
_cb_rfkill_block(void *data EINA_UNUSED, const char *params)
{
if (!_rfkill_dev_verify(params)) return;
_rfkill_do(EINA_TRUE, params);
}
static void
_cb_rfkill_unblock(void *data EINA_UNUSED, const char *params)
{
if (!_rfkill_dev_verify(params)) return;
_rfkill_do(EINA_FALSE, params);
}
void
e_system_rfkill_init(void)
{
e_system_inout_command_register("rfkill-block", _cb_rfkill_block, NULL);
e_system_inout_command_register("rfkill-unblock", _cb_rfkill_unblock, NULL);
}
void
e_system_rfkill_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,455 @@
#include "e_system.h"
typedef struct
{
char *dev, *mountpoint, *cmd, *cmd2, *cmd1;
Ecore_Exe *exe;
Ecore_Event_Handler *handler;
Eina_Bool eject : 1;
Eina_Bool mount : 1;
Eina_Bool umount : 1;
Eina_Bool in_progress : 1;
} Action;
static Eina_List *_pending_actions = NULL;
static Eina_Bool _store_action_do(Action *a);
static Eina_Bool
_store_device_verify(const char *dev)
{
const char *s;
struct stat st;
// not even /dev/something? no way.
if (!(!strncmp(dev, "/dev/", 5))) return EINA_FALSE;
// if it contains /.. - even tho it could be file/..name not file/../name
// it still looks suspicious enough so - no
if (strstr(dev, "/..")) return EINA_FALSE;
// any chars that cold be used in any evil ways - no way. device names
// should not have these...
for (s = dev; *s; s++)
{
if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') ||
(*s == '>') || (*s == '?') || (*s >= '{') ||
((*s >= '[') && (*s <= '^')))
return EINA_FALSE;
}
// must exist as a file - if not - nope
if (stat(dev, &st) != 0) return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
_store_uuid_verify(const char *dev)
{
const char *s;
if (!(!strncmp(dev, "UUID=", 5))) return EINA_FALSE;
for (s = dev + 5; *s; s++)
{
if ((!isalnum(*s)) && (*s != '-')) return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
_mkdir(const char *path, uid_t u, gid_t g)
{
mode_t um;
int ret, e;
um = umask(0);
errno = 0;
ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
e = errno;
umask(um);
if (ret != 0)
{
if (e != EEXIST)
{
ERR("Can't create mount dir [%s]\n", path);
return EINA_FALSE;
}
else
{
struct stat st;
if (stat(path, &st) == 0)
{
if (!S_ISDIR(st.st_mode))
{
ERR("Path is not a dir [%s]\n", path);
return EINA_FALSE;
}
}
}
}
if (chown(path, u, g) != 0)
{
ERR("Can't own [%s] to uid.gid %i.%i\n", path, uid, gid);
return EINA_FALSE;
}
return EINA_TRUE;
}
static Eina_Bool
_store_mount_verify(const char *mnt)
{
char *tmnt, *p;
const char *s;
struct stat st;
if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE;
for (s = mnt; *s; s++)
{
if (*s == '\\') return EINA_FALSE;
}
if (strstr(mnt, "/..")) return EINA_FALSE;
if (stat(mnt, &st) == 0)
{
if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
if (st.st_uid != uid) return EINA_FALSE;
}
tmnt = strdup(mnt);
if (tmnt)
{
// /media <- owned by root
p = strchr(tmnt + 1, '/');
if (!p) goto malformed;
*p = '\0';
if (!_mkdir(tmnt, 0, 0)) goto err;
*p = '/';
// /media/username <- owned by uid.gid
p = strchr(p + 1, '/');
if (!p) goto malformed;
*p = '\0';
if (!_mkdir(tmnt, uid, gid)) goto err;
*p = '/';
// /media/username/dirname <- owned by root
if (!_mkdir(tmnt, uid, gid)) goto err;
free(tmnt);
}
return EINA_TRUE;
malformed:
ERR("Malformed mount point [%s]\n", mnt);
err:
free(tmnt);
return EINA_FALSE;
}
static Eina_Bool
_store_umount_verify(const char *mnt)
{
char *tmnt, *p;
const char *s;
struct stat st;
if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE;
for (s = mnt; *s; s++)
{
if (*s == '\\') return EINA_FALSE;
}
if (stat(mnt, &st) != 0) return EINA_FALSE;
if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
tmnt = strdup(mnt);
if (!tmnt) return EINA_FALSE;
p = strchr(tmnt + 8, '/');
if (!p) goto err;
*p = '\0';
if (stat(tmnt, &st) != 0) goto err;
if (st.st_uid != uid) goto err;
free(tmnt);
return EINA_TRUE;
err:
free(tmnt);
return EINA_FALSE;
}
static void
_store_action_free(Action *a)
{
free(a->dev);
free(a->mountpoint);
free(a->cmd);
free(a->cmd2);
free(a->cmd1);
if (a->handler) ecore_event_handler_del(a->handler);
if (a->exe) ecore_exe_free(a->exe);
free(a);
}
static void
_store_pending_action_next(void)
{
while (_pending_actions)
{
Action *a = _pending_actions->data;
if (_store_action_do(a)) break;
else _pending_actions = eina_list_remove(_pending_actions, a);
}
}
static Eina_Bool
_cb_store_eject_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Del *ev = event;
Action *a = data;
if (ev->exe == a->exe)
{
a->exe = NULL;
if (a->eject)
e_system_inout_command_send("store-eject", "%i %s",
ev->exit_code, a->dev);
else if ((a->mount) &&
((ev->exit_code == 0) ||
(!((a->cmd) || (a->cmd1) || (a->cmd2)))))
e_system_inout_command_send("store-mount", "%i %s %s",
ev->exit_code, a->dev, a->mountpoint);
else if (a->umount)
{
if (ev->exit_code == 0)
{
rmdir(a->mountpoint);
}
e_system_inout_command_send("store-umount", "%i %s",
ev->exit_code, a->mountpoint);
}
if (((a->cmd) || (a->cmd1) || (a->cmd2)) && (ev->exit_code != 0))
{
if (!_store_action_do(a))
{
_pending_actions = eina_list_remove(_pending_actions, a);
_store_action_free(a);
_store_pending_action_next();
}
}
else
{
_pending_actions = eina_list_remove(_pending_actions, a);
_store_action_free(a);
_store_pending_action_next();
}
}
return EINA_TRUE;
}
static Eina_Bool
_store_action_do(Action *a)
{
a->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_cb_store_eject_exe_del, a);
if (!a->handler) _store_action_free(a);
else
{
if (a->cmd2)
{
a->exe = ecore_exe_run(a->cmd2, NULL);
free(a->cmd2);
a->cmd2 = NULL;
}
else if (a->cmd1)
{
a->exe = ecore_exe_run(a->cmd1, NULL);
free(a->cmd1);
a->cmd1 = NULL;
}
else
{
a->exe = ecore_exe_run(a->cmd, NULL);
free(a->cmd);
a->cmd = NULL;
}
a->in_progress = EINA_TRUE;
if (!a->exe) _store_action_free(a);
else return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_store_action_queue(Action *a)
{
if (_pending_actions)
_pending_actions = eina_list_append(_pending_actions, a);
else if (_store_action_do(a))
_pending_actions = eina_list_append(_pending_actions, a);
}
static void
_cb_store_eject(void *data EINA_UNUSED, const char *params)
{
// params:
// /dev/xxx
char cmd0[512];
char cmd[4096 + 512 + 128];
if (!_store_device_verify(params))
{
ERR("Invalid device [%s]\n", params);
return;
}
#if defined (__FreeBSD__) || defined (__OpenBSD__)
// on bsd cdcontrol is the shnizzle for this
if (ecore_file_app_installed("cdcontrol"))
snprintf(cmd0, sizeof(cmd0), "cdcontrol eject");
// otherwise regular old eject will do
else
#endif
snprintf(cmd0, sizeof(cmd0), "eject");
if (snprintf(cmd, sizeof(cmd), "%s %s", cmd0, params) < (int)(sizeof(cmd) - 1))
{
Action *a = calloc(1, sizeof(Action));
if (a)
{
a->eject = EINA_TRUE;
a->dev = strdup(params);
a->cmd = strdup(cmd);
if ((!a->dev) || (!a->cmd)) _store_action_free(a);
else _store_action_queue(a);
}
}
}
static void
_cb_store_mount(void *data EINA_UNUSED, const char *params)
{
// params:
// /dev/sdc1 - /media/user/dir
// /dev/disk/by-uuid/d9c53a62-7fc2-4cc3-9616-4e41e065da4c - /media/user/dir
// /dev/sdb1 x /media/user/dir
// ...
// DEV ARG MNT
// ARG is - OR one or more of the below chars (-, xs, rx, ...):
// x = noexec
// r = ro
// s = sync
// d = dirsync
// l = lazytime
// a = noatime
// A = relatime
// D = diratime
char dev[1024], arg[128], mnt[4096], opt2[512], opt1[512], opt0[256], *p;
char cmd2[(4096 * 2) + 1024 + 500];
char cmd1[(4096 * 2) + 1024 + 500];
char cmd0[(4096 * 2) + 1024 + 500];
if (sscanf(params, "%1023s %127s %4095s", dev, arg, mnt) == 3)
{
char *mnt2;
if ((!_store_device_verify(dev)) && (!_store_uuid_verify(dev)))
{
ERR("Invalid device [%s]\n", dev);
return;
}
if (!_store_mount_verify(mnt))
{
ERR("Invalid mount [%s]\n", mnt);
return;
}
mnt2 = ecore_file_escape_name(mnt);
if (mnt2)
{
Eina_Bool o_noexec = EINA_FALSE;
Eina_Bool o_ro = EINA_FALSE;
Eina_Bool o_sync = EINA_FALSE;
Eina_Bool o_dirsync = EINA_FALSE;
Eina_Bool o_lazytime = EINA_FALSE;
Eina_Bool o_noatime = EINA_FALSE;
Eina_Bool o_relatime = EINA_FALSE;
Eina_Bool o_diratime = EINA_FALSE;
for (p = arg; *p; p++)
{
if ((*p) == 'x') o_noexec = EINA_TRUE;
else if ((*p) == 'r') o_ro = EINA_TRUE;
else if ((*p) == 's') o_sync = EINA_TRUE;
else if ((*p) == 'd') o_dirsync = EINA_TRUE;
else if ((*p) == 'l') o_lazytime = EINA_TRUE;
else if ((*p) == 'a') o_noatime = EINA_TRUE;
else if ((*p) == 'A') o_relatime = EINA_TRUE;
else if ((*p) == 'D') o_diratime = EINA_TRUE;
}
snprintf(opt0, sizeof(opt0),
"nosuid,nodev%s%s%s%s%s%s%s%s",
o_noexec ? ",noexec" : "",
o_ro ? ",ro" : "",
o_sync ? ",sync" : "",
o_dirsync ? ",dirsync" : "",
o_lazytime ? ",lazytime" : "",
o_noatime ? ",noatime" : "",
o_relatime ? ",relatime" : "",
o_diratime ? ",diratime" : "");
snprintf(opt2, sizeof(opt2), "%s,iocharset=utf8,uid=%i", opt0, uid);
snprintf(opt1, sizeof(opt1), "%s,iocharset=utf8", opt0);
// opt2, opt1, opt0
if ((snprintf(cmd2, sizeof(cmd2), "mount -o %s %s %s",
opt2, dev, mnt2) < (int)(sizeof(cmd2) - 1)) &&
(snprintf(cmd1, sizeof(cmd1), "mount -o %s %s %s",
opt1, dev, mnt2) < (int)(sizeof(cmd1) - 1)) &&
(snprintf(cmd0, sizeof(cmd0), "mount -o %s %s %s",
opt0, dev, mnt2) < (int)(sizeof(cmd0) - 1)))
{
Action *a = calloc(1, sizeof(Action));
if (a)
{
a->mount = EINA_TRUE;
a->dev = strdup(dev);
a->mountpoint = strdup(mnt);
a->cmd = strdup(cmd0);
a->cmd2 = strdup(cmd2);
a->cmd1 = strdup(cmd1);
if ((!a->dev) || (!a->mountpoint) ||
(!a->cmd) || (!a->cmd2) || (!a->cmd1))
_store_action_free(a);
else _store_action_queue(a);
}
}
}
free(mnt2);
}
}
static void
_cb_store_umount(void *data EINA_UNUSED, const char *params)
{
// params:
// /media/user/xxx
char cmd[4096];
if (!_store_umount_verify(params))
{
ERR("Invalid mount [%s]\n", params);
return;
}
if (snprintf(cmd, sizeof(cmd), "umount %s", params) < (int)(sizeof(cmd) - 1))
{
Action *a = calloc(1, sizeof(Action));
if (a)
{
a->umount = EINA_TRUE;
a->mountpoint = strdup(params);
a->cmd = strdup(cmd);
if ((!a->mountpoint) || (!a->cmd)) _store_action_free(a);
else _store_action_queue(a);
}
}
}
void
e_system_storage_init(void)
{
e_system_inout_command_register("store-eject", _cb_store_eject, NULL);
e_system_inout_command_register("store-mount", _cb_store_mount, NULL);
e_system_inout_command_register("store-umount", _cb_store_umount, NULL);
}
void
e_system_storage_shutdown(void)
{
// only shutdown things we really have to - no need to free mem etc.
}

View File

@ -0,0 +1,146 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <Eina.h>
#include <Ecore.h>
typedef struct
{
char cmd[24];
int size;
} Message_Head;
static Ecore_Exe *exe;
static Eina_Bool
_cb_exe_del(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event EINA_UNUSED)
{
ecore_main_loop_quit();
return EINA_TRUE;
}
static Eina_Binbuf *buf = NULL;
static Eina_Bool
_message_read(void)
{
Message_Head *head;
const unsigned char *data = eina_binbuf_string_get(buf);
size_t len = eina_binbuf_length_get(buf);
Eina_Binbuf *buf2;
if (!data) return EINA_FALSE;
if (len < sizeof(Message_Head)) return EINA_FALSE;
head = (Message_Head *)data;
if (len < (sizeof(Message_Head) + head->size)) return EINA_FALSE;
printf("CMD: [%s]", head->cmd);
if (head->size == 0) printf("\n\n");
else printf(" [%s]\n\n", data + sizeof(Message_Head));
buf2 = eina_binbuf_new();
eina_binbuf_append_length(buf2,
data + sizeof(Message_Head) + head->size,
len - (sizeof(Message_Head) + head->size));
eina_binbuf_free(buf);
buf = buf2;
return EINA_TRUE;
}
static Eina_Bool
_cb_exe_data(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Data *ev = event;
eina_binbuf_append_length(buf, ev->data, ev->size);
while (_message_read());
return EINA_TRUE;
}
static void
_cb_input(void *data EINA_UNUSED, Ecore_Thread *th)
{
char b[4096], *msg = NULL;
for (;;)
{
while (fgets(b, sizeof(b) - 1, stdin))
{
b[sizeof(b) - 1] = 0;
size_t len = strlen(b);
for (len = len - 1; len > 0; len--)
{
if (b[len] == '\n') b[len] = '\0';
else if (b[len] == '\r') b[len] = '\0';
else break;
}
msg = strdup(b);
if (msg) ecore_thread_feedback(th, msg);
}
}
}
static void
_cb_input_message(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED, void *msg_data)
{
char *msg = msg_data;
char *spc, *params = NULL;
Message_Head head;
head.size = 0;
spc = strchr(msg, ' ');
if (spc)
{
*spc = '\0';
params = spc + 1;
head.size = strlen(params) + 1;
}
strcpy(head.cmd, msg);
ecore_exe_send(exe, &head, sizeof(Message_Head));
if (head.size > 0) ecore_exe_send(exe, params, strlen(params) + 1);
}
static void
_cb_input_end(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
}
static void
_cb_input_cancel(void *data EINA_UNUSED, Ecore_Thread *th EINA_UNUSED)
{
}
int
main(int argc, const char **argv)
{
const char *backend;
if (argc < 2)
{
printf("use: %s /usr/local/lib/enlightenment/utils/enlightenment_system\n"
" or the path to the enlightenment_system tool wherever it is\n",
argv[0]);
return -1;
}
backend = argv[1];
eina_init();
ecore_init();
buf = eina_binbuf_new();
ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _cb_exe_del, NULL);
ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _cb_exe_data, NULL);
exe = ecore_exe_pipe_run(backend,
ECORE_EXE_NOT_LEADER |
ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_PIPE_READ |
ECORE_EXE_PIPE_WRITE, NULL);
ecore_thread_feedback_run(_cb_input, _cb_input_message,
_cb_input_end, _cb_input_cancel, NULL, EINA_TRUE);
ecore_main_loop_begin();
ecore_shutdown();
eina_shutdown();
return 0;
}

View File

@ -0,0 +1,29 @@
src = [
'e_system_main.c',
'e_system_inout.c',
'e_system_backlight.c',
'e_system_storage.c',
'e_system_power.c',
'e_system_rfkill.c',
'e_system_l2ping.c',
'e_system_cpufreq.c',
'e_system.h',
]
executable('enlightenment_system', src,
include_directories: include_directories('../../..'),
dependencies : [ dep_eina, dep_ecore, dep_ecore_file,
dep_m, dep_dl,
dep_eet, dep_eeze,
dep_bluez ],
c_args : suid_cflags,
link_args : suid_ldflags,
install_dir : dir_e_utils,
install : true
)
suid_exes += join_paths(dir_e_utils, 'enlightenment_system')
executable('enlightenment_system_test', [ 'e_system_test.c' ],
include_directories: include_directories('../../..'),
dependencies : [ dep_eina, dep_ecore ],
install_dir : dir_e_utils,
install : true
)