source: mainline/uspace/srv/sysman/connection_ctl.c@ 3529f148

Last change on this file since 3529f148 was 3529f148, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Adding types task_wait_flag_t and ipc_start_flag_t which replaces makros

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <ipc/sysman.h>
31#include <macros.h>
32#include <stdlib.h>
33#include <str.h>
34
35#include "repo.h"
36#include "connection_ctl.h"
37#include "job.h"
38#include "job_closure.h"
39#include "log.h"
40#include "shutdown.h"
41#include "sysman.h"
42
43// TODO possibly provide as type-safe function + macro in sysman.h for generic boxing
44static ipc_call_t *box_callid(ipc_call_t *icall)
45{
46 ipc_call_t *copy = malloc(sizeof(ipc_call_t));
47 if (copy) {
48 memcpy(copy, icall, sizeof(ipc_call_t));
49 }
50 return copy;
51}
52
53static void answer_callback(void *object, void *arg)
54{
55 job_t *job = object;
56 assert(job->state == JOB_FINISHED);
57 assert(job->retval != JOB_UNDEFINED_);
58
59 ipc_call_t *icall = arg;
60 // TODO use descriptive return value (probably refactor job retval)
61 sysarg_t retval = (job->retval == JOB_OK) ? EOK : EIO;
62 async_answer_0(icall, retval);
63 free(icall);
64 job_del_ref(&job);
65}
66
67static void sysman_unit_handle(ipc_call_t *icall)
68{
69 char *unit_name = NULL;
70 sysarg_t retval;
71
72 errno_t rc = async_data_write_accept((void **) &unit_name, true,
73 0, 0, 0, NULL);
74 if (rc != EOK) {
75 retval = rc;
76 goto fail;
77 }
78
79 unit_t *unit = repo_find_unit_by_name(unit_name);
80 if (unit == NULL) {
81 retval = ENOENT;
82 goto fail;
83 }
84
85 async_answer_1(icall, EOK, unit->handle);
86 goto finish;
87
88fail:
89 async_answer_0(icall, retval);
90finish:
91 free(unit_name);
92}
93
94static void sysman_unit_start_by_name(ipc_call_t *icall)
95{
96 char *unit_name = NULL;
97 sysarg_t retval;
98
99 errno_t rc = async_data_write_accept((void **) &unit_name, true,
100 0, 0, 0, NULL);
101 if (rc != EOK) {
102 retval = rc;
103 goto answer;
104 }
105
106 ipc_start_flag_t flags = ipc_get_arg1(icall);
107 sysman_log(LVL_DEBUG2, "%s(%s, %x)", __func__, unit_name, flags);
108
109 unit_t *unit = repo_find_unit_by_name(unit_name);
110 if (unit == NULL) {
111 sysman_log(LVL_NOTE, "Unit '%s' not found.", unit_name);
112 retval = ENOENT;
113 goto answer;
114 }
115
116 if (!(flags & IPC_FLAG_BLOCKING)) {
117 retval = sysman_run_job(unit, STATE_STARTED, 0, NULL, NULL);
118 goto answer;
119 }
120
121 ipc_call_t *icall_copy = box_callid(icall);
122 if (icall_copy == NULL) {
123 retval = ENOMEM;
124 goto answer;
125 }
126 retval = sysman_run_job(unit, STATE_STARTED, 0, &answer_callback,
127 icall_copy);
128 if (retval != EOK) {
129 goto answer;
130 }
131
132 /* Answer asynchronously from callback */
133 goto finish;
134
135answer:
136 async_answer_0(icall, retval);
137finish:
138 free(unit_name);
139}
140
141static void sysman_unit_operation(ipc_call_t *icall, unit_state_t state)
142{
143 sysarg_t retval;
144
145 unit_handle_t handle = ipc_get_arg1(icall);
146 ipc_start_flag_t flags = ipc_get_arg2(icall);
147 sysman_log(LVL_DEBUG2, "%s(%p, %u, %i)", __func__, icall->cap_handle, flags, state);
148
149 unit_t *unit = repo_find_unit_by_handle(handle);
150 if (unit == NULL) {
151 retval = ENOENT;
152 goto answer;
153 }
154
155 if (!(flags & IPC_FLAG_BLOCKING)) {
156 retval = sysman_run_job(unit, state, 0, NULL, NULL);
157 goto answer;
158 }
159
160 ipc_call_t *icall_copy = box_callid(icall);
161 if (icall_copy == NULL) {
162 retval = ENOMEM;
163 goto answer;
164 }
165 retval = sysman_run_job(unit, state, 0, &answer_callback,
166 icall_copy);
167 if (retval != EOK) {
168 goto answer;
169 }
170
171 /* Answer asynchronously from callback */
172 return;
173
174answer:
175 async_answer_0(icall, retval);
176}
177
178static void sysman_unit_start(ipc_call_t *icall)
179{
180 sysman_unit_operation(icall, STATE_STARTED);
181}
182
183static void sysman_unit_stop(ipc_call_t *icall)
184{
185 sysman_unit_operation(icall, STATE_STOPPED);
186}
187
188static errno_t fill_handles_buffer(unit_handle_t *buffer, size_t size,
189 size_t *act_size)
190{
191 if (size % sizeof(unit_handle_t) != 0) {
192 return EINVAL;
193 }
194
195 size_t filled = 0;
196 size_t to_fill = size / sizeof(unit_handle_t);
197 size_t total = 0;
198 repo_rlock();
199 repo_foreach(u) {
200 if (filled < to_fill) {
201 buffer[filled++] = u->handle;
202 }
203 ++total;
204 }
205 repo_runlock();
206 *act_size = total * sizeof(unit_handle_t);
207 return EOK;
208}
209
210static void sysman_get_units(ipc_call_t *icall)
211{
212 ipc_call_t call;
213 size_t size;
214 size_t act_size;
215 errno_t rc;
216
217 if (!async_data_read_receive(&call, &size)) {
218 async_answer_0(&call, EREFUSED);
219 async_answer_0(icall, EREFUSED);
220 return;
221 }
222
223 unit_handle_t *handles = malloc(size);
224 if (handles == NULL && size > 0) {
225 async_answer_0(&call, ENOMEM);
226 async_answer_0(icall, ENOMEM);
227 return;
228 }
229
230 rc = fill_handles_buffer(handles, size, &act_size);
231 if (rc != EOK) {
232 async_answer_0(&call, rc);
233 async_answer_0(icall, rc);
234 return;
235 }
236
237 size_t real_size = min(act_size, size);
238 sysarg_t retval = async_data_read_finalize(&call, handles, real_size);
239 free(handles);
240
241 async_answer_1(icall, retval, act_size);
242}
243
244static void sysman_unit_get_name(ipc_call_t *icall)
245{
246 ipc_call_t call;
247 size_t size;
248
249 if (!async_data_read_receive(&call, &size)) {
250 async_answer_0(&call, EREFUSED);
251 async_answer_0(icall, EREFUSED);
252 return;
253 }
254
255 unit_t *u = repo_find_unit_by_handle(ipc_get_arg1(icall));
256 if (u == NULL) {
257 async_answer_0(&call, ENOENT);
258 async_answer_0(icall, ENOENT);
259 return;
260 }
261
262 size_t real_size = min(str_size(u->name) + 1, size);
263 sysarg_t retval = async_data_read_finalize(&call, u->name, real_size);
264
265 async_answer_0(icall, retval);
266}
267
268static void sysman_unit_get_state(ipc_call_t *icall)
269{
270 unit_t *u = repo_find_unit_by_handle(ipc_get_arg1(icall));
271 if (u == NULL) {
272 async_answer_0(icall, ENOENT);
273 } else {
274 async_answer_1(icall, EOK, u->state);
275 }
276}
277
278static void sysman_shutdown(ipc_call_t *icall)
279{
280 errno_t retval;
281 unit_t *u = repo_find_unit_by_name(TARGET_SHUTDOWN);
282 if (u == NULL) {
283 retval = ENOENT;
284 goto finish;
285 }
286
287 retval = sysman_run_job(u, STATE_STARTED, CLOSURE_ISOLATE,
288 shutdown_cb, NULL);
289
290finish:
291 async_answer_0(icall, retval);
292}
293
294void sysman_connection_ctl(ipc_call_t *icall)
295{
296 sysman_log(LVL_DEBUG2, "%s", __func__);
297
298 while (true) {
299 ipc_call_t call;
300
301 if (!async_get_call(&call) || !ipc_get_imethod(&call)) {
302 /* Client disconnected */
303 break;
304 }
305
306 switch (ipc_get_imethod(&call)) {
307 case SYSMAN_CTL_UNIT_HANDLE:
308 sysman_unit_handle(&call);
309 break;
310 case SYSMAN_CTL_UNIT_START_BY_NAME:
311 sysman_unit_start_by_name(&call);
312 break;
313 case SYSMAN_CTL_UNIT_START:
314 sysman_unit_start(&call);
315 break;
316 case SYSMAN_CTL_UNIT_STOP:
317 sysman_unit_stop(&call);
318 break;
319 case SYSMAN_CTL_GET_UNITS:
320 sysman_get_units(&call);
321 break;
322 case SYSMAN_CTL_UNIT_GET_NAME:
323 sysman_unit_get_name(&call);
324 break;
325 case SYSMAN_CTL_UNIT_GET_STATE:
326 sysman_unit_get_state(&call);
327 break;
328 case SYSMAN_CTL_SHUTDOWN:
329 sysman_shutdown(&call);
330 break;
331 default:
332 async_answer_0(&call, ENOENT);
333 }
334 }
335}
Note: See TracBrowser for help on using the repository browser.