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, &current, 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, &current, 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(&current);
352 	free_storage_list(&addition);
353 	LIST_FOREACH(p, &new, chain) {
354 		n = copy_storage(p);
355 		LIST_INSERT_HEAD(&current, 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, &current, 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(&current);
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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, chain) {
568 		if (p->id == id)
569 			return 1;
570 	}
571 	return 0;
572 }
573