1 /* $Id: module_db_mi.c 20800 2012-01-19 05:13:45Z m-oki $ */
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <inttypes.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <sys/queue.h>
38 #include <unistd.h>
39
40 #include <libarms.h>
41 #include <axp_extern.h>
42 #include <transaction/transaction.h>
43 #include <protocol/arms_methods.h>
44
45 #include <module_db_mi.h>
46
47 #include <libarms/malloc.h>
48
49 module_cb_tbl_t mod_cb_tbl = {
50 NULL,
51 NULL,
52 NULL
53 };
54
55 /* missing macro in sys/queue.h (montavista linux case.) */
56 #ifndef LIST_HEAD_INITIALIZER
57 #define LIST_HEAD_INITIALIZER(head) { NULL }
58 #endif
59 #ifndef LIST_FOREACH
60 #define LIST_FOREACH(var, head, field) \
61 for ((var) = ((head)->lh_first); \
62 (var); \
63 (var) = ((var)->field.le_next))
64 #endif
65 #ifndef LIST_FIRST
66 #define LIST_FIRST(head) ((head)->lh_first)
67 #endif
68
69 LIST_HEAD(module_storage_head, module_storage);
70
71 struct module_storage_head new =
72 LIST_HEAD_INITIALIZER(module_storage_head);
73 struct module_storage_head addition =
74 LIST_HEAD_INITIALIZER(module_storage_head);
75 struct module_storage_head current =
76 LIST_HEAD_INITIALIZER(module_storage_head);
77
78 struct module_storage {
79 uint32_t id;
80 char *ver;
81 char *pkg_name;
82 char *url;
83
84 LIST_ENTRY(module_storage) chain;
85 };
86
87 static struct module_storage *
alloc_storage(void)88 alloc_storage(void)
89 {
90 struct module_storage *p;
91
92 p = MALLOC(sizeof(*p));
93 if (p == NULL)
94 return NULL;
95
96 memset(p, 0, sizeof(*p));
97 return p;
98 }
99
100 static struct module_storage *
copy_storage(struct module_storage * src)101 copy_storage(struct module_storage *src)
102 {
103 struct module_storage *cpy;
104
105 cpy = alloc_storage();
106 if (cpy == NULL)
107 return NULL;
108
109 cpy->id = src->id;
110 if (src->ver != NULL)
111 cpy->ver = STRDUP(src->ver);
112 else
113 cpy->ver = NULL;
114 cpy->pkg_name = STRDUP(src->pkg_name);
115 if (src->url != NULL)
116 cpy->url = STRDUP(src->url);
117 else
118 cpy->url = NULL;
119
120 return cpy;
121 }
122
123 static void
free_storage(struct module_storage * p)124 free_storage(struct module_storage *p)
125 {
126 if (p == NULL)
127 return;
128
129 if (p->ver)
130 FREE(p->ver);
131 if (p->url)
132 FREE(p->url);
133 if (p->pkg_name)
134 FREE(p->pkg_name);
135 FREE(p);
136
137 return;
138 }
139
140 static void
free_storage_list(struct module_storage_head * h)141 free_storage_list(struct module_storage_head *h)
142 {
143 struct module_storage *p;
144
145 if (h == NULL)
146 return;
147
148 while ( (p = LIST_FIRST(h)) != NULL) {
149 LIST_REMOVE(p, chain);
150 free_storage(p);
151 }
152
153 return;
154 }
155
156 static char *
get_pkg_name(const char * url)157 get_pkg_name(const char *url)
158 {
159 return STRDUP(url);
160 #if 0
161 char work[256 + 1];
162 char *workp;
163 const char *urlp;
164 const char *start = NULL;
165
166 if (strlen(url) > sizeof(work))
167 return NULL;
168
169 /* find end of scheme */
170 for (urlp = url; *urlp != '/'; urlp++)
171 ;
172 while (*urlp == '/')
173 urlp++;
174
175 start = urlp;
176 /* find directory separater */
177 while (*urlp != '\0') {
178 if (*urlp == '/') {
179 while (*urlp == '/') urlp++;
180 start = urlp;
181 }
182 urlp++;
183 }
184
185 /* is file name specified? */
186 if (start == NULL)
187 return NULL;
188
189 /* copy until '.' found */
190 memset(work, 0, sizeof(work));
191 workp = work;
192 urlp = start;
193 while (*urlp != '\0') {
194 if (*urlp == '.')
195 break;
196 *workp = *urlp;
197 workp++;
198 urlp++;
199 }
200 /* copy 1st '.' */
201 *workp = *urlp;
202 workp++;
203 urlp++;
204
205 /* copy until '.' found */
206 while (*urlp != '\0') {
207 if (*urlp == '.')
208 break;
209 *workp = *urlp;
210 workp++;
211 urlp++;
212 }
213
214 /* terminate */
215 *workp = '\0';
216
217 return STRDUP(work);
218 #endif
219 }
220
221 static struct module_storage *
find_current(uint32_t id,const char * ver,const char * pkg_name)222 find_current(uint32_t id, const char*ver, const char *pkg_name)
223 {
224 struct module_storage *p;
225
226 LIST_FOREACH(p, ¤t, chain) {
227 if (p->id != id)
228 continue;
229 if (p->ver == NULL && ver != NULL)
230 continue;
231 if (p->ver != NULL && ver == NULL)
232 continue;
233 if (p->ver != NULL && strcmp(p->ver, ver) != 0)
234 continue;
235
236 return p;
237 };
238
239 return NULL;
240 }
241
242 int
add_module(int id,const char * ver,const char * url)243 add_module(int id, const char *ver, const char *url)
244 {
245 struct module_storage *p;
246
247 p = alloc_storage();
248 if (p == NULL)
249 return -1;
250
251 p->id = id;
252 if (ver != NULL)
253 p->ver = STRDUP(ver);
254 if (url != NULL)
255 p->url = STRDUP(url);
256 p->pkg_name = get_pkg_name(url);
257
258 LIST_INSERT_HEAD(&new, p, chain);
259
260 return 0;
261 }
262
263 static int
get_module(char * url)264 get_module(char *url)
265 {
266 if (mod_cb_tbl.get_module_cb != NULL) {
267 return (*mod_cb_tbl.get_module_cb)(url, mod_cb_tbl.udata);
268 }
269
270 return 0;
271 }
272
273 static int
purge_module(uint32_t id,char * pkg_name)274 purge_module(uint32_t id, char *pkg_name)
275 {
276 if (mod_cb_tbl.purge_module_cb != NULL) {
277 return (*mod_cb_tbl.purge_module_cb)(id, pkg_name,
278 mod_cb_tbl.udata);
279 }
280
281 return 0;
282 }
283
284 /*
285 * update current module list. sync with 'new'.
286 */
287 int
sync_module(void)288 sync_module(void)
289 {
290 struct module_storage *p, *c, *n;
291 int err;
292 int failed = 0;
293 #if 0
294 int nmod_sys, retry = 0;
295 #endif
296
297 /*
298 * first, lookup additional module and removal module.
299 */
300 LIST_FOREACH(p, &new, chain) {
301 c = find_current(p->id, p->ver, p->pkg_name);
302 if (c) {
303 /*
304 * skip use preloaded module
305 * (remove from current list)
306 */
307 LIST_REMOVE(c, chain);
308 free_storage(c);
309 continue;
310 }
311 /*
312 * not find in current
313 * (add to addition list)
314 */
315 n = copy_storage(p);
316 if (n) {
317 LIST_INSERT_HEAD(&addition, n, chain);
318 }
319 }
320
321 /*
322 * now, modules in current list is NOT includes in new list.
323 * purge unused module (call user function)
324 */
325 LIST_FOREACH(p, ¤t, chain) {
326 err = purge_module(p->id, p->pkg_name);
327 if (err) {
328 failed = 1;
329 continue;
330 }
331 }
332
333 /*
334 * install new module (call user function)
335 * note: list is not modified
336 */
337 LIST_FOREACH(p, &addition, chain) {
338 err = get_module(p->url);
339 if (err) {
340 failed = 1;
341 continue;
342 }
343 }
344
345 /* XXX: if (failed) ... */
346
347 /*
348 * rebuild db
349 * copy new list to current list
350 */
351 free_storage_list(¤t);
352 free_storage_list(&addition);
353 LIST_FOREACH(p, &new, chain) {
354 n = copy_storage(p);
355 LIST_INSERT_HEAD(¤t, n, chain);
356 }
357 free_storage_list(&new);
358
359 if (failed)
360 return -1;
361 return 0;
362 }
363
364 int
purge_all_modules(void)365 purge_all_modules(void)
366 {
367 struct module_storage *p;
368 int err, failed;
369
370 failed = 0;
371 LIST_FOREACH(p, ¤t, chain) {
372 err = purge_module(p->id, p->pkg_name);
373 if (err) {
374 failed = 1;
375 continue;
376 }
377 }
378
379 free_storage_list(&new);
380 free_storage_list(&addition);
381 free_storage_list(¤t);
382
383 if (failed)
384 return -1;
385 return 0;
386 }
387
388 uint32_t
get_module_id(AXP * axp,int tag)389 get_module_id(AXP *axp, int tag)
390 {
391 const char *mod_idstr;
392 uint32_t mod_id = 0;
393
394 if (axp == NULL) {
395 return 0;
396 }
397
398 /* module-id attribute */
399 mod_idstr = axp_find_attr(axp, tag, "module-id");
400 if (mod_idstr) {
401 if (sscanf(mod_idstr, "%u", &mod_id) != 1) {
402 sscanf(mod_idstr, "0x%x", &mod_id);
403 }
404
405 return mod_id;
406 }
407
408 mod_idstr = axp_find_attr(axp, tag, "id");
409 if (mod_idstr) {
410 if (sscanf(mod_idstr, "%u", &mod_id) != 1) {
411 sscanf(mod_idstr, "0x%x", &mod_id);
412 }
413 return mod_id;
414 }
415 return 0;
416 }
417
418 uint32_t
get_module_order(AXP * axp,int tag)419 get_module_order(AXP *axp, int tag)
420 {
421 const char *mod_idstr;
422 uint32_t mod_id = 0;
423
424 if (axp == NULL) {
425 return 0;
426 }
427
428 /* module-id attribute */
429 mod_idstr = axp_find_attr(axp, tag, "commit-order");
430 if (mod_idstr) {
431 if (sscanf(mod_idstr, "%u", &mod_id) != 1) {
432 sscanf(mod_idstr, "0x%x", &mod_id);
433 }
434
435 return mod_id;
436 }
437 return 0;
438 }
439
440 const char *
get_module_ver(AXP * axp,int tag)441 get_module_ver(AXP *axp, int tag)
442 {
443 const char *ver_str;
444
445 if (axp == NULL) {
446 return 0;
447 }
448
449 /* module-id attribute */
450 ver_str = axp_find_attr(axp, tag, "version");
451
452 return ver_str;
453 }
454
455 char *
lookup_module_ver(uint32_t id)456 lookup_module_ver(uint32_t id)
457 {
458 struct module_storage *p;
459
460 LIST_FOREACH(p, ¤t, chain) {
461 if (p->id == id)
462 return p->ver;
463 }
464 return NULL;
465 }
466
467 char *
lookup_module_location(uint32_t id)468 lookup_module_location(uint32_t id)
469 {
470 struct module_storage *p;
471
472 LIST_FOREACH(p, ¤t, chain) {
473 if (p->id == id)
474 return p->url;
475 }
476 return NULL;
477 }
478
479 int
init_module_cb(module_cb_tbl_t * tbl)480 init_module_cb(module_cb_tbl_t *tbl)
481 {
482 if (tbl == NULL)
483 return -1;
484
485 memset(&mod_cb_tbl, 0, sizeof(mod_cb_tbl));
486 mod_cb_tbl.get_module_cb = tbl->get_module_cb;
487 mod_cb_tbl.purge_module_cb = tbl->purge_module_cb;
488 mod_cb_tbl.udata = tbl->udata;
489
490 return 0;
491 }
492
493 int
arms_count_module(void)494 arms_count_module(void)
495 {
496 struct module_storage *p;
497 int i = 0;
498
499 LIST_FOREACH(p, ¤t, chain) {
500 i++;
501 }
502 return i;
503 }
504
505 /* ugly implementation */
506 int
arms_get_module_id(uint32_t * mod_id,int n)507 arms_get_module_id(uint32_t *mod_id, int n)
508 {
509 struct module_storage *p;
510
511 LIST_FOREACH(p, ¤t, chain) {
512 if (n-- > 0)
513 continue;
514 *mod_id = p->id;
515 return 0;
516 }
517
518 /* not found */
519 return -1;
520 }
521
522 /*
523 * rv: wrote bytes (exclude trailer NUL)
524 */
525 int
arms_dump_module(char * buf,int len)526 arms_dump_module(char *buf, int len)
527 {
528 struct module_storage *p;
529 int size, total;
530
531 total = 0;
532 LIST_FOREACH(p, ¤t, chain) {
533 size = snprintf(buf, len,
534 "<module id=\"%d\" version=\"%s\">",
535 p->id,
536 p->ver != NULL ? arms_escape(p->ver) : "");
537 buf += size;
538 len -= size;
539 total += size;
540 size = snprintf(buf, len,
541 "%s</module>",
542 p->url != NULL ? arms_escape(p->url) : "");
543 buf += size;
544 len -= size;
545 total += size;
546 }
547 return total;
548 }
549
550 int
arms_module_is_added(int32_t id)551 arms_module_is_added(int32_t id)
552 {
553 struct module_storage *p;
554
555 LIST_FOREACH(p, &new, chain) {
556 if (p->id == id)
557 return 1;
558 }
559 return 0;
560 }
561
562 int
arms_module_is_exist(int32_t id)563 arms_module_is_exist(int32_t id)
564 {
565 struct module_storage *p;
566
567 LIST_FOREACH(p, ¤t, chain) {
568 if (p->id == id)
569 return 1;
570 }
571 return 0;
572 }
573