Move important information up in -Si output
[pacman-ng.git] / lib / libalpm / be_sync.c
blob6bac6fbf5fdbc456745b0fe809bc17bcaaa8e06c
1 /*
2 * be_sync.c : backend for sync databases
4 * Copyright (c) 2006-2012 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 <errno.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.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 size_t len = strlen(handle->dbpath) + 6;
45 char *syncpath;
46 struct stat buf;
48 MALLOC(syncpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
49 sprintf(syncpath, "%s%s", handle->dbpath, "sync/");
51 if(stat(syncpath, &buf) != 0) {
52 _alpm_log(handle, ALPM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
53 syncpath);
54 if(_alpm_makepath(syncpath) != 0) {
55 free(syncpath);
56 RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
58 } else if(!S_ISDIR(buf.st_mode)) {
59 _alpm_log(handle, ALPM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
60 if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
61 free(syncpath);
62 RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
66 return syncpath;
69 static int sync_db_validate(alpm_db_t *db)
71 alpm_siglevel_t level;
72 const char *dbpath;
74 if(db->status & DB_STATUS_VALID || db->status & DB_STATUS_MISSING) {
75 return 0;
77 if(db->status & DB_STATUS_INVALID) {
78 db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
79 return -1;
82 dbpath = _alpm_db_path(db);
83 if(!dbpath) {
84 /* pm_errno set in _alpm_db_path() */
85 return -1;
88 /* we can skip any validation if the database doesn't exist */
89 if(_alpm_access(db->handle, NULL, dbpath, R_OK) != 0 && errno == ENOENT) {
90 db->status &= ~DB_STATUS_EXISTS;
91 db->status |= DB_STATUS_MISSING;
92 _alpm_log(db->handle, ALPM_LOG_WARNING,
93 "database file for '%s' does not exist\n", db->treename);
94 goto valid;
96 db->status |= DB_STATUS_EXISTS;
97 db->status &= ~DB_STATUS_MISSING;
99 /* this takes into account the default verification level if UNKNOWN
100 * was assigned to this db */
101 level = alpm_db_get_siglevel(db);
103 if(level & ALPM_SIG_DATABASE) {
104 int retry, ret;
105 do {
106 retry = 0;
107 alpm_siglist_t *siglist;
108 ret = _alpm_check_pgp_helper(db->handle, dbpath, NULL,
109 level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_DATABASE_MARGINAL_OK,
110 level & ALPM_SIG_DATABASE_UNKNOWN_OK, &siglist);
111 if(ret) {
112 retry = _alpm_process_siglist(db->handle, db->treename, siglist,
113 level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_DATABASE_MARGINAL_OK,
114 level & ALPM_SIG_DATABASE_UNKNOWN_OK);
116 alpm_siglist_cleanup(siglist);
117 free(siglist);
118 } while(retry);
120 if(ret) {
121 db->status &= ~DB_STATUS_VALID;
122 db->status |= DB_STATUS_INVALID;
123 db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
124 return 1;
128 valid:
129 db->status |= DB_STATUS_VALID;
130 db->status &= ~DB_STATUS_INVALID;
131 return 0;
134 /** Update a package database
136 * An update of the package database \a db will be attempted. Unless
137 * \a force is true, the update will only be performed if the remote
138 * database was modified since the last update.
140 * This operation requires a database lock, and will return an applicable error
141 * if the lock could not be obtained.
143 * Example:
144 * @code
145 * alpm_list_t *syncs = alpm_get_syncdbs();
146 * for(i = syncs; i; i = alpm_list_next(i)) {
147 * alpm_db_t *db = alpm_list_getdata(i);
148 * result = alpm_db_update(0, db);
150 * if(result < 0) {
151 * printf("Unable to update database: %s\n", alpm_strerrorlast());
152 * } else if(result == 1) {
153 * printf("Database already up to date\n");
154 * } else {
155 * printf("Database updated\n");
158 * @endcode
160 * @ingroup alpm_databases
161 * @note After a successful update, the \link alpm_db_get_pkgcache()
162 * package cache \endlink will be invalidated
163 * @param force if true, then forces the update, otherwise update only in case
164 * the database isn't up to date
165 * @param db pointer to the package database to update
166 * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
167 * to date
169 int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
171 char *syncpath;
172 alpm_list_t *i;
173 int ret = -1;
174 mode_t oldmask;
175 alpm_handle_t *handle;
176 alpm_siglevel_t level;
178 /* Sanity checks */
179 ASSERT(db != NULL, return -1);
180 handle = db->handle;
181 handle->pm_errno = 0;
182 ASSERT(db != handle->db_local, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
183 ASSERT(db->servers != NULL, RET_ERR(handle, ALPM_ERR_SERVER_NONE, -1));
185 syncpath = get_sync_dir(handle);
186 if(!syncpath) {
187 return -1;
190 /* make sure we have a sane umask */
191 oldmask = umask(0022);
193 level = alpm_db_get_siglevel(db);
195 /* attempt to grab a lock */
196 if(_alpm_handle_lock(handle)) {
197 free(syncpath);
198 umask(oldmask);
199 RET_ERR(handle, ALPM_ERR_HANDLE_LOCK, -1);
202 for(i = db->servers; i; i = i->next) {
203 const char *server = i->data;
204 struct dload_payload payload;
205 size_t len;
206 int sig_ret = 0;
208 memset(&payload, 0, sizeof(struct dload_payload));
210 /* set hard upper limit of 25MiB */
211 payload.max_size = 25 * 1024 * 1024;
213 /* print server + filename into a buffer */
214 len = strlen(server) + strlen(db->treename) + 5;
215 /* TODO fix leak syncpath and umask unset */
216 MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
217 snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename);
218 payload.handle = handle;
219 payload.force = force;
220 payload.unlink_on_fail = 1;
222 ret = _alpm_download(&payload, syncpath, NULL);
223 _alpm_dload_payload_reset(&payload);
225 if(ret == 0 && (level & ALPM_SIG_DATABASE)) {
226 /* an existing sig file is no good at this point */
227 char *sigpath = _alpm_sigpath(handle, _alpm_db_path(db));
228 if(!sigpath) {
229 ret = -1;
230 break;
232 unlink(sigpath);
233 free(sigpath);
235 /* if we downloaded a DB, we want the .sig from the same server */
236 /* print server + filename into a buffer (leave space for .sig) */
237 len = strlen(server) + strlen(db->treename) + 9;
238 /* TODO fix leak syncpath and umask unset */
239 MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
240 snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename);
241 payload.handle = handle;
242 payload.force = 1;
243 payload.errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL);
245 /* set hard upper limit of 16KiB */
246 payload.max_size = 16 * 1024;
248 sig_ret = _alpm_download(&payload, syncpath, NULL);
249 /* errors_ok suppresses error messages, but not the return code */
250 sig_ret = payload.errors_ok ? 0 : sig_ret;
251 _alpm_dload_payload_reset(&payload);
254 if(ret != -1 && sig_ret != -1) {
255 break;
259 if(ret == 1) {
260 /* files match, do nothing */
261 handle->pm_errno = 0;
262 goto cleanup;
263 } else if(ret == -1) {
264 /* pm_errno was set by the download code */
265 _alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync db: %s\n",
266 alpm_strerror(handle->pm_errno));
267 goto cleanup;
270 /* Cache needs to be rebuilt */
271 _alpm_db_free_pkgcache(db);
273 /* clear all status flags regarding validity/existence */
274 db->status &= ~DB_STATUS_VALID;
275 db->status &= ~DB_STATUS_INVALID;
276 db->status &= ~DB_STATUS_EXISTS;
277 db->status &= ~DB_STATUS_MISSING;
279 if(sync_db_validate(db)) {
280 /* pm_errno should be set */
281 ret = -1;
284 cleanup:
286 if(_alpm_handle_unlock(handle)) {
287 _alpm_log(handle, ALPM_LOG_WARNING, _("could not remove lock file %s\n"),
288 handle->lockfile);
290 free(syncpath);
291 umask(oldmask);
292 return ret;
295 /* Forward decl so I don't reorganize the whole file right now */
296 static int sync_db_read(alpm_db_t *db, struct archive *archive,
297 struct archive_entry *entry, alpm_pkg_t **likely_pkg);
299 static alpm_pkgvalidation_t _sync_get_validation(alpm_pkg_t *pkg)
301 if(pkg->validation) {
302 return pkg->validation;
305 if(pkg->md5sum) {
306 pkg->validation |= ALPM_PKG_VALIDATION_MD5SUM;
308 if(pkg->sha256sum) {
309 pkg->validation |= ALPM_PKG_VALIDATION_SHA256SUM;
311 if(pkg->base64_sig) {
312 pkg->validation |= ALPM_PKG_VALIDATION_SIGNATURE;
315 if(!pkg->validation) {
316 pkg->validation |= ALPM_PKG_VALIDATION_NONE;
319 return pkg->validation;
322 static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname,
323 const char **entry_filename, alpm_pkg_t *likely_pkg)
325 char *pkgname = NULL, *pkgver = NULL;
326 unsigned long pkgname_hash;
327 alpm_pkg_t *pkg;
329 /* get package and db file names */
330 if(entry_filename) {
331 char *fname = strrchr(entryname, '/');
332 if(fname) {
333 *entry_filename = fname + 1;
334 } else {
335 *entry_filename = NULL;
338 if(_alpm_splitname(entryname, &pkgname, &pkgver, &pkgname_hash) != 0) {
339 _alpm_log(db->handle, ALPM_LOG_ERROR,
340 _("invalid name for database entry '%s'\n"), entryname);
341 return NULL;
344 if(likely_pkg && pkgname_hash == likely_pkg->name_hash
345 && strcmp(likely_pkg->name, pkgname) == 0) {
346 pkg = likely_pkg;
347 } else {
348 pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
350 if(pkg == NULL) {
351 pkg = _alpm_pkg_new();
352 if(pkg == NULL) {
353 RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL);
356 pkg->name = pkgname;
357 pkg->version = pkgver;
358 pkg->name_hash = pkgname_hash;
360 pkg->origin = ALPM_PKG_FROM_SYNCDB;
361 pkg->origin_data.db = db;
362 pkg->ops = &default_pkg_ops;
363 pkg->ops->get_validation = _sync_get_validation;
364 pkg->handle = db->handle;
366 /* add to the collection */
367 _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
368 pkg->name, db->treename);
369 db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg);
370 } else {
371 free(pkgname);
372 free(pkgver);
375 return pkg;
378 /* This function doesn't work as well as one might think, as size of database
379 * entries varies considerably. Adding signatures nearly doubles the size of a
380 * single entry; deltas also can make for large variations in size. These
381 * current values are heavily influenced by Arch Linux; databases with no
382 * deltas and a single signature per package. */
383 static size_t estimate_package_count(struct stat *st, struct archive *archive)
385 int per_package;
387 switch(archive_compression(archive)) {
388 case ARCHIVE_COMPRESSION_NONE:
389 per_package = 3015;
390 break;
391 case ARCHIVE_COMPRESSION_GZIP:
392 case ARCHIVE_COMPRESSION_COMPRESS:
393 per_package = 464;
394 break;
395 case ARCHIVE_COMPRESSION_BZIP2:
396 per_package = 394;
397 break;
398 case ARCHIVE_COMPRESSION_LZMA:
399 case ARCHIVE_COMPRESSION_XZ:
400 per_package = 400;
401 break;
402 #ifdef ARCHIVE_COMPRESSION_UU
403 case ARCHIVE_COMPRESSION_UU:
404 per_package = 3015 * 4 / 3;
405 break;
406 #endif
407 default:
408 /* assume it is at least somewhat compressed */
409 per_package = 500;
411 return (size_t)((st->st_size / per_package) + 1);
414 static int sync_db_populate(alpm_db_t *db)
416 const char *dbpath;
417 size_t est_count;
418 int count, fd;
419 struct stat buf;
420 struct archive *archive;
421 struct archive_entry *entry;
422 alpm_pkg_t *pkg = NULL;
424 if(db->status & DB_STATUS_INVALID) {
425 RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
427 if(db->status & DB_STATUS_MISSING) {
428 RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
430 dbpath = _alpm_db_path(db);
431 if(!dbpath) {
432 /* pm_errno set in _alpm_db_path() */
433 return -1;
436 fd = _alpm_open_archive(db->handle, dbpath, &buf,
437 &archive, ALPM_ERR_DB_OPEN);
438 if(fd < 0) {
439 return -1;
441 est_count = estimate_package_count(&buf, archive);
443 db->pkgcache = _alpm_pkghash_create(est_count);
444 if(db->pkgcache == NULL) {
445 db->handle->pm_errno = ALPM_ERR_MEMORY;
446 count = -1;
447 goto cleanup;
450 while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
451 mode_t mode = archive_entry_mode(entry);
452 if(S_ISDIR(mode)) {
453 continue;
454 } else {
455 /* we have desc, depends or deltas - parse it */
456 if(sync_db_read(db, archive, entry, &pkg) != 0) {
457 _alpm_log(db->handle, ALPM_LOG_ERROR,
458 _("could not parse package description file '%s' from db '%s'\n"),
459 archive_entry_pathname(entry), db->treename);
460 continue;
465 count = alpm_list_count(db->pkgcache->list);
466 if(count > 0) {
467 db->pkgcache->list = alpm_list_msort(db->pkgcache->list,
468 (size_t)count, _alpm_pkg_cmp);
470 _alpm_log(db->handle, ALPM_LOG_DEBUG,
471 "added %d packages to package cache for db '%s'\n",
472 count, db->treename);
474 cleanup:
475 archive_read_finish(archive);
476 if(fd >= 0) {
477 CLOSE(fd);
479 return count;
482 #define READ_NEXT() do { \
483 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
484 line = buf.line; \
485 _alpm_strip_newline(line, buf.real_line_size); \
486 } while(0)
488 #define READ_AND_STORE(f) do { \
489 READ_NEXT(); \
490 STRDUP(f, line, goto error); \
491 } while(0)
493 #define READ_AND_STORE_ALL(f) do { \
494 char *linedup; \
495 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
496 if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
497 STRDUP(linedup, buf.line, goto error); \
498 f = alpm_list_add(f, linedup); \
499 } while(1) /* note the while(1) and not (0) */
501 #define READ_AND_SPLITDEP(f) do { \
502 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
503 if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
504 f = alpm_list_add(f, _alpm_splitdep(line)); \
505 } while(1) /* note the while(1) and not (0) */
507 static int sync_db_read(alpm_db_t *db, struct archive *archive,
508 struct archive_entry *entry, alpm_pkg_t **likely_pkg)
510 const char *entryname, *filename;
511 alpm_pkg_t *pkg;
512 struct archive_read_buffer buf;
514 entryname = archive_entry_pathname(entry);
515 if(entryname == NULL) {
516 _alpm_log(db->handle, ALPM_LOG_DEBUG,
517 "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
518 return -1;
521 _alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data from archive entry %s\n",
522 entryname);
524 memset(&buf, 0, sizeof(buf));
525 /* 512K for a line length seems reasonable */
526 buf.max_line_size = 512 * 1024;
528 pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);
530 if(pkg == NULL) {
531 _alpm_log(db->handle, ALPM_LOG_DEBUG,
532 "entry %s could not be loaded into %s sync database",
533 entryname, db->treename);
534 return -1;
537 if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
538 || strcmp(filename, "deltas") == 0) {
539 int ret;
540 while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
541 char *line = buf.line;
542 if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
543 /* length of stripped line was zero */
544 continue;
547 if(strcmp(line, "%NAME%") == 0) {
548 READ_NEXT();
549 if(strcmp(line, pkg->name) != 0) {
550 _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
551 "mismatch on package %s\n"), db->treename, pkg->name);
553 } else if(strcmp(line, "%VERSION%") == 0) {
554 READ_NEXT();
555 if(strcmp(line, pkg->version) != 0) {
556 _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
557 "mismatch on package %s\n"), db->treename, pkg->name);
559 } else if(strcmp(line, "%FILENAME%") == 0) {
560 READ_AND_STORE(pkg->filename);
561 } else if(strcmp(line, "%DESC%") == 0) {
562 READ_AND_STORE(pkg->desc);
563 } else if(strcmp(line, "%GROUPS%") == 0) {
564 READ_AND_STORE_ALL(pkg->groups);
565 } else if(strcmp(line, "%URL%") == 0) {
566 READ_AND_STORE(pkg->url);
567 } else if(strcmp(line, "%LICENSE%") == 0) {
568 READ_AND_STORE_ALL(pkg->licenses);
569 } else if(strcmp(line, "%ARCH%") == 0) {
570 READ_AND_STORE(pkg->arch);
571 } else if(strcmp(line, "%BUILDDATE%") == 0) {
572 READ_NEXT();
573 pkg->builddate = _alpm_parsedate(line);
574 } else if(strcmp(line, "%PACKAGER%") == 0) {
575 READ_AND_STORE(pkg->packager);
576 } else if(strcmp(line, "%CSIZE%") == 0) {
577 READ_NEXT();
578 pkg->size = _alpm_strtoofft(line);
579 } else if(strcmp(line, "%ISIZE%") == 0) {
580 READ_NEXT();
581 pkg->isize = _alpm_strtoofft(line);
582 } else if(strcmp(line, "%MD5SUM%") == 0) {
583 READ_AND_STORE(pkg->md5sum);
584 } else if(strcmp(line, "%SHA256SUM%") == 0) {
585 READ_AND_STORE(pkg->sha256sum);
586 } else if(strcmp(line, "%PGPSIG%") == 0) {
587 READ_AND_STORE(pkg->base64_sig);
588 } else if(strcmp(line, "%REPLACES%") == 0) {
589 READ_AND_SPLITDEP(pkg->replaces);
590 } else if(strcmp(line, "%DEPENDS%") == 0) {
591 READ_AND_SPLITDEP(pkg->depends);
592 } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
593 READ_AND_SPLITDEP(pkg->optdepends);
594 } else if(strcmp(line, "%MAKEDEPENDS%") == 0) {
595 /* currently unused */
596 while(1) {
597 READ_NEXT();
598 if(strlen(line) == 0) break;
600 } else if(strcmp(line, "%CHECKDEPENDS%") == 0) {
601 /* currently unused */
602 while(1) {
603 READ_NEXT();
604 if(strlen(line) == 0) break;
606 } else if(strcmp(line, "%CONFLICTS%") == 0) {
607 READ_AND_SPLITDEP(pkg->conflicts);
608 } else if(strcmp(line, "%PROVIDES%") == 0) {
609 READ_AND_SPLITDEP(pkg->provides);
610 } else if(strcmp(line, "%DELTAS%") == 0) {
611 /* Different than the rest because of the _alpm_delta_parse call. */
612 while(1) {
613 READ_NEXT();
614 if(strlen(line) == 0) break;
615 pkg->deltas = alpm_list_add(pkg->deltas,
616 _alpm_delta_parse(db->handle, line));
620 if(ret != ARCHIVE_EOF) {
621 goto error;
623 *likely_pkg = pkg;
624 } else if(strcmp(filename, "files") == 0) {
625 /* currently do nothing with this file */
626 } else {
627 /* unknown database file */
628 _alpm_log(db->handle, ALPM_LOG_DEBUG, "unknown database file: %s\n", filename);
631 return 0;
633 error:
634 _alpm_log(db->handle, ALPM_LOG_DEBUG, "error parsing database file: %s\n", filename);
635 return -1;
638 struct db_operations sync_db_ops = {
639 .validate = sync_db_validate,
640 .populate = sync_db_populate,
641 .unregister = _alpm_db_unregister,
644 alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
645 alpm_siglevel_t level)
647 alpm_db_t *db;
649 _alpm_log(handle, ALPM_LOG_DEBUG, "registering sync database '%s'\n", treename);
651 #ifndef HAVE_LIBGPGME
652 if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
653 RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);
655 #endif
657 db = _alpm_db_new(treename, 0);
658 if(db == NULL) {
659 RET_ERR(handle, ALPM_ERR_DB_CREATE, NULL);
661 db->ops = &sync_db_ops;
662 db->handle = handle;
663 db->siglevel = level;
665 sync_db_validate(db);
667 handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
668 return db;
671 /* vim: set ts=2 sw=2 noet: */