Init
/* $Id$ */
/* Copyright (c) 2008-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System Init */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "service.h"
#include "common.h"
#include "session.h"
/* Session */
/* types */
struct _Session
{
String * name;
String * profile;
Event * event;
Config * config;
Service ** services;
size_t services_cnt;
};
/* prototypes */
/* private */
/* accessors */
static StringArray * _session_get_config_services(Session * session);
static String * _session_get_filename(Session * session);
/* useful */
static int _session_load(Session * session);
/* functions */
/* public */
/* session_new */
Session * session_new(char const * name, char const * profile, Event * event)
{
Session * session;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\", %p)\n", __func__, name,
profile, event);
#endif
if(name == NULL || event == NULL)
{
error_set_code(1, "%s", strerror(EINVAL));
return NULL;
}
if((session = object_new(sizeof(*session))) == NULL)
return NULL;
session->name = string_new(name);
session->profile = (profile != NULL) ? string_new(profile) : NULL;
session->event = event;
session->config = config_new();
session->services = NULL;
session->services_cnt = 0;
/* kickoff the session */
/* FIXME should this be really fatal? annoying for Init */
if(session_start(session) != 0)
{
session_delete(session);
return NULL;
}
return session;
}
/* session_delete */
void session_delete(Session * session)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
string_delete(session->name);
string_delete(session->profile);
config_delete(session->config);
object_delete(session);
}
/* AppInterface */
/* session_register */
int session_register(String const * interface, uint16_t port)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", %u)\n", __func__, interface, port);
#endif
/* FIXME not implemented yet */
return -1;
/* authenticate client */
/* check permissions */
/* verify conflicts */
/* register in the services list */
/* return 0; */
}
/* useful */
/* session_start */
int session_start(Session * session)
{
size_t i;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(_session_load(session) != 0)
return -1;
for(i = 0; i < session->services_cnt; i++)
if(service_start(session->services[i]) != 0)
/* we ignore the error because it gets monitored */
error_print(PACKAGE);
return 0;
}
/* session_stop */
int session_stop(Session * session)
{
size_t i;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
/* FIXME should wait until the last service has stopped */
/* FIXME again prone to race conditions */
for(i = 0; i < session->services_cnt; i++)
service_delete(session->services[i]);
session->services_cnt = 0;
return 0;
}
/* private */
/* session_get_config_services */
static StringArray * _session_get_config_services(Session * session)
{
String const * profile;
String const * services;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if((profile = session->profile) == NULL)
profile = config_get(session->config, NULL, "profile");
if((services = config_get(session->config, profile, "services"))
== NULL)
return NULL;
return string_explode(services, ",");
}
/* session_get_filename */
static String * _session_get_filename(Session * session)
{
char const * format = "%s/%s.%s";
String * p;
int size;
if(session->name == NULL)
{
error_set_code(1, "%s", strerror(EINVAL));
return NULL;
}
if((size = snprintf(NULL, 0, format, SESSIONDIR, session->name,
SESSIONEXT)) <= 0)
{
error_set_code(1, "%s", strerror(EINVAL));
return NULL;
}
if((p = object_new(++size)) == NULL) /* XXX string_new_format() ? */
return NULL;
snprintf(p, size, format, SESSIONDIR, session->name, SESSIONEXT);
return p;
}
/* useful */
static void _load_service_foreach(void * value, void * data);
static int _load_service(Session * session, String const * service);
static int _session_load(Session * session)
{
int ret;
String * filename;
StringArray * services;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(session->services_cnt != 0)
return error_set_code(1, "%s", "Session is already started");
/* lookup configuration file */
if((filename = _session_get_filename(session)) == NULL)
return -1;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() filename=\"%s\"\n", __func__, filename);
#endif
config_reset(session->config);
ret = config_load(session->config, filename);
string_delete(filename);
if(ret != 0)
return -1;
/* parse the services list */
if((services = _session_get_config_services(session)) == NULL)
return -1;
/* add the services */
array_foreach(services, _load_service_foreach, session);
array_foreach(services, (ArrayForeach)string_delete, NULL);
array_delete(services);
return 0;
}
static void _load_service_foreach(void * value, void * data)
{
String * service = value;
Session * session = data;
if(_load_service(session, service) != 0)
error_print(PACKAGE);
}
static int _load_service(Session * session, String const * service)
{
Service ** p;
size_t cnt = session->services_cnt;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, service);
#endif
if((p = realloc(session->services, sizeof(*p) * (cnt + 1))) == NULL)
return -error_set_code(1, "%s", strerror(errno));
session->services = p;
if((session->services[cnt] = service_new(service)) == NULL)
return -1;
session->services_cnt++;
return 0;
}