Rename pmhandle_t to alpm_handle_t
[pacman-ng.git] / lib / libalpm / be_sync.c
blob4f0cc2b6cd99f678a860e9dca23b98eed604e0da
1 /*
2 * be_sync.c : backend for sync databases
4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
27 /* libarchive */
28 #include <archive.h>
29 #include <archive_entry.h>
31 /* libalpm */
32 #include "util.h"
33 #include "log.h"
34 #include "alpm.h"
35 #include "alpm_list.h"
36 #include "package.h"
37 #include "handle.h"
38 #include "delta.h"
39 #include "deps.h"
40 #include "dload.h"
42 static char *get_sync_dir(alpm_handle_t *handle)
44 const char *dbpath = alpm_option_get_dbpath(handle);
45 size_t len = strlen(dbpath) + 6;
46 char *syncpath;
47 struct stat buf;
49 MALLOC(syncpath, len, RET_ERR(handle, PM_ERR_MEMORY, NULL));
50 sprintf(syncpath, "%s%s", dbpath, "sync/");
52 if(stat(syncpath, &buf) != 0) {
53 _alpm_log(handle, PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
54 syncpath);
55 if(_alpm_makepath(syncpath) != 0) {
56 free(syncpath);
57 RET_ERR(handle, PM_ERR_SYSTEM, NULL);
59 } else if(!S_ISDIR(buf.st_mode)) {
60 _alpm_log(handle, PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
61 if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
62 free(syncpath);
63 RET_ERR(handle, PM_ERR_SYSTEM, NULL);
67 return syncpath;
70 static int sync_db_validate(pmdb_t *db)
72 pgp_verify_t check_sig;
74 if(db->status & DB_STATUS_VALID) {
75 return 0;
78 /* this takes into account the default verification level if UNKNOWN
79 * was assigned to this db */
80 check_sig = _alpm_db_get_sigverify_level(db);
82 if(check_sig != PM_PGP_VERIFY_NEVER) {
83 int ret;
84 const char *dbpath = _alpm_db_path(db);
85 if(!dbpath) {
86 /* pm_errno set in _alpm_db_path() */
87 return -1;
90 /* we can skip any validation if the database doesn't exist */
91 if(access(dbpath, R_OK) != 0 && errno == ENOENT) {
92 goto valid;
93 return 0;
96 _alpm_log(db->handle, PM_LOG_DEBUG, "checking signature for %s\n",
97 db->treename);
98 ret = _alpm_gpgme_checksig(db->handle, dbpath, NULL);
99 if((check_sig == PM_PGP_VERIFY_ALWAYS && ret != 0) ||
100 (check_sig == PM_PGP_VERIFY_OPTIONAL && ret == 1)) {
101 RET_ERR(db->handle, PM_ERR_SIG_INVALID, -1);
105 valid:
106 db->status |= DB_STATUS_VALID;
107 return 0;
110 /** Update a package database
112 * An update of the package database \a db will be attempted. Unless
113 * \a force is true, the update will only be performed if the remote
114 * database was modified since the last update.
116 * This operation requires a database lock, and will return an applicable error
117 * if the lock could not be obtained.
119 * Example:
120 * @code
121 * alpm_list_t *syncs = alpm_option_get_syncdbs();
122 * for(i = syncs; i; i = alpm_list_next(i)) {
123 * pmdb_t *db = alpm_list_getdata(i);
124 * result = alpm_db_update(0, db);
126 * if(result < 0) {
127 * printf("Unable to update database: %s\n", alpm_strerrorlast());
128 * } else if(result == 1) {
129 * printf("Database already up to date\n");
130 * } else {
131 * printf("Database updated\n");
134 * @endcode
136 * @ingroup alpm_databases
137 * @note After a successful update, the \link alpm_db_get_pkgcache()
138 * package cache \endlink will be invalidated
139 * @param force if true, then forces the update, otherwise update only in case
140 * the database isn't up to date
141 * @param db pointer to the package database to update
142 * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
143 * to date
145 int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
147 char *syncpath;
148 alpm_list_t *i;
149 int ret = -1;
150 mode_t oldmask;
151 alpm_handle_t *handle;
152 pgp_verify_t check_sig;
154 /* Sanity checks */
155 ASSERT(db != NULL, return -1);
156 handle = db->handle;
157 handle->pm_errno = 0;
158 ASSERT(db != handle->db_local, RET_ERR(handle, PM_ERR_WRONG_ARGS, -1));
159 ASSERT(db->servers != NULL, RET_ERR(handle, PM_ERR_SERVER_NONE, -1));
161 syncpath = get_sync_dir(handle);
162 if(!syncpath) {
163 return -1;
166 /* make sure we have a sane umask */
167 oldmask = umask(0022);
169 check_sig = _alpm_db_get_sigverify_level(db);
171 /* attempt to grab a lock */
172 if(_alpm_handle_lock(handle)) {
173 RET_ERR(handle, PM_ERR_HANDLE_LOCK, -1);
176 for(i = db->servers; i; i = i->next) {
177 const char *server = i->data;
178 char *fileurl;
179 size_t len;
180 int sig_ret = 0;
182 /* print server + filename into a buffer (leave space for .sig) */
183 len = strlen(server) + strlen(db->treename) + 9;
184 CALLOC(fileurl, len, sizeof(char), RET_ERR(handle, PM_ERR_MEMORY, -1));
185 snprintf(fileurl, len, "%s/%s.db", server, db->treename);
187 ret = _alpm_download(handle, fileurl, syncpath, force, 0, 0);
189 if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS ||
190 check_sig == PM_PGP_VERIFY_OPTIONAL)) {
191 /* an existing sig file is no good at this point */
192 char *sigpath = _alpm_db_sig_path(db);
193 if(!sigpath) {
194 ret = -1;
195 break;
197 unlink(sigpath);
198 free(sigpath);
200 int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL);
201 /* if we downloaded a DB, we want the .sig from the same server */
202 snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename);
204 sig_ret = _alpm_download(handle, fileurl, syncpath, 1, 0, errors_ok);
205 /* errors_ok suppresses error messages, but not the return code */
206 sig_ret = errors_ok ? 0 : sig_ret;
209 FREE(fileurl);
210 if(ret != -1 && sig_ret != -1) {
211 break;
215 if(ret == 1) {
216 /* files match, do nothing */
217 handle->pm_errno = 0;
218 goto cleanup;
219 } else if(ret == -1) {
220 /* pm_errno was set by the download code */
221 _alpm_log(handle, PM_LOG_DEBUG, "failed to sync db: %s\n",
222 alpm_strerror(handle->pm_errno));
223 goto cleanup;
226 /* Cache needs to be rebuilt */
227 _alpm_db_free_pkgcache(db);
229 db->status &= ~DB_STATUS_VALID;
230 if(sync_db_validate(db)) {
231 /* pm_errno should be set */
232 ret = -1;
235 cleanup:
237 if(_alpm_handle_unlock(handle)) {
238 _alpm_log(handle, PM_LOG_WARNING, _("could not remove lock file %s\n"),
239 alpm_option_get_lockfile(handle));
241 free(syncpath);
242 umask(oldmask);
243 return ret;
246 /* Forward decl so I don't reorganize the whole file right now */
247 static int sync_db_read(pmdb_t *db, struct archive *archive,
248 struct archive_entry *entry, pmpkg_t **likely_pkg);
250 static pmpkg_t *load_pkg_for_entry(pmdb_t *db, const char *entryname,
251 const char **entry_filename, pmpkg_t *likely_pkg)
253 char *pkgname = NULL, *pkgver = NULL;
254 unsigned long pkgname_hash;
255 pmpkg_t *pkg;
257 /* get package and db file names */
258 if(entry_filename) {
259 char *fname = strrchr(entryname, '/');
260 if(fname) {
261 *entry_filename = fname + 1;
262 } else {
263 *entry_filename = NULL;
266 if(_alpm_splitname(entryname, &pkgname, &pkgver, &pkgname_hash) != 0) {
267 _alpm_log(db->handle, PM_LOG_ERROR,
268 _("invalid name for database entry '%s'\n"), entryname);
269 return NULL;
272 if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) {
273 pkg = likely_pkg;
274 } else {
275 pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
277 if(pkg == NULL) {
278 pkg = _alpm_pkg_new();
279 if(pkg == NULL) {
280 RET_ERR(db->handle, PM_ERR_MEMORY, NULL);
283 pkg->name = pkgname;
284 pkg->version = pkgver;
285 pkg->name_hash = pkgname_hash;
287 pkg->origin = PKG_FROM_SYNCDB;
288 pkg->origin_data.db = db;
289 pkg->ops = &default_pkg_ops;
290 pkg->handle = db->handle;
292 /* add to the collection */
293 _alpm_log(db->handle, PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
294 pkg->name, db->treename);
295 db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg);
296 } else {
297 free(pkgname);
298 free(pkgver);
301 return pkg;
305 * This is the data table used to generate the estimating function below.
306 * "Weighted Avg" means averaging the bottom table values; thus each repo, big
307 * or small, will have equal influence. "Unweighted Avg" means averaging the
308 * sums of the top table columns, thus each package has equal influence. The
309 * final values are calculated by (surprise) averaging the averages, because
310 * why the hell not.
312 * Database Pkgs tar bz2 gz xz
313 * community 2096 5294080 256391 421227 301296
314 * core 180 460800 25257 36850 29356
315 * extra 2606 6635520 294647 470818 339392
316 * multilib 126 327680 16120 23261 18732
317 * testing 76 204800 10902 14348 12100
319 * Bytes Per Package
320 * community 2096 2525.80 122.32 200.97 143.75
321 * core 180 2560.00 140.32 204.72 163.09
322 * extra 2606 2546.25 113.06 180.67 130.23
323 * multilib 126 2600.63 127.94 184.61 148.67
324 * testing 76 2694.74 143.45 188.79 159.21
326 * Weighted Avg 2585.48 129.42 191.95 148.99
327 * Unweighted Avg 2543.39 118.74 190.16 137.93
328 * Average of Avgs 2564.44 124.08 191.06 143.46
330 static size_t estimate_package_count(struct stat *st, struct archive *archive)
332 unsigned int per_package;
334 switch(archive_compression(archive)) {
335 case ARCHIVE_COMPRESSION_NONE:
336 per_package = 2564;
337 break;
338 case ARCHIVE_COMPRESSION_GZIP:
339 per_package = 191;
340 break;
341 case ARCHIVE_COMPRESSION_BZIP2:
342 per_package = 124;
343 break;
344 case ARCHIVE_COMPRESSION_COMPRESS:
345 per_package = 193;
346 break;
347 case ARCHIVE_COMPRESSION_LZMA:
348 case ARCHIVE_COMPRESSION_XZ:
349 per_package = 143;
350 break;
351 #ifdef ARCHIVE_COMPRESSION_UU
352 case ARCHIVE_COMPRESSION_UU:
353 per_package = 3543;
354 break;
355 #endif
356 default:
357 /* assume it is at least somewhat compressed */
358 per_package = 200;
360 return (size_t)((st->st_size / per_package) + 1);
363 static int sync_db_populate(pmdb_t *db)
365 const char *dbpath;
366 size_t est_count;
367 int count = 0;
368 struct stat buf;
369 struct archive *archive;
370 struct archive_entry *entry;
371 pmpkg_t *pkg = NULL;
373 if((archive = archive_read_new()) == NULL) {
374 RET_ERR(db->handle, PM_ERR_LIBARCHIVE, -1);
377 archive_read_support_compression_all(archive);
378 archive_read_support_format_all(archive);
380 dbpath = _alpm_db_path(db);
381 if(!dbpath) {
382 /* pm_errno set in _alpm_db_path() */
383 return -1;
386 _alpm_log(db->handle, PM_LOG_DEBUG, "opening database archive %s\n", dbpath);
388 if(archive_read_open_filename(archive, dbpath,
389 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
390 _alpm_log(db->handle, PM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath,
391 archive_error_string(archive));
392 archive_read_finish(archive);
393 RET_ERR(db->handle, PM_ERR_DB_OPEN, -1);
395 if(stat(dbpath, &buf) != 0) {
396 RET_ERR(db->handle, PM_ERR_DB_OPEN, -1);
398 est_count = estimate_package_count(&buf, archive);
400 /* initialize hash at 66% full */
401 db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);
402 if(db->pkgcache == NULL) {
403 RET_ERR(db->handle, PM_ERR_MEMORY, -1);
406 while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
407 const struct stat *st;
409 st = archive_entry_stat(entry);
411 if(S_ISDIR(st->st_mode)) {
412 continue;
413 } else {
414 /* we have desc, depends or deltas - parse it */
415 if(sync_db_read(db, archive, entry, &pkg) != 0) {
416 _alpm_log(db->handle, PM_LOG_ERROR,
417 _("could not parse package description file '%s' from db '%s'\n"),
418 archive_entry_pathname(entry), db->treename);
419 continue;
424 count = alpm_list_count(db->pkgcache->list);
426 if(count > 0) {
427 db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
429 archive_read_finish(archive);
430 _alpm_log(db->handle, PM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n",
431 count, db->treename);
433 return count;
436 #define READ_NEXT(s) do { \
437 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
438 s = _alpm_strtrim(buf.line); \
439 } while(0)
441 #define READ_AND_STORE(f) do { \
442 READ_NEXT(line); \
443 STRDUP(f, line, goto error); \
444 } while(0)
446 #define READ_AND_STORE_ALL(f) do { \
447 char *linedup; \
448 READ_NEXT(line); \
449 if(strlen(line) == 0) break; \
450 STRDUP(linedup, line, goto error); \
451 f = alpm_list_add(f, linedup); \
452 } while(1) /* note the while(1) and not (0) */
454 static int sync_db_read(pmdb_t *db, struct archive *archive,
455 struct archive_entry *entry, pmpkg_t **likely_pkg)
457 const char *entryname, *filename;
458 pmpkg_t *pkg;
459 struct archive_read_buffer buf;
461 entryname = archive_entry_pathname(entry);
462 if(entryname == NULL) {
463 _alpm_log(db->handle, PM_LOG_DEBUG,
464 "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
465 return -1;
468 _alpm_log(db->handle, PM_LOG_FUNCTION, "loading package data from archive entry %s\n",
469 entryname);
471 memset(&buf, 0, sizeof(buf));
472 /* 512K for a line length seems reasonable */
473 buf.max_line_size = 512 * 1024;
475 pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);
477 if(pkg == NULL) {
478 _alpm_log(db->handle, PM_LOG_DEBUG,
479 "entry %s could not be loaded into %s sync database",
480 entryname, db->treename);
481 return -1;
484 if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
485 || strcmp(filename, "deltas") == 0) {
486 int ret;
487 while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
488 char *line = _alpm_strtrim(buf.line);
490 if(strcmp(line, "%NAME%") == 0) {
491 READ_NEXT(line);
492 if(strcmp(line, pkg->name) != 0) {
493 _alpm_log(db->handle, PM_LOG_ERROR, _("%s database is inconsistent: name "
494 "mismatch on package %s\n"), db->treename, pkg->name);
496 } else if(strcmp(line, "%VERSION%") == 0) {
497 READ_NEXT(line);
498 if(strcmp(line, pkg->version) != 0) {
499 _alpm_log(db->handle, PM_LOG_ERROR, _("%s database is inconsistent: version "
500 "mismatch on package %s\n"), db->treename, pkg->name);
502 } else if(strcmp(line, "%FILENAME%") == 0) {
503 READ_AND_STORE(pkg->filename);
504 } else if(strcmp(line, "%DESC%") == 0) {
505 READ_AND_STORE(pkg->desc);
506 } else if(strcmp(line, "%GROUPS%") == 0) {
507 READ_AND_STORE_ALL(pkg->groups);
508 } else if(strcmp(line, "%URL%") == 0) {
509 READ_AND_STORE(pkg->url);
510 } else if(strcmp(line, "%LICENSE%") == 0) {
511 READ_AND_STORE_ALL(pkg->licenses);
512 } else if(strcmp(line, "%ARCH%") == 0) {
513 READ_AND_STORE(pkg->arch);
514 } else if(strcmp(line, "%BUILDDATE%") == 0) {
515 READ_NEXT(line);
516 pkg->builddate = _alpm_parsedate(line);
517 } else if(strcmp(line, "%PACKAGER%") == 0) {
518 READ_AND_STORE(pkg->packager);
519 } else if(strcmp(line, "%CSIZE%") == 0) {
520 /* Note: the CSIZE and SIZE fields both share the "size" field in the
521 * pkginfo_t struct. This can be done b/c CSIZE is currently only used
522 * in sync databases, and SIZE is only used in local databases.
524 READ_NEXT(line);
525 pkg->size = atol(line);
526 /* also store this value to isize if isize is unset */
527 if(pkg->isize == 0) {
528 pkg->isize = pkg->size;
530 } else if(strcmp(line, "%ISIZE%") == 0) {
531 READ_NEXT(line);
532 pkg->isize = atol(line);
533 } else if(strcmp(line, "%MD5SUM%") == 0) {
534 READ_AND_STORE(pkg->md5sum);
535 } else if(strcmp(line, "%SHA256SUM%") == 0) {
536 /* we don't do anything with this value right now */
537 READ_NEXT(line);
538 } else if(strcmp(line, "%PGPSIG%") == 0) {
539 READ_AND_STORE(pkg->base64_sig);
540 } else if(strcmp(line, "%REPLACES%") == 0) {
541 READ_AND_STORE_ALL(pkg->replaces);
542 } else if(strcmp(line, "%DEPENDS%") == 0) {
543 /* Different than the rest because of the _alpm_splitdep call. */
544 while(1) {
545 READ_NEXT(line);
546 if(strlen(line) == 0) break;
547 pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line));
549 } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
550 READ_AND_STORE_ALL(pkg->optdepends);
551 } else if(strcmp(line, "%CONFLICTS%") == 0) {
552 READ_AND_STORE_ALL(pkg->conflicts);
553 } else if(strcmp(line, "%PROVIDES%") == 0) {
554 READ_AND_STORE_ALL(pkg->provides);
555 } else if(strcmp(line, "%DELTAS%") == 0) {
556 /* Different than the rest because of the _alpm_delta_parse call. */
557 while(1) {
558 READ_NEXT(line);
559 if(strlen(line) == 0) break;
560 pkg->deltas = alpm_list_add(pkg->deltas, _alpm_delta_parse(line));
564 if(ret != ARCHIVE_EOF) {
565 goto error;
567 *likely_pkg = pkg;
568 } else if(strcmp(filename, "files") == 0) {
569 /* currently do nothing with this file */
570 } else {
571 /* unknown database file */
572 _alpm_log(db->handle, PM_LOG_DEBUG, "unknown database file: %s\n", filename);
575 return 0;
577 error:
578 _alpm_log(db->handle, PM_LOG_DEBUG, "error parsing database file: %s\n", filename);
579 return -1;
582 struct db_operations sync_db_ops = {
583 .populate = sync_db_populate,
584 .unregister = _alpm_db_unregister,
587 pmdb_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
588 pgp_verify_t level)
590 pmdb_t *db;
592 _alpm_log(handle, PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
594 db = _alpm_db_new(treename, 0);
595 if(db == NULL) {
596 RET_ERR(handle, PM_ERR_DB_CREATE, NULL);
598 db->ops = &sync_db_ops;
599 db->handle = handle;
600 db->pgp_verify = level;
602 if(sync_db_validate(db)) {
603 _alpm_db_free(db);
604 return NULL;
607 handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
608 return db;
612 /* vim: set ts=2 sw=2 noet: */