#include "wgtpkg-mustach.h"
#include "utils-json.h"
#include "wgt-json.h"
+#include "utils-systemd.h"
#include "wgtpkg-unit.h"
-#if !defined(SYSTEMD_UNITS_ROOT)
-# define SYSTEMD_UNITS_ROOT "/usr/local/lib/systemd"
-#endif
-
#if 0
#include <ctype.h>
#else
char cont; /* flag telling whether the line continues the previous one */
char nextcont; /* flag telling whether the line will continues the next one */
- cont = 0;
+ nextcont = 0;
c = *(write = read = text);
/* iteration over lines */
while (c) {
/* computes emit, nextcont, emit and start for the current line */
+ cont = nextcont;
emit = nextcont = 0;
start = NULL;
begin = read;
if (c)
c = *++read;
/* emit the line if not empty */
- if (emit) {
+ if (emit || (cont && !nextcont)) {
/* removes the blanks on the left of not continuing lines */
if (!cont && start)
begin = start;
*write++ = *begin++;
}
}
- cont = nextcont;
}
*write = 0;
return (size_t)(write - text);
*/
static int process_one_unit(char *spec, struct unitdesc *desc)
{
- char *nsoc, *nsrv, *name;
- int isuser, issystem, issock, isserv;
+ char *nsoc, *nsrv, *name, *wanted;
+ int isuser, issystem, issock, isserv, iswanted;
size_t len;
/* finds the configuration directive of the unit */
issystem = !!offset(spec, "%systemd-unit system\n", NULL);
issock = !!offset(spec, "%systemd-unit socket ", &nsoc);
isserv = !!offset(spec, "%systemd-unit service ", &nsrv);
+ iswanted = !!offset(spec, "%systemd-unit wanted-by ", &wanted);
/* check the unit scope */
if ((isuser + issystem) == 1) {
desc->name_length = 0;
}
+ if (iswanted) {
+ len = (size_t)(strchrnul(wanted, '\n') - wanted);
+ desc->wanted_by = strndup(wanted, len);
+ desc->wanted_by_length = len;
+ } else {
+ desc->wanted_by = NULL;
+ desc->wanted_by_length = 0;
+ }
+
desc->content = spec;
desc->content_length = pack(spec, '%');
* with its given 'closure' and the array descripbing the units.
* Return 0 in case of success or a negative value in case of error.
*/
-static int process_all_units(char *corpus, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure)
+static int process_all_units(char *corpus, const struct unitconf *conf, int (*process)(void *closure, const struct generatedesc *desc), void *closure)
{
- int rc, rc2;
- unsigned n;
+ int n, rc, rc2;
char *beg, *end;
- struct unitdesc *descs, *d;
+ struct unitdesc *units, *u;
+ struct generatedesc gdesc;
- descs = NULL;
+ units = NULL;
n = 0;
rc = rc2 = 0;
*end = 0;
/* allocates a descriptor for the unit */
- d = realloc(descs, (n + 1) * sizeof *descs);
- if (d == NULL)
+ u = realloc(units, ((unsigned)n + 1) * sizeof *units);
+ if (u == NULL)
rc2 = -ENOMEM;
else {
/* creates the unit description */
- memset(&d[n], 0, sizeof *d);
- descs = d;
- rc2 = process_one_unit(beg, &descs[n]);
+ units = u;
+ u = &u[n];
+ memset(u, 0, sizeof *u);
+ rc2 = process_one_unit(beg, u);
if (rc2 >= 0)
n++;
}
}
/* call the function that processes the units */
- if (rc == 0 && process)
- rc = process(closure, descs, n);
+ if (rc == 0 && process) {
+ gdesc.conf = conf;
+ gdesc.units = units;
+ gdesc.nunits = n;
+ rc = process(closure, &gdesc);
+ }
/* cleanup and frees */
- while(n)
- free((char *)(descs[--n].name));
- free(descs);
+ while(n) {
+ free((char *)(units[--n].name));
+ free((char *)(units[n].wanted_by));
+ }
+ free(units);
return rc;
}
return rc;
}
+static int add_metadata(struct json_object *jdesc, const struct unitconf *conf)
+{
+ char portstr[30];
+
+ sprintf(portstr, "%d", conf->port);
+ return j_add_many_strings_m(jdesc,
+ "#metadata.install-dir", conf->installdir,
+ "#metadata.app-data-dir", "%h/app-data",
+ "#metadata.icons-dir", conf->icondir,
+ "#metadata.http-port", portstr,
+ NULL) ? 0 : -1;
+}
+
/*
- * Applies the object 'jdesc' to the current unit generator.
+ * Applies the object 'jdesc' augmented of meta data coming
+ * from 'conf' to the current unit generator.
* The current unit generator will be set to the default one if not unit
* was previously set using the function 'unit_generator_on'.
* The callback function 'process' is then called with the
* Return what returned process in case of success or a negative
* error code.
*/
-int unit_generator_process(struct json_object *jdesc, int (*process)(void *closure, const struct unitdesc descs[], unsigned count), void *closure)
+int unit_generator_process(struct json_object *jdesc, const struct unitconf *conf, int (*process)(void *closure, const struct generatedesc *desc), void *closure)
{
int rc;
size_t size;
char *instance;
- rc = template ? 0 : unit_generator_on(NULL);
- if (!rc) {
- instance = NULL;
- rc = apply_mustach(template, jdesc, &instance, &size);
- if (!rc)
- rc = process_all_units(instance, process, closure);
- free(instance);
+ rc = add_metadata(jdesc, conf);
+ if (rc)
+ ERROR("can't set the metadata. %m");
+ else {
+ rc = template ? 0 : unit_generator_on(NULL);
+ if (!rc) {
+ instance = NULL;
+ rc = apply_mustach(template, jdesc, &instance, &size);
+ if (!rc)
+ rc = process_all_units(instance, conf, process, closure);
+ free(instance);
+ }
}
return rc;
}
/**************** SPECIALIZED PART *****************************/
-
-static int get_unit_path(char *path, size_t pathlen, const struct unitdesc *desc)
+static int check_unit_desc(const struct unitdesc *desc, int tells)
{
- int rc;
+ if (desc->scope != unitscope_unknown && desc->type != unittype_unknown && desc->name != NULL)
+ return 0;
- if (desc->scope == unitscope_unknown || desc->type == unittype_unknown || desc->name == NULL) {
+ if (tells) {
if (desc->scope == unitscope_unknown)
ERROR("unit of unknown scope");
if (desc->type == unittype_unknown)
ERROR("unit of unknown type");
if (desc->name == NULL)
ERROR("unit of unknown name");
- errno = EINVAL;
- rc = -1;
- }
- else {
- rc = snprintf(path, pathlen, "%s/%s/%s.%s",
- SYSTEMD_UNITS_ROOT,
- desc->scope == unitscope_system ? "system" : "user",
- desc->name,
- desc->type == unittype_socket ? "socket" : "service");
-
- if (rc >= 0 && (size_t)rc >= pathlen) {
- ERROR("can't set the unit name");
- errno = EINVAL;
- rc = -1;
- }
}
+ errno = EINVAL;
+ return -1;
+}
+
+static int get_unit_path(char *path, size_t pathlen, const struct unitdesc *desc)
+{
+ int rc = systemd_get_unit_path(
+ path, pathlen, desc->scope == unitscope_user,
+ desc->name, desc->type == unittype_socket ? "socket" : "service");
+
+ if (rc < 0)
+ ERROR("can't get the unit path for %s", desc->name);
+
return rc;
}
-static int do_install_units(void *closure, const struct unitdesc descs[], unsigned count)
+static int get_wants_path(char *path, size_t pathlen, const struct unitdesc *desc)
{
- int rc;
- unsigned i;
- char path[PATH_MAX + 1];
+ int rc = systemd_get_wants_path(
+ path, pathlen, desc->scope == unitscope_user, desc->wanted_by,
+ desc->name, desc->type == unittype_socket ? "socket" : "service");
- for (i = 0 ; i < count ; i++) {
- rc = get_unit_path(path, sizeof path, &descs[i]);
- if (rc >= 0) {
- rc = putfile(path, descs[i].content, descs[i].content_length);
+ if (rc < 0)
+ ERROR("can't get the wants path for %s and %s", desc->name, desc->wanted_by);
+
+ return rc;
+}
+
+static int get_wants_target(char *path, size_t pathlen, const struct unitdesc *desc)
+{
+ int rc = systemd_get_wants_target(
+ path, pathlen,
+ desc->name, desc->type == unittype_socket ? "socket" : "service");
+
+ if (rc < 0)
+ ERROR("can't get the wants target for %s", desc->name);
+
+ return rc;
+}
+
+static int do_send_reload(const struct generatedesc *desc)
+{
+ int i;
+ int reloadsys, reloadusr;
+ const struct unitdesc *u;
+
+ reloadsys = reloadusr = 0;
+ for (i = 0 ; i < desc->nunits ; i++) {
+ u = &desc->units[i];
+ if (u->wanted_by != NULL) {
+ switch (u->scope) {
+ case unitscope_user:
+ reloadusr = 1;
+ break;
+ case unitscope_system:
+ reloadsys = 1;
+ break;
+ default:
+ break;
+ }
}
}
- return 0;
+
+ if (reloadusr)
+ reloadusr = systemd_daemon_reload(1);
+ if (reloadsys)
+ reloadsys = systemd_daemon_reload(0);
+ return reloadsys ? : reloadusr ? : 0;
}
-static int do_uninstall_units(void *closure, const struct unitdesc descs[], unsigned count)
+static int do_uninstall_units(void *closure, const struct generatedesc *desc)
{
- int rc;
- unsigned i;
+ int rc, rc2;
+ int i;
char path[PATH_MAX];
-
- for (i = 0 ; i < count ; i++) {
- rc = get_unit_path(path, sizeof path, &descs[i]);
- if (rc >= 0) {
- rc = unlink(path);
+ const struct unitdesc *u;
+
+ rc = 0;
+ for (i = 0 ; i < desc->nunits ; i++) {
+ u = &desc->units[i];
+ rc2 = check_unit_desc(u, 0);
+ if (rc2 == 0) {
+ rc2 = get_unit_path(path, sizeof path, u);
+ if (rc2 >= 0) {
+ rc2 = unlink(path);
+ }
+ if (rc2 < 0 && rc == 0)
+ rc = rc2;
+ if (u->wanted_by != NULL) {
+ rc2 = get_wants_path(path, sizeof path, u);
+ if (rc2 >= 0)
+ rc2 = unlink(path);
+ }
}
+ if (rc2 < 0 && rc == 0)
+ rc = rc2;
}
- return 0;
+ rc2 = do_send_reload(desc);
+ if (rc2 < 0 && rc == 0)
+ rc = rc2;
+ return rc;
}
-static int add_metadata(struct json_object *jdesc, const char *installdir, const char *icondir, int port)
+static int do_install_units(void *closure, const struct generatedesc *desc)
{
- char portstr[30];
-
- sprintf(portstr, "%d", port);
- return j_add_many_strings_m(jdesc,
- "#metadata.install-dir", installdir,
- "#metadata.app-data-dir", "%h/app-data",
- "#metadata.icons-dir", icondir,
- "#metadata.http-port", portstr,
- NULL) ? 0 : -1;
+ int rc;
+ int i;
+ char path[PATH_MAX + 1], target[PATH_MAX + 1];
+ const struct unitdesc *u;
+
+ i = 0;
+ while (i < desc->nunits) {
+ u = &desc->units[i];
+ rc = check_unit_desc(u, 1);
+ if (!rc) {
+ rc = get_unit_path(path, sizeof path, u);
+ if (rc >= 0) {
+ rc = putfile(path, u->content, u->content_length);
+ if (rc >= 0 && u->wanted_by != NULL) {
+ rc = get_wants_path(path, sizeof path, u);
+ if (rc >= 0) {
+ rc = get_wants_target(target, sizeof target, u);
+ if (rc >= 0) {
+ unlink(path); /* TODO? check? */
+ rc = symlink(target, path);
+ }
+ }
+ }
+ i++;
+ }
+ }
+ if (rc < 0)
+ goto error;
+ }
+ rc = do_send_reload(desc);
+ if (rc < 0)
+ goto error;
+ return 0;
+error:
+ i = errno;
+ do_uninstall_units(closure, desc);
+ errno = i;
+ return rc;
}
static int do_install_uninstall(
struct wgt_info *ifo,
- const char *installdir,
- const char *icondir,
- int port,
- int (*doer)(void *, const struct unitdesc[], unsigned)
+ const struct unitconf *conf,
+ int (*doer)(void *, const struct generatedesc *)
)
{
int rc;
if (!jdesc)
rc = -1;
else {
- rc = add_metadata(jdesc, installdir, icondir, port);
- if (rc)
- ERROR("can't set the metadata. %m");
- else {
- rc = unit_generator_process(jdesc, doer, NULL);
- if (rc)
- ERROR("can't install units, error %d", rc);
- }
+ rc = unit_generator_process(jdesc, conf, doer, NULL);
json_object_put(jdesc);
}
return rc;
}
-int unit_install(struct wgt_info *ifo, const char *installdir, const char *icondir, int port)
+int unit_install(struct wgt_info *ifo, const struct unitconf *conf)
{
- return do_install_uninstall(ifo, installdir, icondir, port, do_install_units);
+ return do_install_uninstall(ifo, conf, do_install_units);
}
-int unit_uninstall(struct wgt_info *ifo)
+int unit_uninstall(struct wgt_info *ifo, const struct unitconf *conf)
{
- return do_install_uninstall(ifo, "", "", 0, do_uninstall_units);
+ return do_install_uninstall(ifo, conf, do_uninstall_units);
}