/*
- Copyright 2015, 2016, 2017 IoT.bzh
+ Copyright (C) 2015-2019 IoT.bzh
author: José Bollo <jose.bollo@iot.bzh>
#include "afm-udb.h"
#include "afm-urun.h"
+static const char key_unit_d_path[] = "-unit-dpath-";
+
/**************** get appli basis *********************/
-static int get_basis(struct json_object *appli, int *isuser, const char **dpath, int load)
+static int get_basis(struct json_object *appli, int *isuser, const char **dpath, int uid)
{
- char *dp;
+ char userid[40];
+ char *dp, *arodot, *nun;
const char *uname, *uscope;
+ struct json_object *odp;
+ int rc;
/* get the scope */
if (!j_read_string_at(appli, "unit-scope", &uscope)) {
}
*isuser = strcmp(uscope, "system") != 0;
- /* get dpath */
- if (!j_read_string_at(appli, "-unit-dpath-", dpath)) {
- if (!load) {
- errno = ENOENT;
- goto error;
+ /* get dpaths of known users */
+ odp = NULL;
+ if (json_object_object_get_ex(appli, key_unit_d_path, &odp)) {
+ /* try not parametric dpath */
+ if (json_object_get_type(odp) == json_type_string) {
+ *dpath = json_object_get_string(odp);
+ return 0;
}
- if (!j_read_string_at(appli, "unit-name", &uname)) {
- ERROR("'unit-name' missing in appli description %s", json_object_get_string(appli));
+ assert(json_object_get_type(odp) == json_type_object);
+ /* get userid */
+ if (uid < 0) {
+ ERROR("unexpected uid %d", uid);
goto inval;
}
+ rc = snprintf(userid, sizeof userid, "%d", uid);
+ assert(rc < (int)(sizeof userid));
+ /* try dpath for the user */
+ if (j_read_string_at(odp, userid, dpath))
+ return 0;
+ }
+
+ /* get uname */
+ if (!j_read_string_at(appli, "unit-name", &uname)) {
+ ERROR("'unit-name' missing in appli description %s", json_object_get_string(appli));
+ goto inval;
+ }
+
+ /* is user parametric? */
+ arodot = strchr(uname, '@');
+ if (arodot && *++arodot == '.') {
+ if (!odp) {
+ /* get userid */
+ if (uid < 0) {
+ ERROR("unexpected uid %d", uid);
+ goto inval;
+ }
+ rc = snprintf(userid, sizeof userid, "%d", uid);
+ assert(rc < (int)(sizeof userid));
+
+ /* create the dpaths of known users */
+ odp = json_object_new_object();
+ if (!odp)
+ goto nomem;
+ json_object_object_add(appli, key_unit_d_path, odp);
+ }
+
+ /* get dpath of userid */
+ nun = alloca((size_t)(arodot - uname) + strlen(userid) + strlen(arodot) + 1);
+ stpcpy(stpcpy(stpncpy(nun, uname, (size_t)(arodot - uname)), userid), arodot);
+ dp = systemd_unit_dpath_by_name(*isuser, nun, 1);
+ if (dp == NULL) {
+ ERROR("Can't load unit of name %s for %s: %m", nun, uscope);
+ goto error;
+ }
+ /* record the dpath */
+ if (!j_add_string(odp, userid, dp)) {
+ free(dp);
+ goto nomem;
+ }
+ free(dp);
+ j_read_string_at(odp, userid, dpath);
+ } else {
+ /* get dpath */
dp = systemd_unit_dpath_by_name(*isuser, uname, 1);
if (dp == NULL) {
ERROR("Can't load unit of name %s for %s: %m", uname, uscope);
goto error;
}
- if (!j_add_string(appli, "-unit-dpath-", dp)) {
+ /* record the dpath */
+ if (!j_add_string(appli, key_unit_d_path, dp)) {
free(dp);
goto nomem;
}
free(dp);
- j_read_string_at(appli, "-unit-dpath-", dpath);
+ j_read_string_at(appli, key_unit_d_path, dpath);
}
-
return 0;
nomem:
*
* Returns the runid in case of success or -1 in case of error
*/
-int afm_urun_start(struct json_object *appli)
+int afm_urun_start(struct json_object *appli, int uid)
{
- return afm_urun_once(appli);
+ return afm_urun_once(appli, uid);
}
/*
*
* Returns the runid in case of success or -1 in case of error
*/
-int afm_urun_once(struct json_object *appli)
+int afm_urun_once(struct json_object *appli, int uid)
{
const char *udpath, *state, *uscope, *uname;
int rc, isuser;
/* retrieve basis */
- rc = get_basis(appli, &isuser, &udpath, 1);
+ rc = get_basis(appli, &isuser, &udpath, uid);
if (rc < 0)
goto error;
if (rc < 0) {
j_read_string_at(appli, "unit-scope", &uscope);
j_read_string_at(appli, "unit-name", &uname);
- ERROR("can't start %s unit %s", uscope, uname);
+ ERROR("can't start %s unit %s for uid %d", uscope, uname, uid);
goto error;
}
if (state == NULL) {
j_read_string_at(appli, "unit-scope", &uscope);
j_read_string_at(appli, "unit-name", &uname);
- ERROR("can't wait %s unit %s: %m", uscope, uname);
+ ERROR("can't wait %s unit %s for uid %d: %m", uscope, uname, uid);
goto error;
}
if (state != SysD_State_Active) {
j_read_string_at(appli, "unit-scope", &uscope);
j_read_string_at(appli, "unit-name", &uname);
- ERROR("start error %s unit %s: %s", uscope, uname, state);
+ ERROR("start error %s unit %s for uid %d: %s", uscope, uname, uid, state);
goto error;
}
rc = systemd_unit_pid_of_dpath(isuser, udpath);
- if (rc < 0) {
+ if (rc <= 0) {
j_read_string_at(appli, "unit-scope", &uscope);
j_read_string_at(appli, "unit-name", &uname);
- ERROR("can't getpid of %s unit %s: %m", uscope, uname);
+ ERROR("can't getpid of %s unit %s for uid %d: %m", uscope, uname, uid);
goto error;
}
-
+
return rc;
error:
*
* Returns 0 in case of success or -1 in case of error
*/
-int afm_urun_terminate(int runid)
+int afm_urun_terminate(int runid, int uid)
{
int rc = systemd_unit_stop_pid(1 /* TODO: isuser? */, (unsigned)runid);
+ if (rc < 0)
+ rc = systemd_unit_stop_pid(0 /* TODO: isuser? */, (unsigned)runid);
return rc < 0 ? rc : 0;
}
*
* Returns 0 in case of success or -1 in case of error
*/
-int afm_urun_pause(int runid)
+int afm_urun_pause(int runid, int uid)
{
return not_yet_implemented("pause");
}
*
* Returns 0 in case of success or -1 in case of error
*/
-int afm_urun_resume(int runid)
+int afm_urun_resume(int runid, int uid)
{
return not_yet_implemented("resume");
}
*
* Returns the list or NULL in case of error.
*/
-struct json_object *afm_urun_list(struct afm_udb *db)
+struct json_object *afm_urun_list(struct afm_udb *db, int all, int uid)
{
int i, n, isuser, pid;
const char *udpath;
if (result == NULL)
goto error;
- apps = afm_udb_applications_private(db);
+ apps = afm_udb_applications_private(db, all, uid);
n = json_object_array_length(apps);
for (i = 0 ; i < n ; i++) {
appli = json_object_array_get_idx(apps, i);
- if (appli && get_basis(appli, &isuser, &udpath, 0) >= 0) {
+ if (appli && get_basis(appli, &isuser, &udpath, uid) >= 0) {
pid = systemd_unit_pid_of_dpath(isuser, udpath);
if (pid > 0 && j_read_string_at(appli, "id", &id)) {
state = systemd_unit_state_of_dpath(isuser, udpath);
- desc = mkstate(id, pid, pid, state);
- if (desc && json_object_array_add(result, desc) == -1) {
- ERROR("can't add desc %s to result", json_object_get_string(desc));
- json_object_put(desc);
+ if (state == SysD_State_Active) {
+ desc = mkstate(id, pid, pid, state);
+ if (desc && json_object_array_add(result, desc) == -1) {
+ ERROR("can't add desc %s to result", json_object_get_string(desc));
+ json_object_put(desc);
+ }
}
}
}
*
* Returns the state or NULL in case of success
*/
-struct json_object *afm_urun_state(struct afm_udb *db, int runid)
+struct json_object *afm_urun_state(struct afm_udb *db, int runid, int uid)
{
- int i, n, isuser, pid;
+ int i, n, isuser, pid, wasuser;
char *dpath;
const char *udpath;
const char *id;
result = NULL;
/* get the dpath */
- dpath = systemd_unit_dpath_by_pid(1 /* TODO: isuser? */, (unsigned)runid);
+ dpath = systemd_unit_dpath_by_pid(wasuser = 1, (unsigned)runid);
+ if (!dpath)
+ dpath = systemd_unit_dpath_by_pid(wasuser = 0, (unsigned)runid);
if (!dpath) {
- result = NULL;
errno = EINVAL;
WARNING("searched runid %d not found", runid);
} else {
/* search in the base */
- apps = afm_udb_applications_private(db);
+ apps = afm_udb_applications_private(db, 1, uid);
n = json_object_array_length(apps);
for (i = 0 ; i < n ; i++) {
appli = json_object_array_get_idx(apps, i);
if (appli
- && get_basis(appli, &isuser, &udpath, 0) >= 0
+ && get_basis(appli, &isuser, &udpath, uid) >= 0
&& !strcmp(dpath, udpath)
&& j_read_string_at(appli, "id", &id)) {
pid = systemd_unit_pid_of_dpath(isuser, udpath);
state = systemd_unit_state_of_dpath(isuser, dpath);
- result = mkstate(id, runid, pid, state);
+ if (pid > 0 && state == SysD_State_Active)
+ result = mkstate(id, runid, pid, state);
goto end;
}
}
- result = NULL;
errno = ENOENT;
WARNING("searched runid %d of dpath %s isn't an applications", runid, dpath);
end:
json_object_put(apps);
- free(dpath);
+ free(dpath);
}
return result;
}
+/*
+ * Search the runid, if any, of the application of 'id' for the user 'uid'.
+ * Returns the pid (a positive not null number) or -1 in case of error.
+ */
+int afm_urun_search_runid(struct afm_udb *db, const char *id, int uid)
+{
+ int isuser, pid;
+ const char *udpath;
+ struct json_object *appli;
+
+ appli = afm_udb_get_application_private(db, id, uid);
+ if (!appli) {
+ NOTICE("Unknown appid %s", id);
+ errno = ENOENT;
+ pid = -1;
+ } else if (get_basis(appli, &isuser, &udpath, uid) < 0) {
+ pid = -1;
+ } else {
+ pid = systemd_unit_pid_of_dpath(isuser, udpath);
+ if (pid == 0) {
+ errno = ESRCH;
+ pid = -1;
+ }
+ }
+ return pid;
+}
+