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/>.
27 #include <archive_entry.h>
33 #include "alpm_list.h"
40 /** Update a package database
42 * An update of the package database \a db will be attempted. Unless
43 * \a force is true, the update will only be performed if the remote
44 * database was modified since the last update.
46 * A transaction is necessary for this operation, in order to obtain a
47 * database lock. During this transaction the front-end will be informed
48 * of the download progress of the database via the download callback.
52 * alpm_list_t *syncs = alpm_option_get_syncdbs();
53 * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
54 * for(i = syncs; i; i = alpm_list_next(i)) {
55 * pmdb_t *db = alpm_list_getdata(i);
56 * result = alpm_db_update(0, db);
57 * alpm_trans_release();
60 * printf("Unable to update database: %s\n", alpm_strerrorlast());
61 * } else if(result == 1) {
62 * printf("Database already up to date\n");
64 * printf("Database updated\n");
70 * @ingroup alpm_databases
71 * @note After a successful update, the \link alpm_db_get_pkgcache()
72 * package cache \endlink will be invalidated
73 * @param force if true, then forces the update, otherwise update only in case
74 * the database isn't up to date
75 * @param db pointer to the package database to update
76 * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
79 int SYMEXPORT
alpm_db_update(int force
, pmdb_t
*db
)
81 char *dbfile
, *syncpath
;
91 ASSERT(handle
!= NULL
, RET_ERR(PM_ERR_HANDLE_NULL
, -1));
92 ASSERT(db
!= NULL
&& db
!= handle
->db_local
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
94 if(!alpm_list_find_ptr(handle
->dbs_sync
, db
)) {
95 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
98 len
= strlen(db
->treename
) + 4;
99 MALLOC(dbfile
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
100 sprintf(dbfile
, "%s.db", db
->treename
);
102 dbpath
= alpm_option_get_dbpath();
103 len
= strlen(dbpath
) + 6;
104 MALLOC(syncpath
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
105 sprintf(syncpath
, "%s%s", dbpath
, "sync/");
107 /* make sure we have a sane umask */
108 oldmask
= umask(0022);
110 if(stat(syncpath
, &buf
) != 0) {
111 _alpm_log(PM_LOG_DEBUG
, "database dir '%s' does not exist, creating it\n",
113 if(_alpm_makepath(syncpath
) != 0) {
116 RET_ERR(PM_ERR_SYSTEM
, -1);
118 } else if(!S_ISDIR(buf
.st_mode
)) {
119 _alpm_log(PM_LOG_WARNING
, _("removing invalid file: %s\n"), syncpath
);
120 if(unlink(syncpath
) != 0 || _alpm_makepath(syncpath
) != 0) {
123 RET_ERR(PM_ERR_SYSTEM
, -1);
127 ret
= _alpm_download_single_file(dbfile
, db
->servers
, syncpath
, force
);
130 /* files match, do nothing */
133 } else if(ret
== -1) {
134 /* pm_errno was set by the download code */
135 _alpm_log(PM_LOG_DEBUG
, "failed to sync db: %s\n", alpm_strerrorlast());
139 /* Download and check the signature of the database if needed */
140 if(db
->pgp_verify
!= PM_PGP_VERIFY_NEVER
) {
141 char *sigfile
, *sigfilepath
;
144 len
= strlen(dbfile
) + 5;
145 MALLOC(sigfile
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
146 sprintf(sigfile
, "%s.sig", dbfile
);
148 /* prevent old signature being used if the following download fails */
149 len
= strlen(syncpath
) + strlen(sigfile
) + 1;
150 MALLOC(sigfilepath
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
151 sprintf(sigfilepath
, "%s%s", syncpath
, sigfile
);
152 _alpm_rmrf(sigfilepath
);
155 sigret
= _alpm_download_single_file(sigfile
, db
->servers
, syncpath
, 0);
158 if(sigret
== -1 && db
->pgp_verify
== PM_PGP_VERIFY_ALWAYS
) {
159 _alpm_log(PM_LOG_ERROR
, _("Failed to download signature for db: %s\n"),
160 alpm_strerrorlast());
161 pm_errno
= PM_ERR_SIG_INVALID
;
166 sigret
= alpm_db_check_pgp_signature(db
);
167 if((db
->pgp_verify
== PM_PGP_VERIFY_ALWAYS
&& sigret
!= 0) ||
168 (db
->pgp_verify
== PM_PGP_VERIFY_OPTIONAL
&& sigret
== 1)) {
169 /* pm_errno was set by the checking code */
170 /* TODO: should we just leave the unverified database */
176 /* Cache needs to be rebuilt */
177 _alpm_db_free_pkgcache(db
);
187 /* Forward decl so I don't reorganize the whole file right now */
188 static int sync_db_read(pmdb_t
*db
, struct archive
*archive
,
189 struct archive_entry
*entry
, pmpkg_t
*likely_pkg
);
192 * This is the data table used to generate the estimating function below.
193 * "Weighted Avg" means averaging the bottom table values; thus each repo, big
194 * or small, will have equal influence. "Unweighted Avg" means averaging the
195 * sums of the top table columns, thus each package has equal influence. The
196 * final values are calculated by (surprise) averaging the averages, because
199 * Database Pkgs tar bz2 gz xz
200 * community 2096 5294080 256391 421227 301296
201 * core 180 460800 25257 36850 29356
202 * extra 2606 6635520 294647 470818 339392
203 * multilib 126 327680 16120 23261 18732
204 * testing 76 204800 10902 14348 12100
207 * community 2096 2525.80 122.32 200.97 143.75
208 * core 180 2560.00 140.32 204.72 163.09
209 * extra 2606 2546.25 113.06 180.67 130.23
210 * multilib 126 2600.63 127.94 184.61 148.67
211 * testing 76 2694.74 143.45 188.79 159.21
213 * Weighted Avg 2585.48 129.42 191.95 148.99
214 * Unweighted Avg 2543.39 118.74 190.16 137.93
215 * Average of Avgs 2564.44 124.08 191.06 143.46
217 static size_t estimate_package_count(struct stat
*st
, struct archive
*archive
)
219 unsigned int per_package
;
221 switch(archive_compression(archive
)) {
222 case ARCHIVE_COMPRESSION_NONE
:
225 case ARCHIVE_COMPRESSION_GZIP
:
228 case ARCHIVE_COMPRESSION_BZIP2
:
231 case ARCHIVE_COMPRESSION_COMPRESS
:
234 case ARCHIVE_COMPRESSION_LZMA
:
235 case ARCHIVE_COMPRESSION_XZ
:
238 #ifdef ARCHIVE_COMPRESSION_UU
239 case ARCHIVE_COMPRESSION_UU
:
244 /* assume it is at least somewhat compressed */
247 return (size_t)((st
->st_size
/ per_package
) + 1);
250 static int sync_db_populate(pmdb_t
*db
)
256 struct archive
*archive
;
257 struct archive_entry
*entry
;
262 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, -1));
264 if((archive
= archive_read_new()) == NULL
)
265 RET_ERR(PM_ERR_LIBARCHIVE
, 1);
267 archive_read_support_compression_all(archive
);
268 archive_read_support_format_all(archive
);
270 dbpath
= _alpm_db_path(db
);
272 /* pm_errno set in _alpm_db_path() */
276 _alpm_log(PM_LOG_DEBUG
, "opening database archive %s\n", dbpath
);
278 if(archive_read_open_filename(archive
, dbpath
,
279 ARCHIVE_DEFAULT_BYTES_PER_BLOCK
) != ARCHIVE_OK
) {
280 _alpm_log(PM_LOG_ERROR
, _("could not open file %s: %s\n"), dbpath
,
281 archive_error_string(archive
));
282 archive_read_finish(archive
);
283 RET_ERR(PM_ERR_DB_OPEN
, 1);
285 if(stat(dbpath
, &buf
) != 0) {
286 RET_ERR(PM_ERR_DB_OPEN
, 1);
288 est_count
= estimate_package_count(&buf
, archive
);
290 /* initialize hash at 66% full */
291 db
->pkgcache
= _alpm_pkghash_create(est_count
* 3 / 2);
292 if(db
->pkgcache
== NULL
) {
293 RET_ERR(PM_ERR_MEMORY
, -1);
296 while(archive_read_next_header(archive
, &entry
) == ARCHIVE_OK
) {
297 const struct stat
*st
;
299 st
= archive_entry_stat(entry
);
301 if(S_ISDIR(st
->st_mode
)) {
304 pkg
= _alpm_pkg_new();
306 archive_read_finish(archive
);
307 RET_ERR(PM_ERR_MEMORY
, -1);
310 name
= archive_entry_pathname(entry
);
312 if(_alpm_splitname(name
, pkg
) != 0) {
313 _alpm_log(PM_LOG_ERROR
, _("invalid name for database entry '%s'\n"),
319 /* duplicated database entries are not allowed */
320 if(_alpm_pkghash_find(db
->pkgcache
, pkg
->name
)) {
321 _alpm_log(PM_LOG_ERROR
, _("duplicated database entry '%s'\n"), pkg
->name
);
326 pkg
->origin
= PKG_FROM_SYNCDB
;
327 pkg
->ops
= &default_pkg_ops
;
328 pkg
->origin_data
.db
= db
;
330 /* add to the collection */
331 _alpm_log(PM_LOG_FUNCTION
, "adding '%s' to package cache for db '%s'\n",
332 pkg
->name
, db
->treename
);
333 db
->pkgcache
= _alpm_pkghash_add(db
->pkgcache
, pkg
);
336 /* we have desc, depends or deltas - parse it */
337 sync_db_read(db
, archive
, entry
, pkg
);
342 db
->pkgcache
->list
= alpm_list_msort(db
->pkgcache
->list
, (size_t)count
, _alpm_pkg_cmp
);
344 archive_read_finish(archive
);
349 #define READ_NEXT(s) do { \
350 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
351 s = _alpm_strtrim(buf.line); \
354 #define READ_AND_STORE(f) do { \
356 STRDUP(f, line, goto error); \
359 #define READ_AND_STORE_ALL(f) do { \
362 if(strlen(line) == 0) break; \
363 STRDUP(linedup, line, goto error); \
364 f = alpm_list_add(f, linedup); \
365 } while(1) /* note the while(1) and not (0) */
367 static int sync_db_read(pmdb_t
*db
, struct archive
*archive
,
368 struct archive_entry
*entry
, pmpkg_t
*likely_pkg
)
370 const char *entryname
= NULL
, *filename
;
371 char *pkgname
, *p
, *q
;
373 struct archive_read_buffer buf
;
378 RET_ERR(PM_ERR_DB_NULL
, -1);
382 entryname
= archive_entry_pathname(entry
);
384 if(entryname
== NULL
) {
385 _alpm_log(PM_LOG_DEBUG
, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
389 _alpm_log(PM_LOG_FUNCTION
, "loading package data from archive entry %s\n",
392 memset(&buf
, 0, sizeof(buf
));
393 /* 512K for a line length seems reasonable */
394 buf
.max_line_size
= 512 * 1024;
396 /* get package and db file names */
397 STRDUP(pkgname
, entryname
, RET_ERR(PM_ERR_MEMORY
, -1));
398 p
= pkgname
+ strlen(pkgname
);
399 for(q
= --p
; *q
&& *q
!= '/'; q
--);
401 for(p
= --q
; *p
&& *p
!= '-'; p
--);
402 for(q
= --p
; *q
&& *q
!= '-'; q
--);
405 /* package is already in db due to parsing of directory name */
406 if(likely_pkg
&& strcmp(likely_pkg
->name
, pkgname
) == 0) {
409 if(db
->pkgcache
== NULL
) {
410 RET_ERR(PM_ERR_MEMORY
, -1);
412 pkg
= _alpm_pkghash_find(db
->pkgcache
, pkgname
);
415 _alpm_log(PM_LOG_DEBUG
, "package %s not found in %s sync database",
416 pkgname
, db
->treename
);
420 if(strcmp(filename
, "desc") == 0 || strcmp(filename
, "depends") == 0
421 || strcmp(filename
, "deltas") == 0) {
422 while(_alpm_archive_fgets(archive
, &buf
) == ARCHIVE_OK
) {
423 char *line
= _alpm_strtrim(buf
.line
);
425 if(strcmp(line
, "%NAME%") == 0) {
427 if(strcmp(line
, pkg
->name
) != 0) {
428 _alpm_log(PM_LOG_ERROR
, _("%s database is inconsistent: name "
429 "mismatch on package %s\n"), db
->treename
, pkg
->name
);
431 } else if(strcmp(line
, "%VERSION%") == 0) {
433 if(strcmp(line
, pkg
->version
) != 0) {
434 _alpm_log(PM_LOG_ERROR
, _("%s database is inconsistent: version "
435 "mismatch on package %s\n"), db
->treename
, pkg
->name
);
437 } else if(strcmp(line
, "%FILENAME%") == 0) {
438 READ_AND_STORE(pkg
->filename
);
439 } else if(strcmp(line
, "%DESC%") == 0) {
440 READ_AND_STORE(pkg
->desc
);
441 } else if(strcmp(line
, "%GROUPS%") == 0) {
442 READ_AND_STORE_ALL(pkg
->groups
);
443 } else if(strcmp(line
, "%URL%") == 0) {
444 READ_AND_STORE(pkg
->url
);
445 } else if(strcmp(line
, "%LICENSE%") == 0) {
446 READ_AND_STORE_ALL(pkg
->licenses
);
447 } else if(strcmp(line
, "%ARCH%") == 0) {
448 READ_AND_STORE(pkg
->arch
);
449 } else if(strcmp(line
, "%BUILDDATE%") == 0) {
451 pkg
->builddate
= _alpm_parsedate(line
);
452 } else if(strcmp(line
, "%PACKAGER%") == 0) {
453 READ_AND_STORE(pkg
->packager
);
454 } else if(strcmp(line
, "%CSIZE%") == 0) {
455 /* Note: the CSIZE and SIZE fields both share the "size" field in the
456 * pkginfo_t struct. This can be done b/c CSIZE is currently only used
457 * in sync databases, and SIZE is only used in local databases.
460 pkg
->size
= atol(line
);
461 /* also store this value to isize if isize is unset */
462 if(pkg
->isize
== 0) {
463 pkg
->isize
= pkg
->size
;
465 } else if(strcmp(line
, "%ISIZE%") == 0) {
467 pkg
->isize
= atol(line
);
468 } else if(strcmp(line
, "%MD5SUM%") == 0) {
469 READ_AND_STORE(pkg
->md5sum
);
470 } else if(strcmp(line
, "%SHA256SUM%") == 0) {
471 /* we don't do anything with this value right now */
473 } else if(strcmp(line
, "%PGPSIG%") == 0) {
474 READ_AND_STORE(pkg
->pgpsig
.base64_data
);
475 } else if(strcmp(line
, "%REPLACES%") == 0) {
476 READ_AND_STORE_ALL(pkg
->replaces
);
477 } else if(strcmp(line
, "%DEPENDS%") == 0) {
478 /* Different than the rest because of the _alpm_splitdep call. */
481 if(strlen(line
) == 0) break;
482 pkg
->depends
= alpm_list_add(pkg
->depends
, _alpm_splitdep(line
));
484 } else if(strcmp(line
, "%OPTDEPENDS%") == 0) {
485 READ_AND_STORE_ALL(pkg
->optdepends
);
486 } else if(strcmp(line
, "%CONFLICTS%") == 0) {
487 READ_AND_STORE_ALL(pkg
->conflicts
);
488 } else if(strcmp(line
, "%PROVIDES%") == 0) {
489 READ_AND_STORE_ALL(pkg
->provides
);
490 } else if(strcmp(line
, "%DELTAS%") == 0) {
491 /* Different than the rest because of the _alpm_delta_parse call. */
494 if(strlen(line
) == 0) break;
495 pkg
->deltas
= alpm_list_add(pkg
->deltas
, _alpm_delta_parse(line
));
499 } else if(strcmp(filename
, "files") == 0) {
500 /* currently do nothing with this file */
502 /* unknown database file */
503 _alpm_log(PM_LOG_DEBUG
, "unknown database file: %s\n", filename
);
508 /* TODO: return 0 always? */
512 static int sync_db_version(pmdb_t
*db
)
517 struct db_operations sync_db_ops
= {
518 .populate
= sync_db_populate
,
519 .unregister
= _alpm_db_unregister
,
520 .version
= sync_db_version
,
523 pmdb_t
*_alpm_db_register_sync(const char *treename
)
530 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
531 pmdb_t
*sdb
= i
->data
;
532 if(strcmp(treename
, sdb
->treename
) == 0) {
533 _alpm_log(PM_LOG_DEBUG
, "attempt to re-register the '%s' database, using existing\n", sdb
->treename
);
538 _alpm_log(PM_LOG_DEBUG
, "registering sync database '%s'\n", treename
);
540 db
= _alpm_db_new(treename
, 0);
542 RET_ERR(PM_ERR_DB_CREATE
, NULL
);
544 db
->ops
= &sync_db_ops
;
546 handle
->dbs_sync
= alpm_list_add(handle
->dbs_sync
, db
);
551 /* vim: set ts=2 sw=2 noet: */