ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/lib/libmport/index.c
Revision: 12077
Committed: Fri Sep 28 12:24:45 2018 UTC (5 years, 7 months ago) by laffer1
Content type: text/plain
File size: 13420 byte(s)
Log Message:
fix some formatting issues and check return status on a few things.

File Contents

# Content
1 /*-
2 * Copyright (c) 2009 Chris Reinhardt
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __MBSDID("$MidnightBSD$");
29
30 #include "mport.h"
31 #include "mport_private.h"
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <errno.h>
39
40 static int index_is_recentish(void);
41 static int index_last_checked_recentish(mportInstance *);
42 static int index_update_last_checked(mportInstance *);
43 static time_t get_time(void);
44 static int lookup_alias(mportInstance *, const char *, char **);
45 static int attach_index_db(sqlite3 *db);
46 static void populate_row(sqlite3_stmt *stmt, mportIndexEntry *e);
47
48 /*
49 * Loads the index database. The index contains a list of bundles that are
50 * available for download, a list of aliases (apache is aliased to apache22 for
51 * example), and a list of mirrors.
52 *
53 * This function will use the current local index if it is present and younger
54 * than the max index age. Otherwise, it will download the index. If any
55 * index is present, the mirror list will be used; otherwise the bootstrap
56 * url will be used.
57 */
58 MPORT_PUBLIC_API int
59 mport_index_load(mportInstance *mport)
60 {
61
62 if (mport_file_exists(MPORT_INDEX_FILE)) {
63
64 if (attach_index_db(mport->db) != MPORT_OK)
65 RETURN_CURRENT_ERROR;
66
67 mport->flags |= MPORT_INST_HAVE_INDEX;
68
69 if (!index_is_recentish()) {
70 if (index_last_checked_recentish(mport))
71 return MPORT_OK;
72
73 return mport_index_get(mport);
74 }
75 } else {
76 if (mport_fetch_bootstrap_index(mport) != MPORT_OK)
77 RETURN_CURRENT_ERROR;
78
79 if (!mport_file_exists(MPORT_INDEX_FILE))
80 RETURN_ERROR(MPORT_ERR_FATAL, "Index file could not be extracted");
81
82 if (attach_index_db(mport->db) != MPORT_OK)
83 RETURN_CURRENT_ERROR;
84
85 mport->flags |= MPORT_INST_HAVE_INDEX;
86 if (index_update_last_checked(mport) != MPORT_OK)
87 RETURN_CURRENT_ERROR;
88 }
89
90 return (MPORT_OK);
91 }
92
93 static int
94 attach_index_db(sqlite3 *db)
95 {
96
97 if (mport_db_do(db, "ATTACH %Q AS idx", MPORT_INDEX_FILE) != MPORT_OK) {
98 RETURN_CURRENT_ERROR;
99 }
100
101 return (MPORT_OK);
102 }
103
104
105 /**
106 * mport_index_load is typically preferred. This function is only used to force
107 * a download of the index manually by the user.
108 */
109 MPORT_PUBLIC_API int
110 mport_index_get(mportInstance *mport)
111 {
112
113 if (!(mport->flags & MPORT_INST_HAVE_INDEX)) {
114 if (mport_fetch_bootstrap_index(mport) != MPORT_OK)
115 RETURN_CURRENT_ERROR;
116 } else {
117 if (mport_fetch_index(mport) != MPORT_OK) {
118 SET_ERROR(MPORT_ERR_WARN, "Could not fetch updated index; previous index used.");
119 RETURN_CURRENT_ERROR;
120 }
121 }
122
123 /* if we were already attached, reconnect refreshed index. */
124 if (mport->flags & MPORT_INST_HAVE_INDEX) {
125 if (mport_db_do(mport->db, "DETACH idx") != MPORT_OK)
126 RETURN_CURRENT_ERROR;
127
128 mport->flags &= ~MPORT_INST_HAVE_INDEX;
129
130 if (attach_index_db(mport->db) != MPORT_OK)
131 RETURN_CURRENT_ERROR;
132
133 mport->flags |= MPORT_INST_HAVE_INDEX;
134 }
135
136 if (index_update_last_checked(mport) != MPORT_OK)
137 RETURN_CURRENT_ERROR;
138
139 return (MPORT_OK);
140 }
141
142
143 /* return 1 if the index is younger than the max age, 0 otherwise */
144 static int
145 index_is_recentish(void)
146 {
147 struct stat st;
148
149 if (stat(MPORT_INDEX_FILE, &st) != 0)
150 return 0;
151
152 if ((st.st_birthtime + MPORT_MAX_INDEX_AGE) < get_time())
153 return 0;
154
155 return 1;
156 }
157
158 static int
159 index_last_checked_recentish(mportInstance *mport) {
160 char *recent;
161 int ret;
162
163 recent = mport_setting_get(mport, MPORT_SETTING_INDEX_LAST_CHECKED);
164 if (recent && get_time() < atoi(recent) + MPORT_DAY)
165 ret = 1;
166 else
167 ret = 0;
168
169 free(recent);
170
171 return ret;
172 }
173
174 static int
175 index_update_last_checked(mportInstance *mport) {
176 char *utime;
177 int ret;
178
179 asprintf(&utime, "%jd", (intmax_t) get_time());
180 if (utime)
181 ret = mport_setting_set(mport, MPORT_SETTING_INDEX_LAST_CHECKED, utime);
182 else
183 RETURN_CURRENT_ERROR;
184 free(utime);
185
186 return ret;
187 }
188
189 static time_t
190 get_time(void) {
191 struct timespec now;
192
193 if (clock_gettime(CLOCK_REALTIME, &now) != 0)
194 RETURN_ERROR(MPORT_ERR_FATAL, strerror(errno));
195
196 return now.tv_sec;
197 }
198
199
200 /*
201 * Fills the string vector with the list of the mirrors for the current
202 * country.
203 *
204 * XXX - The country is currently hardcoded to the US.
205 */
206 int mport_index_get_mirror_list(mportInstance *mport, char ***list_p, int *list_size)
207 {
208 char **list;
209 int ret, i;
210 int len;
211 sqlite3_stmt *stmt;
212
213 /* XXX the country is hard coded until a configuration system is created */
214 if (mport_db_count(mport->db, &len, "SELECT COUNT(*) FROM idx.mirrors WHERE country='us'") != MPORT_OK)
215 RETURN_CURRENT_ERROR;
216
217 *list_size = len;
218 list = calloc((size_t) len + 1, sizeof(char *));
219 *list_p = list;
220 i = 0;
221
222 if (mport_db_prepare(mport->db, &stmt, "SELECT mirror FROM idx.mirrors WHERE country='us'") != MPORT_OK) {
223 sqlite3_finalize(stmt);
224 RETURN_CURRENT_ERROR;
225 }
226
227 while (1) {
228 ret = sqlite3_step(stmt);
229
230 if (ret == SQLITE_ROW) {
231 list[i] = strdup((const char *) sqlite3_column_text(stmt, 0));
232
233 if (list[i] == NULL) {
234 sqlite3_finalize(stmt);
235 RETURN_ERROR(MPORT_ERR_FATAL, "Out of memory.");
236 }
237
238 i++;
239 } else if (ret == SQLITE_DONE) {
240 list[i] = NULL;
241 break;
242 } else {
243 list[i] = NULL;
244 sqlite3_finalize(stmt);
245 RETURN_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
246 }
247 }
248
249 sqlite3_finalize(stmt);
250 return MPORT_OK;
251 }
252
253 /*
254 * Looks up a pkgname from the index and fills a vector of index entries
255 * with the result.
256 *
257 * Globbing is supported, and the alias list is consulted. The calling code
258 * is responsible for freeing the memory allocated. See
259 * mport_index_entry_free_vec()
260 */
261 MPORT_PUBLIC_API int
262 mport_index_lookup_pkgname(mportInstance *mport, const char *pkgname, mportIndexEntry ***entry_vec)
263 {
264 char *lookup = NULL;
265 int count;
266 int i = 0, step;
267 sqlite3_stmt *stmt;
268 int ret = MPORT_OK;
269 mportIndexEntry **e = NULL;
270
271 MPORT_CHECK_FOR_INDEX(mport, "mport_index_lookup_pkgname()")
272
273 if (lookup_alias(mport, pkgname, &lookup) != MPORT_OK)
274 RETURN_CURRENT_ERROR;
275
276 if (mport_db_count(mport->db, &count,"SELECT count(*) FROM idx.packages WHERE pkg GLOB %Q", lookup) != MPORT_OK)
277 RETURN_CURRENT_ERROR;
278
279 e = (mportIndexEntry **) calloc((size_t) count + 1, sizeof(mportIndexEntry *));
280 if (e == NULL) {
281 ret = MPORT_ERR_FATAL;
282 goto DONE;
283 }
284 *entry_vec = e;
285
286 if (count == 0) {
287 ret = MPORT_OK;
288 goto DONE;
289 }
290
291 if (mport_db_prepare(mport->db, &stmt,
292 "SELECT pkg, version, comment, bundlefile, license, hash FROM idx.packages WHERE pkg GLOB %Q",
293 lookup) != MPORT_OK) {
294 ret = mport_err_code();
295 goto DONE;
296 }
297
298 while (1) {
299 step = sqlite3_step(stmt);
300
301 if (step == SQLITE_ROW) {
302 if ((e[i] = (mportIndexEntry *) calloc(1, sizeof(mportIndexEntry))) == NULL) {
303 ret = MPORT_ERR_FATAL;
304 goto DONE;
305 }
306
307 populate_row(stmt, e[i]);
308
309 if (e[i]->pkgname == NULL || e[i]->version == NULL || e[i]->comment == NULL || e[i]->license == NULL ||
310 e[i]->bundlefile == NULL) {
311 ret = MPORT_ERR_FATAL;
312 goto DONE;
313 }
314
315 i++;
316 } else if (step == SQLITE_DONE) {
317 e[i] = NULL;
318 goto DONE;
319 } else {
320 ret = SET_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
321 goto DONE;
322 }
323 }
324
325 DONE:
326 free(lookup);
327 sqlite3_finalize(stmt);
328 return ret;
329 }
330
331
332 /* mport_index_search(mportInstance *mport, mportIndexEntry ***entry_vec, const char *where, ...)
333 *
334 * Allocate and populate the index meta for the given package in the index.
335 *
336 * 'where' and the vargs are used to be build a where clause. For example to search by
337 * name:
338 *
339 * mport_index_search(mport, &indexEntries, "pkg=%Q", name);
340 *
341 * indexEntries is set to an empty allocated list and MPORT_OK is returned if no packages where found.
342 */
343 MPORT_PUBLIC_API int
344 mport_index_search(mportInstance *mport, mportIndexEntry ***entry_vec, const char *fmt, ...)
345 {
346 va_list args;
347 sqlite3_stmt *stmt;
348 int ret = MPORT_OK;
349 int len;
350 int i = 0, step;
351 char *where;
352 sqlite3 *db = mport->db;
353 mportIndexEntry **e;
354
355 va_start(args, fmt);
356 where = sqlite3_vmprintf(fmt, args);
357 va_end(args);
358
359 if (where == NULL)
360 RETURN_ERROR(MPORT_ERR_FATAL, "Could not build where clause");
361
362 if (mport_db_count(mport->db, &len,"SELECT count(*) FROM idx.packages WHERE %s", where) != MPORT_OK)
363 RETURN_CURRENT_ERROR;
364
365 e = (mportIndexEntry **)calloc((size_t) len + 1, sizeof(mportIndexEntry *));
366 if (e == NULL) {
367 ret = MPORT_ERR_FATAL;
368 goto DONE;
369 }
370 *entry_vec = e;
371
372 if (len == 0) {
373 sqlite3_free(where);
374 return MPORT_OK;
375 }
376
377 if (mport_db_prepare(db, &stmt, "SELECT pkg, version, comment, bundlefile, license, hash FROM idx.packages WHERE %s", where) != MPORT_OK) {
378 sqlite3_free(where);
379 sqlite3_finalize(stmt);
380 RETURN_CURRENT_ERROR;
381 }
382
383 while (1) {
384 step = sqlite3_step(stmt);
385
386 if (step == SQLITE_ROW) {
387 if ((e[i] = (mportIndexEntry *)calloc(1, sizeof(mportIndexEntry))) == NULL) {
388 ret = MPORT_ERR_FATAL;
389 break;
390 }
391
392 populate_row(stmt, e[i]);
393
394 if (e[i]->pkgname == NULL || e[i]->version == NULL || e[i]->comment == NULL || e[i]->license == NULL || e[i]->bundlefile == NULL) {
395 ret = MPORT_ERR_FATAL;
396 break;
397 }
398
399 i++;
400 } else if (step == SQLITE_DONE) {
401 e[i] = NULL;
402 break;
403 } else {
404 ret = SET_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
405 break;
406 }
407 }
408
409 sqlite3_free(where);
410 sqlite3_finalize(stmt);
411
412 return ret;
413 }
414
415
416 MPORT_PUBLIC_API int
417 mport_index_list(mportInstance *mport, mportIndexEntry ***entry_vec)
418 {
419 sqlite3_stmt *stmt;
420 int ret = MPORT_OK;
421 int len;
422 int i = 0, step;
423 sqlite3 *db = mport->db;
424 mportIndexEntry **e;
425
426 if (mport_db_count(mport->db, &len,"SELECT count(*) FROM idx.packages") != MPORT_OK)
427 RETURN_CURRENT_ERROR;
428
429 e = (mportIndexEntry **) calloc((size_t) len + 1, sizeof(mportIndexEntry *));
430 *entry_vec = e;
431
432 if (len == 0) {
433 return MPORT_OK;
434 }
435
436 if (mport_db_prepare(db, &stmt, "SELECT pkg, version, comment, bundlefile, license, hash FROM idx.packages") !=
437 MPORT_OK) {
438 sqlite3_finalize(stmt);
439 RETURN_CURRENT_ERROR;
440 }
441
442 while (1) {
443 step = sqlite3_step(stmt);
444
445 if (step == SQLITE_ROW) {
446 if ((e[i] = (mportIndexEntry *) calloc(1, sizeof(mportIndexEntry))) == NULL) {
447 ret = MPORT_ERR_FATAL;
448 break;
449 }
450
451 populate_row(stmt, e[i]);
452
453 if (e[i]->pkgname == NULL || e[i]->version == NULL || e[i]->comment == NULL || e[i]->license == NULL ||
454 e[i]->bundlefile == NULL) {
455 ret = MPORT_ERR_FATAL;
456 break;
457 }
458
459 i++;
460 } else if (step == SQLITE_DONE) {
461 e[i] = NULL;
462 break;
463 } else {
464 ret = SET_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
465 break;
466 }
467 }
468
469 sqlite3_finalize(stmt);
470
471 return ret;
472 }
473
474 static void
475 populate_row(sqlite3_stmt *stmt, mportIndexEntry *e) {
476
477 e->pkgname = strdup((const char *) sqlite3_column_text(stmt, 0));
478 e->version = strdup((const char *) sqlite3_column_text(stmt, 1));
479 e->comment = strdup((const char *) sqlite3_column_text(stmt, 2));
480 e->bundlefile = strdup((const char *) sqlite3_column_text(stmt, 3));
481 e->license = strdup((const char *) sqlite3_column_text(stmt, 4));
482 e->hash = strdup((const char *) sqlite3_column_text(stmt, 5));
483 }
484
485
486 static int
487 lookup_alias(mportInstance *mport, const char *query, char **result)
488 {
489 sqlite3_stmt *stmt;
490 __block int ret = MPORT_OK;
491
492 if (mport_db_prepare(mport->db, &stmt, "SELECT pkg FROM idx.aliases WHERE alias=%Q", query) != MPORT_OK)
493 RETURN_CURRENT_ERROR;
494
495 dispatch_sync(mportSQLSerial, ^{
496 switch (sqlite3_step(stmt)) {
497 case SQLITE_ROW:
498 *result = strdup((const char *) sqlite3_column_text(stmt, 0));
499 break;
500 case SQLITE_DONE:
501 *result = strdup(query);
502 break;
503 default:
504 ret = SET_ERROR(MPORT_ERR_FATAL, sqlite3_errmsg(mport->db));
505 break;
506 }
507
508 sqlite3_finalize(stmt);
509 });
510
511 return ret;
512 }
513
514
515 /* free a vector of mportIndexEntry structs */
516 MPORT_PUBLIC_API void
517 mport_index_entry_free_vec(mportIndexEntry **e)
518 {
519
520 if (e == NULL)
521 return;
522
523 for (int i = 0; e[i] != NULL; i++)
524 mport_index_entry_free(e[i]);
525
526 free(e);
527 }
528
529
530 /* free a mportIndexEntry struct */
531 MPORT_PUBLIC_API void
532 mport_index_entry_free(mportIndexEntry *e)
533 {
534
535 if (e == NULL)
536 return;
537
538 free(e->pkgname);
539 free(e->comment);
540 free(e->version);
541 free(e->bundlefile);
542 free(e->license);
543 free(e->hash);
544 free(e);
545 }

Properties

Name Value
svn:keywords MidnightBSD=%H