source: mainline/uspace/srv/sysman/main.c@ 73f7c4e

Last change on this file since 73f7c4e was 73f7c4e, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Create tests for job control

  • units are mocked by patching virtual methods table
  • sysman_process_queue to enforce emptying event queue

Conflicts:

.bzrignore
boot/Makefile.common

  • Property mode set to 100644
File size: 6.2 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 <async.h>
30#include <errno.h>
31#include <fibril.h>
32#include <ipc/sysman.h>
33#include <macros.h>
34#include <ns.h>
35#include <stddef.h>
36#include <stdio.h>
37#include <str.h>
38
39#include "configuration.h"
40#include "connection_broker.h"
41#include "connection_ctl.h"
42#include "dep.h"
43#include "job.h"
44#include "log.h"
45#include "sysman.h"
46#include "unit.h"
47
48#define NAME "sysman"
49
50#define INITRD_DEVICE "bd/initrd"
51#define INITRD_MOUNT_POINT "/"
52#define INITRD_CFG_PATH "/cfg/sysman"
53
54#define TARGET_INIT "initrd.tgt"
55#define TARGET_ROOTFS "rootfs.tgt"
56#define TARGET_DEFAULT "default.tgt"
57
58#define UNIT_MNT_INITRD "initrd.mnt"
59#define UNIT_CFG_INITRD "init.cfg"
60
61
62static const char *target_sequence[] = {
63 TARGET_INIT,
64 TARGET_ROOTFS,
65 TARGET_DEFAULT,
66 NULL
67};
68
69/*
70 * Forward declarations
71 */
72static void prepare_and_run_job(const char **target_name_ptr);
73
74/*
75 * Static functions
76 */
77
78static void sysman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
79{
80 sysman_interface_t iface = IPC_GET_ARG1(*icall);
81 switch (iface) {
82 case SYSMAN_PORT_BROKER:
83 sysman_connection_broker(iid, icall);
84 break;
85 case SYSMAN_PORT_CTL:
86 sysman_connection_ctl(iid, icall);
87 break;
88 default:
89 /* Unknown interface */
90 async_answer_0(iid, ENOENT);
91 }
92}
93
94/** Build hard coded configuration */
95static int create_entry_configuration(void) {
96 int rc;
97 unit_t *mnt_initrd = NULL;
98 unit_t *cfg_init = NULL;
99 unit_t *tgt_init = NULL;
100
101 mnt_initrd = unit_create(UNIT_MOUNT);
102 if (mnt_initrd == NULL) {
103 rc = ENOMEM;
104 goto fail;
105 }
106 mnt_initrd->name = str_dup(UNIT_MNT_INITRD);
107 CAST_MNT(mnt_initrd)->type = str_dup(STRING(RDFMT));
108 CAST_MNT(mnt_initrd)->mountpoint = str_dup(INITRD_MOUNT_POINT);
109 CAST_MNT(mnt_initrd)->device = str_dup(INITRD_DEVICE);
110 CAST_MNT(mnt_initrd)->autostart = false;
111 CAST_MNT(mnt_initrd)->blocking = true;
112
113 cfg_init = unit_create(UNIT_CONFIGURATION);
114 if (cfg_init == NULL) {
115 rc = ENOMEM;
116 goto fail;
117 }
118 cfg_init->name = str_dup(UNIT_CFG_INITRD);
119 CAST_CFG(cfg_init)->path = str_dup(INITRD_CFG_PATH);
120
121 tgt_init = unit_create(UNIT_TARGET);
122 if (tgt_init == NULL) {
123 rc = ENOMEM;
124 goto fail;
125 }
126 tgt_init->name = str_dup(TARGET_INIT);
127
128
129 /*
130 * Add units to configuration and start the default target.
131 */
132 configuration_start_update();
133
134 configuration_add_unit(mnt_initrd);
135 configuration_add_unit(cfg_init);
136 configuration_add_unit(tgt_init);
137
138 rc = dep_add_dependency(tgt_init, cfg_init);
139 if (rc != EOK) {
140 goto rollback;
141 }
142
143 rc = dep_add_dependency(cfg_init, mnt_initrd);
144 if (rc != EOK) {
145 goto rollback;
146 }
147
148 configuration_commit();
149
150 return EOK;
151
152fail:
153 unit_destroy(&tgt_init);
154 unit_destroy(&cfg_init);
155 unit_destroy(&mnt_initrd);
156 return rc;
157
158rollback:
159 configuration_rollback();
160 return rc;
161}
162
163static void sequence_job_handler(void *object, void *arg)
164{
165 job_t *job = object;
166 if (job->retval == JOB_FAILED) {
167 sysman_log(LVL_ERROR, "Failed to start '%s'.", unit_name(job->unit));
168 job_del_ref(&job);
169 return;
170 }
171 job_del_ref(&job);
172
173 const char **target_name_ptr = arg;
174 prepare_and_run_job(target_name_ptr + 1);
175}
176
177static void prepare_and_run_job(const char **target_name_ptr)
178{
179 const char *target_name = *target_name_ptr;
180
181 if (target_name == NULL) {
182 sysman_log(LVL_NOTE, "All initial units started.");
183 return;
184 }
185
186 /* Previous targets should have loaded new units */
187 unit_t *tgt = configuration_find_unit_by_name(target_name);
188 if (tgt == NULL) {
189 sysman_log(LVL_ERROR,
190 "Expected unit '%s' not found in configuration.",
191 target_name);
192 return;
193 }
194
195 int rc = sysman_run_job(tgt, STATE_STARTED, &sequence_job_handler,
196 target_name_ptr);
197
198 if (rc != EOK) {
199 sysman_log(LVL_FATAL, "Cannot create job for '%s'.", target_name);
200 }
201}
202
203int main(int argc, char *argv[])
204{
205 printf(NAME ": HelenOS system daemon\n");
206
207 /*
208 * Initialize global structures
209 */
210 configuration_init();
211 sysman_events_init();
212 job_queue_init();
213
214 /*
215 * Create initial configuration while we are in a single fibril
216 */
217 int rc = create_entry_configuration();
218 if (rc != EOK) {
219 sysman_log(LVL_FATAL,
220 "Could not create initial configuration (%i).", rc);
221 return rc;
222 }
223
224 /*
225 * Event loop runs in separate fibril, all consequent access to global
226 * structure is made from this fibril only.
227 */
228 fid_t event_loop_fibril = fibril_create(sysman_events_loop, NULL);
229 fibril_add_ready(event_loop_fibril);
230
231 /* Queue first job from sequence */
232 prepare_and_run_job(&target_sequence[0]);
233
234 /* We're service too */
235 rc = service_register(SERVICE_SYSMAN);
236 if (rc != EOK) {
237 sysman_log(LVL_FATAL,
238 "Cannot register at naming service (%i).", rc);
239 return rc;
240 }
241
242 /* Start sysman server */
243 async_set_client_connection(sysman_connection);
244
245 printf(NAME ": Accepting connections\n");
246 async_manager();
247
248 /* not reached */
249 return 0;
250}
Note: See TracBrowser for help on using the repository browser.