ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_app_library.c
Go to the documentation of this file.
1
9#include "mdl_app_internal.h"
10
11typedef struct {
12 size_t found;
14
33 const char* first,
34 const char* second,
35 const char* third)
36{
37 ra8_err_t error = priv_mdl_stream_text(k_ra8_ok, stream, first);
38 error = priv_mdl_stream_text(error, stream, second);
39 return priv_mdl_stream_text(error, stream, third);
40}
41
60{
61 if (error == k_ra8_err_invalid_state) {
63 "mdl: state file unreadable or corrupt while ",
64 action,
65 "\n");
66 }
67 if (error == k_ra8_err_invalid_size) {
69 ra8_err_t output_error = internal_library_text3(priv_mdl_app_context()->diagnostic,
70 "mdl: library capacity exceeded while ",
71 action,
72 " (observed ");
73 output_error = priv_mdl_stream_u64(output_error,
74 priv_mdl_app_context()->diagnostic,
75 workspace->required_entries);
76 output_error =
77 priv_mdl_stream_text(output_error, priv_mdl_app_context()->diagnostic, ", limit ");
78 output_error =
79 priv_mdl_stream_u64(output_error, priv_mdl_app_context()->diagnostic, workspace->entry_limit);
80 return priv_mdl_stream_text(output_error, priv_mdl_app_context()->diagnostic, ")\n");
81 }
82 if (error == k_ra8_err_hw_not_ready) {
84 "mdl: library storage unavailable while ",
85 action,
86 "\n");
87 }
88 ra8_err_t output_error = internal_library_text3(priv_mdl_app_context()->diagnostic,
89 "mdl: library operation failed while ",
90 action,
91 " (");
92 output_error =
93 priv_mdl_stream_u64(output_error, priv_mdl_app_context()->diagnostic, (uint32_t)error);
94 return priv_mdl_stream_text(output_error, priv_mdl_app_context()->diagnostic, ")\n");
95}
96
115RA8_INTERNAL static ra8_err_t internal_list_cb(const char* series_dir,
116 const char* state_path,
117 const mdl_state_t* state,
118 void* ctx,
119 bool* out_continue)
120{
121 list_ctx_t* list = (list_ctx_t*)ctx;
122 (void)state_path;
123 list->found += 1U;
124 char cov[k_cov_bytes];
125 mdl_state_coverage(state, cov, sizeof(cov));
126 ra8_err_t output_error =
127 internal_library_text3(priv_mdl_app_context()->output, " ", series_dir, "\n url: ");
128 output_error =
129 priv_mdl_stream_text(output_error,
130 priv_mdl_app_context()->output,
131 (state->series_url[0] != '\0') ? state->series_url : "(unknown)");
132 output_error = priv_mdl_stream_text(output_error, priv_mdl_app_context()->output, "\n ");
133 output_error = priv_mdl_stream_text(output_error, priv_mdl_app_context()->output, cov);
134 output_error = priv_mdl_stream_text(output_error, priv_mdl_app_context()->output, "\n");
135 *out_continue = output_error == k_ra8_ok;
136 return output_error;
137}
138
139int mdl_app_run_list(const char* out_dir)
140{
141 list_ctx_t list = {};
144 out_dir,
145 &priv_mdl_app_context()->state,
146 &priv_mdl_app_context()->library_workspace,
147 &policy,
149 &list);
150 if (rc != k_ra8_ok) {
151 (void)internal_library_report("listing tracked series", rc);
152 } else if (list.found == 0U) {
154 "no tracked series under ",
155 out_dir,
156 "\n") != k_ra8_ok) {
157 return 1;
158 }
159 }
160 return (rc == k_ra8_ok) ? 0 : 1;
161}
162
181RA8_INTERNAL static bool
182internal_resolve_removal_target(const char* out_dir, const char* url_or_slug, char* dir)
183{
184 char slug[k_slug_bytes];
185 mdl_urlname_last_segment(url_or_slug, slug, sizeof(slug));
186 if (!mdl_path_join(out_dir, slug, dir, k_dir_path_bytes)) {
188 "mdl: cannot resolve series '",
189 url_or_slug,
190 "'\n");
191 return false;
192 }
193 fw_fs_stat_t dir_stat = {};
194 if ((fw_fs_stat(&priv_mdl_app_context()->storage.fs->names, dir, &dir_stat) != k_ra8_ok) ||
195 !dir_stat.exists || (dir_stat.type != k_fw_fs_node_directory)) {
197 "mdl: refusing to remove unsafe series path '",
198 dir,
199 "'\n");
200 return false;
201 }
202 char state_path[PATH_MAX];
203 bool state_exists = false;
204 if (!priv_mdl_app_state_path_of(dir, state_path, sizeof(state_path)) ||
205 (mdl_state_probe(&priv_mdl_app_context()->storage, state_path, &state_exists) != k_ra8_ok) ||
206 !state_exists) {
208 "mdl: refusing to remove untracked directory '",
209 dir,
210 "' (missing or unsafe .mdl_state)\n");
211 return false;
212 }
214 state_path,
215 &priv_mdl_app_context()->state) != k_ra8_ok) {
217 "mdl: refusing to remove '",
218 dir,
219 "' (state is unreadable or corrupt)\n");
220 return false;
221 }
222 char recorded_slug[k_slug_bytes];
224 recorded_slug,
225 sizeof(recorded_slug));
226 if ((priv_mdl_app_context()->state.series_url[0] != '\0') && (strcmp(recorded_slug, slug) == 0)) {
227 return true;
228 }
230 "mdl: refusing to remove '",
231 dir,
232 "' (state identity does not match target)\n");
233 return false;
234}
235
236int mdl_app_run_remove(const char* out_dir, const char* url_or_slug)
237{
238 char dir[k_dir_path_bytes];
239 if (!internal_resolve_removal_target(out_dir, url_or_slug, dir)) {
240 return 1;
241 }
244 dir,
245 &policy,
246 &priv_mdl_app_context()->library_workspace) != k_ra8_ok) {
248 "mdl: failed to remove ",
249 dir,
250 "\n");
251 return 1;
252 }
253 return (internal_library_text3(priv_mdl_app_context()->output, "removed ", dir, "\n") == k_ra8_ok)
254 ? 0
255 : 1;
256}
257
263typedef struct {
265 size_t updated;
266 size_t failed;
268
287RA8_INTERNAL static ra8_err_t internal_update_all_cb(const char* series_dir,
288 const char* state_path,
289 const mdl_state_t* state,
290 void* ctx,
291 bool* out_continue)
292{
294 (void)state_path;
295 char url[k_mdl_url_max];
296 char cfg[k_mdl_cfgpath_max];
297 (void)snprintf(url, sizeof(url), "%s", state->series_url);
298 (void)snprintf(cfg,
299 sizeof(cfg),
300 "%s",
301 (state->config_path[0] != '\0') ? state->config_path : p->base->cfg_path);
302 if ((url[0] == '\0') || (cfg[0] == '\0')) {
303 const ra8_err_t output_error = internal_library_text3(priv_mdl_app_context()->output,
304 "skip ",
305 series_dir,
306 " (no series URL / descriptor "
307 "recorded)\n");
308 p->failed += 1U;
309 *out_continue = output_error == k_ra8_ok;
310 return output_error;
311 }
312 const ra8_err_t output_error =
313 internal_library_text3(priv_mdl_app_context()->output, "updating ", url, "\n");
314 if (output_error != k_ra8_ok) {
315 *out_continue = false;
316 return output_error;
317 }
318 mdl_series_run_t run = *p->base;
319 run.series_url = url;
320 run.cfg_path = cfg;
321 run.update = true;
322 if (mdl_app_run_series(&run) == 0) {
323 p->updated += 1U;
324 } else {
325 p->failed += 1U;
326 }
327 *out_continue = true;
328 return k_ra8_ok;
329}
330
332{
333 update_all_ctx_t c = {.base = base, .updated = 0U, .failed = 0U};
336 base->out_dir,
337 &priv_mdl_app_context()->state,
338 &priv_mdl_app_context()->library_workspace,
339 &policy,
341 &c);
342 if (c.updated == 0U) {
343 const ra8_err_t output_error = internal_library_text3(priv_mdl_app_context()->output,
344 "no tracked series to update under ",
345 base->out_dir,
346 "\n");
347 if (output_error != k_ra8_ok) {
348 return 1;
349 }
350 }
351 if (c.failed > 0U) {
352 ra8_err_t output_error =
353 priv_mdl_stream_text(k_ra8_ok, priv_mdl_app_context()->diagnostic, "mdl: ");
354 output_error = priv_mdl_stream_u64(output_error, priv_mdl_app_context()->diagnostic, c.failed);
355 output_error = priv_mdl_stream_text(output_error,
356 priv_mdl_app_context()->diagnostic,
357 " series failed to update\n");
358 if (output_error != k_ra8_ok) {
359 return 1;
360 }
361 }
362 if (rc != k_ra8_ok) {
363 (void)internal_library_report("updating tracked series", rc);
364 }
365 return ((rc == k_ra8_ok) && (c.failed == 0U)) ? 0 : 1;
366}
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
Definition fw_if_fs.c:480
@ k_fw_fs_node_directory
Directory.
mdl_app_context_t * priv_mdl_app_context(void)
The working set the composition root bound with mdl_app_bind.
Definition mdl_app.c:33
int mdl_app_run_series(const mdl_series_run_t *run)
Execute one prepared series download.
Module-private contract shared by the application-mode translation units.
@ k_dir_path_bytes
Directory-path buffer.
@ k_cov_bytes
Coverage summary line buffer.
@ k_slug_bytes
Series slug buffer.
bool priv_mdl_app_state_path_of(const char *abs_dir, char *out, size_t cap)
Compose the state-journal path within a series directory.
static ra8_err_t internal_list_cb(const char *series_dir, const char *state_path, const mdl_state_t *state, void *ctx, bool *out_continue)
Print one tracked series for library-list mode.
static ra8_err_t internal_library_report(const char *action, ra8_err_t error)
Report a portable library-enumeration failure in user-facing terms.
int mdl_app_run_update_all(const mdl_series_run_t *base)
Incrementally update every tracked series under a library root.
static ra8_err_t internal_update_all_cb(const char *series_dir, const char *state_path, const mdl_state_t *state, void *ctx, bool *out_continue)
Incrementally update one visited tracked series.
static ra8_err_t internal_library_text3(ra8_io_stream_t *stream, const char *first, const char *second, const char *third)
Write up to three borrowed fragments through one selected sink.
static bool internal_resolve_removal_target(const char *out_dir, const char *url_or_slug, char *dir)
Resolve and authenticate one tracked library-removal target.
int mdl_app_run_remove(const char *out_dir, const char *url_or_slug)
Remove one explicitly tracked series directory.
int mdl_app_run_list(const char *out_dir)
List every tracked series under one library root.
@ k_mdl_url_max
Max bytes per URL, including the NUL.
Definition mdl_extract.h:25
ra8_err_t mdl_library_for_each(mdl_storage_t *storage, const char *out_dir, mdl_state_t *state_scratch, mdl_library_workspace_t *workspace, const mdl_library_policy_t *policy, mdl_library_fn callback, void *callback_ctx)
Visit every authenticated tracked series under a library root.
mdl_library_policy_t mdl_library_policy_default(void)
Return the production library traversal policy.
Definition mdl_library.c:29
ra8_err_t mdl_library_remove_tree(mdl_storage_t *storage, const char *dir, const mdl_library_policy_t *policy, mdl_library_workspace_t *workspace)
Remove one canonical directory tree through portable namespace calls.
bool mdl_path_join(const char *parent, const char *seg, char *out, size_t cap)
Join one safe child segment under a parent directory path.
void mdl_state_coverage(const mdl_state_t *st, char *buf, size_t cap)
Render a one-line coverage summary (chapter span, count, gaps).
Definition mdl_state.c:559
@ k_mdl_cfgpath_max
Site-descriptor path bytes.
Definition mdl_state.h:103
ra8_err_t mdl_state_load_authenticated(mdl_storage_t *storage, const char *path, mdl_state_t *st)
Load only an authenticated checksummed state generation.
ra8_err_t mdl_state_probe(mdl_storage_t *storage, const char *path, bool *out_exists)
Probe the complete two-generation state marker through portable storage.
ra8_err_t priv_mdl_stream_text(ra8_err_t prior, ra8_io_stream_t *stream, const char *text)
Append text unless an earlier operation already failed.
Definition mdl_stream.c:16
ra8_err_t priv_mdl_stream_u64(ra8_err_t prior, ra8_io_stream_t *stream, uint64_t value)
Append one unsigned integer unless an earlier append failed.
Definition mdl_stream.c:21
void mdl_urlname_last_segment(const char *url, char *out, size_t cap)
Sanitised last non-empty path segment of a URL.
Definition mdl_urlname.c:75
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_not_ready
Hardware peripheral exists but not ready yet.
Definition ra8_err.h:298
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
Result of a portable metadata query.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
size_t found
Authenticated tracked series encountered.
mdl_library_workspace_t library_workspace
Bounded tree-removal stack.
Definition mdl_app.h:174
Caller-selected limits within the compile-time hard ceilings.
Definition mdl_library.h:39
Caller-owned directory cursor storage and iterative traversal stack.
Definition mdl_library.h:53
uint32_t required_entries
Entries observed through cap+1.
Definition mdl_library.h:59
uint32_t entry_limit
Active explicit traversal limit.
Definition mdl_library.h:60
Parameters of one series download, as values rather than arguments.
Definition mdl_app.h:114
const char * out_dir
Output library root.
Definition mdl_app.h:117
const char * cfg_path
Site descriptor path.
Definition mdl_app.h:115
One series' complete persistent state (declare at file scope).
Definition mdl_state.h:175
char series_url[k_mdl_url_max]
Series page URL.
Definition mdl_state.h:177
char config_path[k_mdl_cfgpath_max]
Descriptor used.
Definition mdl_state.h:181
Caller-allocated byte-stream handle binding a sink to its context.
Context threaded through internal_update_all_cb for --update-all.
size_t updated
Count of series updated.
size_t failed
Count of series skipped or unsuccessfully updated.
const mdl_series_run_t * base
Template run (format/knobs); url filled per series.