2 Copyright 2015, 2016, 2017 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
23 #include <sys/types.h>
30 #include <json-c/json.h>
33 #include "utils-dir.h"
34 #include "utils-json.h"
35 #include "utils-systemd.h"
39 static const char key_unit_d_path[] = "-unit-dpath-";
41 /**************** get appli basis *********************/
43 static int get_basis(struct json_object *appli, int *isuser, const char **dpath, int load)
46 const char *uname, *uscope;
49 if (!j_read_string_at(appli, "unit-scope", &uscope)) {
50 ERROR("'unit-scope' missing in appli description %s", json_object_get_string(appli));
53 *isuser = strcmp(uscope, "system") != 0;
56 if (!j_read_string_at(appli, key_unit_d_path, dpath)) {
61 if (!j_read_string_at(appli, "unit-name", &uname)) {
62 ERROR("'unit-name' missing in appli description %s", json_object_get_string(appli));
65 dp = systemd_unit_dpath_by_name(*isuser, uname, 1);
67 ERROR("Can't load unit of name %s for %s: %m", uname, uscope);
70 if (!j_add_string(appli, key_unit_d_path, dp)) {
75 j_read_string_at(appli, key_unit_d_path, dpath);
81 ERROR("out of memory");
91 static const char *wait_state_stable(int isuser, const char *dpath)
96 state = systemd_unit_state_of_dpath(isuser, dpath);
97 if (state == NULL || state == SysD_State_Active
98 || state == SysD_State_Failed)
105 * Creates a json object that describes the state for:
106 * - 'id', the id of the application
107 * - 'runid', its runid
109 * - 'state', its systemd state
111 * Returns the created object or NULL in case of error.
113 static json_object *mkstate(const char *id, int runid, int pid, const char *state)
115 struct json_object *result, *pids;
118 result = json_object_new_object();
123 if (!j_add_integer(result, "runid", runid))
128 pids = j_add_new_array(result, "pids");
131 if (!j_add_integer(pids, NULL, pid))
136 if (!j_add_string(result, "state", state == SysD_State_Active ? "running" : "terminated"))
139 /* the application id */
140 if (!j_add_string(result, "id", id))
147 json_object_put(result);
152 /**************** API handling ************************/
155 * Starts the application described by 'appli' for the 'mode'.
156 * In case of remote start, it returns in uri the uri to
159 * A reference to 'appli' is kept during the live of the
160 * runner. This is made using json_object_get. Thus be aware
161 * that further modifications to 'appli' might create errors.
163 * Returns the runid in case of success or -1 in case of error
165 int afm_urun_start(struct json_object *appli)
167 return afm_urun_once(appli);
171 * Returns the runid of a previously started application 'appli'
172 * or if none is running, starts the application described by 'appli'
175 * A reference to 'appli' is kept during the live of the
176 * runner. This is made using json_object_get. Thus be aware
177 * that further modifications to 'appli' might create errors.
179 * Returns the runid in case of success or -1 in case of error
181 int afm_urun_once(struct json_object *appli)
183 const char *udpath, *state, *uscope, *uname;
187 rc = get_basis(appli, &isuser, &udpath, 1);
192 rc = systemd_unit_start_dpath(isuser, udpath);
194 j_read_string_at(appli, "unit-scope", &uscope);
195 j_read_string_at(appli, "unit-name", &uname);
196 ERROR("can't start %s unit %s", uscope, uname);
200 state = wait_state_stable(isuser, udpath);
202 j_read_string_at(appli, "unit-scope", &uscope);
203 j_read_string_at(appli, "unit-name", &uname);
204 ERROR("can't wait %s unit %s: %m", uscope, uname);
207 if (state != SysD_State_Active) {
208 j_read_string_at(appli, "unit-scope", &uscope);
209 j_read_string_at(appli, "unit-name", &uname);
210 ERROR("start error %s unit %s: %s", uscope, uname, state);
214 rc = systemd_unit_pid_of_dpath(isuser, udpath);
216 j_read_string_at(appli, "unit-scope", &uscope);
217 j_read_string_at(appli, "unit-name", &uname);
218 ERROR("can't getpid of %s unit %s: %m", uscope, uname);
228 static int not_yet_implemented(const char *what)
230 ERROR("%s isn't yet implemented", what);
236 * Terminates the runner of 'runid'
238 * Returns 0 in case of success or -1 in case of error
240 int afm_urun_terminate(int runid)
242 int rc = systemd_unit_stop_pid(1 /* TODO: isuser? */, (unsigned)runid);
244 rc = systemd_unit_stop_pid(0 /* TODO: isuser? */, (unsigned)runid);
245 return rc < 0 ? rc : 0;
249 * Stops (aka pause) the runner of 'runid'
251 * Returns 0 in case of success or -1 in case of error
253 int afm_urun_pause(int runid)
255 return not_yet_implemented("pause");
259 * Continue (aka resume) the runner of 'runid'
261 * Returns 0 in case of success or -1 in case of error
263 int afm_urun_resume(int runid)
265 return not_yet_implemented("resume");
269 * Get the list of the runners.
271 * Returns the list or NULL in case of error.
273 struct json_object *afm_urun_list(struct afm_udb *db)
275 int i, n, isuser, pid;
279 struct json_object *desc;
280 struct json_object *appli;
281 struct json_object *apps;
282 struct json_object *result;
285 result = json_object_new_array();
289 apps = afm_udb_applications_private(db);
290 n = json_object_array_length(apps);
291 for (i = 0 ; i < n ; i++) {
292 appli = json_object_array_get_idx(apps, i);
293 if (appli && get_basis(appli, &isuser, &udpath, 0) >= 0) {
294 pid = systemd_unit_pid_of_dpath(isuser, udpath);
295 if (pid > 0 && j_read_string_at(appli, "id", &id)) {
296 state = systemd_unit_state_of_dpath(isuser, udpath);
297 if (state == SysD_State_Active) {
298 desc = mkstate(id, pid, pid, state);
299 if (desc && json_object_array_add(result, desc) == -1) {
300 ERROR("can't add desc %s to result", json_object_get_string(desc));
301 json_object_put(desc);
309 json_object_put(apps);
314 * Get the state of the runner of 'runid'.
316 * Returns the state or NULL in case of success
318 struct json_object *afm_urun_state(struct afm_udb *db, int runid)
320 int i, n, isuser, pid, wasuser;
325 struct json_object *appli;
326 struct json_object *apps;
327 struct json_object *result;
332 dpath = systemd_unit_dpath_by_pid(wasuser = 1, (unsigned)runid);
334 dpath = systemd_unit_dpath_by_pid(wasuser = 0, (unsigned)runid);
337 WARNING("searched runid %d not found", runid);
339 /* search in the base */
340 apps = afm_udb_applications_private(db);
341 n = json_object_array_length(apps);
342 for (i = 0 ; i < n ; i++) {
343 appli = json_object_array_get_idx(apps, i);
345 && get_basis(appli, &isuser, &udpath, 0) >= 0
346 && !strcmp(dpath, udpath)
347 && j_read_string_at(appli, "id", &id)) {
348 pid = systemd_unit_pid_of_dpath(isuser, udpath);
349 state = systemd_unit_state_of_dpath(isuser, dpath);
350 if (state == SysD_State_Active)
351 result = mkstate(id, runid, pid, state);
356 WARNING("searched runid %d of dpath %s isn't an applications", runid, dpath);
358 json_object_put(apps);