You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

585 lines
15 KiB

#include "entrance.h"
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <Eina.h>
#include "Ecore_Getopt.h"
#include <xcb/xcb.h>
#include <assert.h>
#define ENTRANCE_DISPLAY ":0.0"
#define ENTRANCE_XEPHYR ":1.0"
#define ENTRANCE_CONFIG_HOME_PATH "/var/cache/entrance/client"
static Eina_Bool _open_log();
static Eina_Bool _entrance_main(const char *dname);
static void _remove_lock();
static void _signal_cb(int sig);
static void _signal_log(int sig);
static void _entrance_autologin_lock_set(void);
static Eina_Bool _entrance_autologin_lock_get(void);
static Eina_Bool _entrance_client_error(void *data, int type, void *event);
static Eina_Bool _entrance_client_data(void *data, int type, void *event);
static Eina_Bool _entrance_client_del(void *data, int type, void *event);
static void _entrance_wait(void);
static Eina_Bool _testing = 0;
static Eina_Bool _xephyr = 0;
static Ecore_Exe *_entrance_client = NULL;
static void
_signal_cb(int sig)
{
PT("signal %d received", sig);
//FIXME if I don't have main loop at this time ?
if (_entrance_client)
ecore_exe_terminate(_entrance_client);
else
ecore_main_loop_quit();
}
static void
_signal_log(int sig EINA_UNUSED)
{
PT("reopen the log file");
entrance_close_log();
_open_log();
}
static Eina_Bool
_get_lock()
{
FILE *f;
char buf[128];
int my_pid;
my_pid = getpid();
f = fopen(entrance_config->lockfile, "r");
if (!f)
{
/* No lockfile, so create one */
f = fopen(entrance_config->lockfile, "w");
if (!f)
{
PT("Couldn't create lockfile!");
return (EINA_FALSE);
}
snprintf(buf, sizeof(buf), "%d", my_pid);
if (!fwrite(buf, strlen(buf), 1, f))
{
fclose(f);
PT("Couldn't write the lockfile");
return EINA_FALSE;
}
fclose(f);
}
else
{
int pid = 0;
/* read the lockfile */
if (fgets(buf, sizeof(buf), f))
pid = atoi(buf);
fclose(f);
if (pid == my_pid)
return EINA_TRUE;
PT("A lock file are present another instance are present ?");
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
_update_lock()
{
FILE *f;
char buf[128];
f = fopen(entrance_config->lockfile, "w");
snprintf(buf, sizeof(buf), "%d", getpid());
if (!fwrite(buf, strlen(buf), 1, f))
PT("Coudn't update lockfile");
fclose(f);
}
static void
_remove_lock()
{
remove(entrance_config->lockfile);
}
static Eina_Bool
_open_log()
{
FILE *elog;
elog = fopen(entrance_config->logfile, "a");
if (!elog)
{
PT("could not open logfile !");
return EINA_FALSE;
}
fclose(elog);
if (!freopen(entrance_config->logfile, "a", stdout))
PT("Error on reopen stdout");
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
if (!freopen(entrance_config->logfile, "a", stderr))
PT("Error on reopen stderr");
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
return EINA_TRUE;
}
void
entrance_close_log()
{
{
fclose(stderr);
fclose(stdout);
}
}
static void
_entrance_wait(void)
{
// XXX: use eina_prefix! hardcoding paths . :(
execl(PACKAGE_BIN_DIR"/entrance_wait", PACKAGE_SBIN_DIR"/entrance", NULL);
PT("HUM HUM HUM can't wait ...");
_exit(1);
}
static Eina_Bool
_entrance_client_error(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
char buf[4096];
Ecore_Exe_Event_Data *ev;
size_t size;
ev = event;
size = ev->size;
if ((unsigned int)ev->size > sizeof(buf) - 1)
size = sizeof(buf) - 1;
strncpy(buf, (char*)ev->data, size);
EINA_LOG_DOM_ERR(_entrance_client_log, "%s", buf);
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
_entrance_client_data(void *d EINA_UNUSED, int t EINA_UNUSED, void *event)
{
char buf[4096];
Ecore_Exe_Event_Data *ev;
size_t size;
ev = event;
size = ev->size;
if ((unsigned int)ev->size > sizeof(buf) - 1)
size = sizeof(buf) - 1;
snprintf(buf, size + 1, "%s", (char*)ev->data);
EINA_LOG_DOM_INFO(_entrance_client_log, "%s", buf);
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
_entrance_main(const char *dname)
{
struct passwd *pwd = NULL;
const char *user;
char buf[PATH_MAX];
const char *home_path;
struct stat st;
PT("starting...");
if (!entrance_config->autologin)
{
if (!_entrance_client)
{
ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_entrance_client_del, NULL);
ecore_event_handler_add(ECORE_EXE_EVENT_ERROR,
_entrance_client_error, NULL);
ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
_entrance_client_data, NULL);
if (entrance_config->start_user
&& entrance_config->start_user[0]) {
pwd = getpwnam(entrance_config->start_user);
}
if (!pwd)
{
PT("The given user %s, is not valid."
"Falling back to nobody", entrance_config->start_user);
pwd = getpwnam("nobody");
user = "nobody";
assert(pwd);
}
else
{
user = entrance_config->start_user;
}
if (!pwd->pw_dir || !strcmp(pwd->pw_dir, "/"))
{
PT("No home directory for client");
home_path = ENTRANCE_CONFIG_HOME_PATH;
if (!ecore_file_exists(ENTRANCE_CONFIG_HOME_PATH))
{
PT("Creating new home directory for client");
ecore_file_mkdir(ENTRANCE_CONFIG_HOME_PATH);
chown(ENTRANCE_CONFIG_HOME_PATH,
pwd->pw_uid, pwd->pw_gid);
}
}
else
{
home_path = pwd->pw_dir;
}
PT("Home directory %s", home_path);
stat(home_path, &st);
if ((st.st_uid != pwd->pw_uid)
|| (st.st_gid != pwd->pw_gid))
{
PT("The permission about %s is wrong, I fix it", home_path);
chown(home_path, pwd->pw_uid, pwd->pw_gid);
}
snprintf(buf, sizeof(buf),
SUDO" --user %s HOME=%s "
"LD_LIBRARY_PATH="PACKAGE_LIB_DIR" "
PACKAGE_BIN_DIR"/entrance_client -d %s -t %s",
user, home_path, dname, entrance_config->theme);
PT("Exec entrance_client: %s", buf);
_entrance_client =
ecore_exe_pipe_run(buf,
ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR,
NULL);
}
}
else
ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_entrance_client_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Del *ev;
ev = event;
if (ev->exe != _entrance_client)
return ECORE_CALLBACK_PASS_ON;
PT("client have terminated");
ecore_main_loop_quit();
_entrance_client = NULL;
return ECORE_CALLBACK_DONE;
}
static void
_entrance_autologin_lock_set(void)
{
system("touch /var/cache/entrance/login");
}
static Eina_Bool
_entrance_autologin_lock_get(void)
{
FILE *f;
char buf[4096];
double uptime, sleep_time;
struct stat st_login;
f = fopen("/proc/uptime", "r");
if (f)
{
fgets(buf, sizeof(buf), f);
fscanf(f, "%lf %lf", &uptime, &sleep_time);
fclose(f);
if (stat("/var/run/entrance/login", &st_login) > 0)
return EINA_FALSE;
else
return EINA_TRUE;
}
return EINA_FALSE;
}
static const Ecore_Getopt options =
{
PACKAGE,
"%prog [options]",
VERSION,
"(C) 201e Enlightenment, see AUTHORS",
"GPL, see COPYING",
"Entrance is a login manager, written using core efl libraries",
EINA_TRUE,
{
ECORE_GETOPT_STORE_TRUE('n', "nodaemon", "Don't daemonize."),
ECORE_GETOPT_STORE_TRUE('t', "test", "run in test mode."),
ECORE_GETOPT_STORE_TRUE('e', "fastexit", "Will change the way entrance"
"handles the exit of the created session. If "
"set, entrance will exit if the session quits. "
"If not, entrance will restart if the session is "
"quit because of an error, or if the environment "
"variable ENTRANCE_RESTART is set."),
ECORE_GETOPT_STORE_TRUE('x', "xephyr", "run in test mode and use "
"Xephyr."),
ECORE_GETOPT_HELP ('h', "help"),
ECORE_GETOPT_VERSION('V', "version"),
ECORE_GETOPT_COPYRIGHT('R', "copyright"),
ECORE_GETOPT_LICENSE('L', "license"),
ECORE_GETOPT_SENTINEL
}
};
int
main (int argc, char ** argv)
{
int args;
int pid = -1;
char *dname;
char *entrance_user = NULL;
unsigned char nodaemon = 0;
unsigned char fastexit = 0;
unsigned char quit_option = 0;
Ecore_Getopt_Value values[] =
{
ECORE_GETOPT_VALUE_BOOL(nodaemon),
ECORE_GETOPT_VALUE_BOOL(_testing),
ECORE_GETOPT_VALUE_BOOL(fastexit),
ECORE_GETOPT_VALUE_BOOL(_xephyr),
ECORE_GETOPT_VALUE_BOOL(quit_option),
ECORE_GETOPT_VALUE_BOOL(quit_option),
ECORE_GETOPT_VALUE_BOOL(quit_option),
ECORE_GETOPT_VALUE_BOOL(quit_option),
ECORE_GETOPT_VALUE_NONE
};
eina_init();
eina_log_threads_enable();
ecore_init();
_entrance_log = eina_log_domain_register("entrance", EINA_COLOR_CYAN);
_entrance_client_log = eina_log_domain_register("entrance_client",
EINA_COLOR_CYAN);
eina_log_domain_level_set("entrance", 5);
eina_log_domain_level_set("entrance_client", 5);
args = ecore_getopt_parse(&options, values, argc, argv);
if (args < 0)
{
PT("ERROR: could not parse options.");
return -1;
}
if (quit_option)
return 0;
if (getuid() != 0)
{
fprintf(stderr, "Sorry, only root can run this program!");
return 1;
}
if (!_xephyr && getenv("ENTRANCE_XEPHYR"))
_xephyr = EINA_TRUE;
if (fastexit)
{
putenv(strdup("ENTRANCE_FAST_QUIT=1"));
PT("Fast exit enabled !");
}
if (_xephyr)
{
_testing = EINA_TRUE;
dname = strdup(ENTRANCE_XEPHYR);
putenv(strdup("ENTRANCE_XEPHYR=1"));
}
else
dname = strdup(ENTRANCE_DISPLAY);
if (!_testing && getenv("ENTRANCE_TESTING"))
_testing = EINA_TRUE;
if (_testing)
{
putenv(strdup("ENTRANCE_TESTING=1"));
nodaemon = EINA_TRUE;
}
eet_init();
entrance_config_init();
if (!entrance_config)
{
PT("No config loaded, sorry must quit ...");
exit(1);
}
if (!_testing && !_get_lock())
{
exit(1);
}
if (!nodaemon && entrance_config->daemonize)
{
if (daemon(0, 1) == -1)
{
PT("Error on daemonize !");
quit_option = EINA_TRUE;
}
_update_lock();
int fd;
if ((fd = open("/dev/null", O_RDONLY)))
{
dup2(fd, 0);
close(fd);
}
}
if (quit_option)
{
entrance_config_shutdown();
exit(1);
}
if (!_testing && !_open_log())
{
PT("Can't open log file !!!!");
entrance_config_shutdown();
exit(1);
}
entrance_user = getenv("ENTRANCE_USER");
if (entrance_user)
{
char *quit;
entrance_xserver_wait();
sleep(5);
entrance_session_init(dname);
entrance_session_end(entrance_user);
entrance_session_shutdown();
quit = getenv("ENTRANCE_QUIT");
if (quit)
{
unsetenv("ENTRANCE_QUIT");
PT("Last DE Session quit with error!");
}
_remove_lock();
PT("Entrance will quit, bye bye :).");
entrance_close_log();
exit(1);
}
PT("Welcome");
ecore_init();
efreet_init();
/* Initialise event handler */
signal(SIGQUIT, _signal_cb);
signal(SIGTERM, _signal_cb);
signal(SIGKILL, _signal_cb);
signal(SIGINT, _signal_cb);
signal(SIGHUP, _signal_cb);
signal(SIGPIPE, _signal_cb);
signal(SIGALRM, _signal_cb);
signal(SIGUSR2, _signal_log);
PT("session init");
entrance_session_init(dname);
entrance_session_cookie();
if (!_xephyr)
{
PT("xserver init");
pid = entrance_xserver_init(_entrance_main, dname);
}
else
{
putenv(strdup("ENTRANCE_XPID=-1"));
_entrance_main(dname);
}
PT("history init");
entrance_history_init();
if ((entrance_config->autologin) && _entrance_autologin_lock_get())
{
PT("autologin init");
xcb_connection_t *disp = NULL;
disp = xcb_connect(dname, NULL);
PT("main loop begin");
ecore_main_loop_begin();
PT("auth user");
#ifdef HAVE_PAM
entrance_pam_init(PACKAGE, dname, NULL);
entrance_pam_item_set(ENTRANCE_PAM_ITEM_USER,
entrance_config->userlogin);
#endif
PT("login user");
entrance_session_login(
entrance_history_user_session_get(entrance_config->userlogin),
EINA_FALSE);
sleep(30);
xcb_disconnect(disp);
}
else
{
PT("action init");
entrance_action_init();
PT("server init");
entrance_server_init();
PT("starting main loop");
ecore_main_loop_begin();
PT("main loop end");
entrance_server_shutdown();
PT("server shutdown");
entrance_action_shutdown();
PT("action shutdown");
}
entrance_history_shutdown();
PT("history shutdown");
if (_xephyr)
{
//ecore_exe_terminate(xephyr);
PT("Xephyr shutdown");
}
else
{
entrance_xserver_shutdown();
PT("xserver shutdown");
}
#ifdef HAVE_PAM
entrance_pam_shutdown();
PT("pam shutdown");
#endif
_entrance_autologin_lock_set();
efreet_shutdown();
PT("ecore shutdown");
ecore_shutdown();
PT("session shutdown");
entrance_session_shutdown();
if (entrance_session_logged_get())
{
PT("user logged, waiting...");
_entrance_wait();
/* no more running here */
}
_remove_lock();
PT("config shutdown");
entrance_config_shutdown();
PT("eet shutdown");
eet_shutdown();
free(dname);
if (!_xephyr)
{
PT("ending xserver");
kill(pid, SIGTERM);
entrance_xserver_end();
entrance_xserver_wait();
}
else
PT("No session to wait, exiting");
entrance_close_log();
return 0;
}