X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafm-urun.c;h=051ce7e19b01354da00339f6da907babe9ccc8f8;hb=f8f2338aba84394e132fff55b6ebdef7d884292b;hp=d6185c889d4198a599191816b47c3958dae17c5c;hpb=51a86fcd6e4f199009888b5a106bf472f1b7c742;p=src%2Fapp-framework-main.git diff --git a/src/afm-urun.c b/src/afm-urun.c index d6185c8..051ce7e 100644 --- a/src/afm-urun.c +++ b/src/afm-urun.c @@ -1,5 +1,5 @@ /* - Copyright 2015, 2016, 2017 IoT.bzh + Copyright (C) 2015-2020 IoT.bzh author: José Bollo @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -36,12 +37,17 @@ #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)) { @@ -50,29 +56,82 @@ static int get_basis(struct json_object *appli, int *isuser, const char **dpath, } *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: @@ -86,17 +145,31 @@ error: return -1; } -static const char *wait_state_stable(int isuser, const char *dpath) +static enum SysD_State wait_state_stable(int isuser, const char *dpath) { - const char *state; - - for (;;) { + int trial; + enum SysD_State state = SysD_State_INVALID; + struct timespec tispec; + const int period_ms = 10; + const int trial_s = 10; + const int trial_count = (trial_s * 1000) / period_ms; + const int period_ns = period_ms * 1000000; + + for (trial = 1 ; trial <= trial_count ; trial++) { state = systemd_unit_state_of_dpath(isuser, dpath); - if (state == NULL || state == SysD_State_Active - || state == SysD_State_Failed) + switch (state) { + case SysD_State_Active: + case SysD_State_Failed: + case SysD_State_Inactive: return state; - /* TODO: sleep */ + default: + tispec.tv_sec = 0; + tispec.tv_nsec = period_ns; + nanosleep(&tispec, NULL); + break; + } } + return state; } /* @@ -108,7 +181,7 @@ static const char *wait_state_stable(int isuser, const char *dpath) * * Returns the created object or NULL in case of error. */ -static json_object *mkstate(const char *id, int runid, int pid, const char *state) +static json_object *mkstate(const char *id, int runid, int pid, enum SysD_State state) { struct json_object *result, *pids; @@ -160,9 +233,9 @@ error: * * 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); } /* @@ -176,13 +249,14 @@ int afm_urun_start(struct json_object *appli) * * 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; + const char *udpath, *uscope, *uname; + enum SysD_State state; int rc, isuser; /* retrieve basis */ - rc = get_basis(appli, &isuser, &udpath, 1); + rc = get_basis(appli, &isuser, &udpath, uid); if (rc < 0) goto error; @@ -191,21 +265,25 @@ int afm_urun_once(struct json_object *appli) 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; } state = wait_state_stable(isuser, udpath); - if (state == NULL) { + switch (state) { + case SysD_State_Active: + case SysD_State_Inactive: + break; + case SysD_State_Failed: 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("start error %s unit %s for uid %d: %s", uscope, uname, uid, + systemd_state_name(state)); goto error; - } - if (state != SysD_State_Active) { + default: 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("can't wait %s unit %s for uid %d: %m", uscope, uname, uid); goto error; } @@ -213,10 +291,10 @@ int afm_urun_once(struct json_object *appli) 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 get pid of %s unit %s for uid %d: %m", uscope, uname, uid); goto error; } - + return rc; error: @@ -235,9 +313,11 @@ static int not_yet_implemented(const char *what) * * 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; } @@ -246,7 +326,7 @@ int afm_urun_terminate(int runid) * * 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"); } @@ -256,7 +336,7 @@ int afm_urun_pause(int runid) * * 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"); } @@ -266,12 +346,12 @@ int afm_urun_resume(int runid) * * 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; const char *id; - const char *state; + enum SysD_State state; struct json_object *desc; struct json_object *appli; struct json_object *apps; @@ -282,18 +362,20 @@ struct json_object *afm_urun_list(struct afm_udb *db) 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); + } } } } @@ -309,13 +391,13 @@ error: * * 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; - const char *state; + enum SysD_State state; struct json_object *appli; struct json_object *apps; struct json_object *result; @@ -323,35 +405,63 @@ struct json_object *afm_urun_state(struct afm_udb *db, int runid) 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; +} +