Use standard errno codes in return from _alpm_archive_fgets
[pacman-ng.git] / lib / libalpm / be_sync.c
blobaeba86f1a91b471bf2074e2ac72f96689bdac353
1 /*
2 * be_sync.c
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 <sys/stat.h>
25 /* libarchive */
26 #include <archive.h>
27 #include <archive_entry.h>
29 /* libalpm */
30 #include "util.h"
31 #include "log.h"
32 #include "alpm.h"
33 #include "alpm_list.h"
34 #include "package.h"
35 #include "handle.h"
36 #include "delta.h"
37 #include "deps.h"
38 #include "dload.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.
50 * Example:
51 * @code
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();
59 * if(result < 0) {
60 * printf("Unable to update database: %s\n", alpm_strerrorlast());
61 * } else if(result == 1) {
62 * printf("Database already up to date\n");
63 * } else {
64 * printf("Database updated\n");
65 * }
66 * }
67 * }
68 * @endcode
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
77 * to date
79 int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
81 char *syncpath;
82 const char *dbpath;
83 alpm_list_t *i;
84 struct stat buf;
85 size_t len;
86 int ret = -1;
87 mode_t oldmask;
88 pgp_verify_t check_sig;
90 /* Sanity checks */
91 ASSERT(db != NULL && db != db->handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
92 ASSERT(db->servers != NULL, RET_ERR(PM_ERR_SERVER_NONE, -1));
94 dbpath = alpm_option_get_dbpath();
95 len = strlen(dbpath) + 6;
96 MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
97 sprintf(syncpath, "%s%s", dbpath, "sync/");
99 /* make sure we have a sane umask */
100 oldmask = umask(0022);
102 if(stat(syncpath, &buf) != 0) {
103 _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
104 syncpath);
105 if(_alpm_makepath(syncpath) != 0) {
106 free(syncpath);
107 RET_ERR(PM_ERR_SYSTEM, -1);
109 } else if(!S_ISDIR(buf.st_mode)) {
110 _alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
111 if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
112 free(syncpath);
113 RET_ERR(PM_ERR_SYSTEM, -1);
117 check_sig = _alpm_db_get_sigverify_level(db);
119 for(i = db->servers; i; i = i->next) {
120 const char *server = i->data;
121 char *fileurl;
122 size_t len;
123 int sig_ret = 0;
125 /* print server + filename into a buffer (leave space for .sig) */
126 len = strlen(server) + strlen(db->treename) + 9;
127 CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1));
128 snprintf(fileurl, len, "%s/%s.db", server, db->treename);
130 ret = _alpm_download(fileurl, syncpath, force, 0, 0);
132 if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS ||
133 check_sig == PM_PGP_VERIFY_OPTIONAL)) {
134 int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL);
135 /* if we downloaded a DB, we want the .sig from the same server */
136 snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename);
138 sig_ret = _alpm_download(fileurl, syncpath, 1, 0, errors_ok);
139 /* errors_ok suppresses error messages, but not the return code */
140 sig_ret = errors_ok ? 0 : sig_ret;
143 FREE(fileurl);
144 if(ret != -1 && sig_ret != -1) {
145 break;
149 if(ret == 1) {
150 /* files match, do nothing */
151 pm_errno = 0;
152 goto cleanup;
153 } else if(ret == -1) {
154 /* pm_errno was set by the download code */
155 _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
156 goto cleanup;
159 /* Cache needs to be rebuilt */
160 _alpm_db_free_pkgcache(db);
162 cleanup:
164 free(syncpath);
165 umask(oldmask);
166 return ret;
169 /* Forward decl so I don't reorganize the whole file right now */
170 static int sync_db_read(pmdb_t *db, struct archive *archive,
171 struct archive_entry *entry, pmpkg_t *likely_pkg);
174 * This is the data table used to generate the estimating function below.
175 * "Weighted Avg" means averaging the bottom table values; thus each repo, big
176 * or small, will have equal influence. "Unweighted Avg" means averaging the
177 * sums of the top table columns, thus each package has equal influence. The
178 * final values are calculated by (surprise) averaging the averages, because
179 * why the hell not.
181 * Database Pkgs tar bz2 gz xz
182 * community 2096 5294080 256391 421227 301296
183 * core 180 460800 25257 36850 29356
184 * extra 2606 6635520 294647 470818 339392
185 * multilib 126 327680 16120 23261 18732
186 * testing 76 204800 10902 14348 12100
188 * Bytes Per Package
189 * community 2096 2525.80 122.32 200.97 143.75
190 * core 180 2560.00 140.32 204.72 163.09
191 * extra 2606 2546.25 113.06 180.67 130.23
192 * multilib 126 2600.63 127.94 184.61 148.67
193 * testing 76 2694.74 143.45 188.79 159.21
195 * Weighted Avg 2585.48 129.42 191.95 148.99
196 * Unweighted Avg 2543.39 118.74 190.16 137.93
197 * Average of Avgs 2564.44 124.08 191.06 143.46
199 static size_t estimate_package_count(struct stat *st, struct archive *archive)
201 unsigned int per_package;
203 switch(archive_compression(archive)) {
204 case ARCHIVE_COMPRESSION_NONE:
205 per_package = 2564;
206 break;
207 case ARCHIVE_COMPRESSION_GZIP:
208 per_package = 191;
209 break;
210 case ARCHIVE_COMPRESSION_BZIP2:
211 per_package = 124;
212 break;
213 case ARCHIVE_COMPRESSION_COMPRESS:
214 per_package = 193;
215 break;
216 case ARCHIVE_COMPRESSION_LZMA:
217 case ARCHIVE_COMPRESSION_XZ:
218 per_package = 143;
219 break;
220 #ifdef ARCHIVE_COMPRESSION_UU
221 case ARCHIVE_COMPRESSION_UU:
222 per_package = 3543;
223 break;
224 #endif
225 default:
226 /* assume it is at least somewhat compressed */
227 per_package = 200;
229 return (size_t)((st->st_size / per_package) + 1);
232 static int sync_db_populate(pmdb_t *db)
234 const char *dbpath;
235 size_t est_count;
236 int count = 0;
237 struct stat buf;
238 struct archive *archive;
239 struct archive_entry *entry;
240 pmpkg_t *pkg = NULL;
242 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
244 if((archive = archive_read_new()) == NULL) {
245 RET_ERR(PM_ERR_LIBARCHIVE, -1);
248 archive_read_support_compression_all(archive);
249 archive_read_support_format_all(archive);
251 dbpath = _alpm_db_path(db);
252 if(!dbpath) {
253 /* pm_errno set in _alpm_db_path() */
254 return -1;
257 _alpm_log(PM_LOG_DEBUG, "opening database archive %s\n", dbpath);
259 if(archive_read_open_filename(archive, dbpath,
260 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
261 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath,
262 archive_error_string(archive));
263 archive_read_finish(archive);
264 RET_ERR(PM_ERR_DB_OPEN, -1);
266 if(stat(dbpath, &buf) != 0) {
267 RET_ERR(PM_ERR_DB_OPEN, -1);
269 est_count = estimate_package_count(&buf, archive);
271 /* initialize hash at 66% full */
272 db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);
273 if(db->pkgcache == NULL) {
274 RET_ERR(PM_ERR_MEMORY, -1);
277 while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
278 const struct stat *st;
280 st = archive_entry_stat(entry);
282 if(S_ISDIR(st->st_mode)) {
283 const char *name;
285 pkg = _alpm_pkg_new();
286 if(pkg == NULL) {
287 archive_read_finish(archive);
288 RET_ERR(PM_ERR_MEMORY, -1);
291 name = archive_entry_pathname(entry);
293 if(_alpm_splitname(name, pkg) != 0) {
294 _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
295 name);
296 _alpm_pkg_free(pkg);
297 pkg = NULL;
298 continue;
301 /* duplicated database entries are not allowed */
302 if(_alpm_pkghash_find(db->pkgcache, pkg->name)) {
303 _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
304 _alpm_pkg_free(pkg);
305 pkg = NULL;
306 continue;
309 pkg->origin = PKG_FROM_SYNCDB;
310 pkg->origin_data.db = db;
311 pkg->ops = &default_pkg_ops;
312 pkg->handle = db->handle;
314 /* add to the collection */
315 _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
316 pkg->name, db->treename);
317 db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg);
318 count++;
319 } else {
320 /* we have desc, depends or deltas - parse it */
321 if(sync_db_read(db, archive, entry, pkg) != 0) {
322 _alpm_log(PM_LOG_ERROR,
323 _("could not parse package '%s' description file from db '%s'\n"),
324 pkg->name, db->treename);
325 _alpm_pkg_free(pkg);
326 pkg = NULL;
327 continue;
332 if(count > 0) {
333 db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
335 archive_read_finish(archive);
336 _alpm_log(PM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n",
337 count, db->treename);
339 return count;
342 #define READ_NEXT(s) do { \
343 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
344 s = _alpm_strtrim(buf.line); \
345 } while(0)
347 #define READ_AND_STORE(f) do { \
348 READ_NEXT(line); \
349 STRDUP(f, line, goto error); \
350 } while(0)
352 #define READ_AND_STORE_ALL(f) do { \
353 char *linedup; \
354 READ_NEXT(line); \
355 if(strlen(line) == 0) break; \
356 STRDUP(linedup, line, goto error); \
357 f = alpm_list_add(f, linedup); \
358 } while(1) /* note the while(1) and not (0) */
360 static int sync_db_read(pmdb_t *db, struct archive *archive,
361 struct archive_entry *entry, pmpkg_t *likely_pkg)
363 const char *entryname = NULL, *filename;
364 char *pkgname, *p, *q;
365 pmpkg_t *pkg;
366 struct archive_read_buffer buf;
368 if(db == NULL) {
369 RET_ERR(PM_ERR_DB_NULL, -1);
372 if(entry != NULL) {
373 entryname = archive_entry_pathname(entry);
375 if(entryname == NULL) {
376 _alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
377 return -1;
380 _alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n",
381 entryname);
383 memset(&buf, 0, sizeof(buf));
384 /* 512K for a line length seems reasonable */
385 buf.max_line_size = 512 * 1024;
387 /* get package and db file names */
388 STRDUP(pkgname, entryname, RET_ERR(PM_ERR_MEMORY, -1));
389 p = pkgname + strlen(pkgname);
390 for(q = --p; *q && *q != '/'; q--);
391 filename = q + 1;
392 for(p = --q; *p && *p != '-'; p--);
393 for(q = --p; *q && *q != '-'; q--);
394 *q = '\0';
396 /* package is already in db due to parsing of directory name */
397 if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) {
398 pkg = likely_pkg;
399 } else {
400 if(db->pkgcache == NULL) {
401 RET_ERR(PM_ERR_MEMORY, -1);
403 pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
405 if(pkg == NULL) {
406 _alpm_log(PM_LOG_DEBUG, "package %s not found in %s sync database",
407 pkgname, db->treename);
408 return -1;
411 if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
412 || strcmp(filename, "deltas") == 0) {
413 int ret;
414 while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
415 char *line = _alpm_strtrim(buf.line);
417 if(strcmp(line, "%NAME%") == 0) {
418 READ_NEXT(line);
419 if(strcmp(line, pkg->name) != 0) {
420 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
421 "mismatch on package %s\n"), db->treename, pkg->name);
423 } else if(strcmp(line, "%VERSION%") == 0) {
424 READ_NEXT(line);
425 if(strcmp(line, pkg->version) != 0) {
426 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
427 "mismatch on package %s\n"), db->treename, pkg->name);
429 } else if(strcmp(line, "%FILENAME%") == 0) {
430 READ_AND_STORE(pkg->filename);
431 } else if(strcmp(line, "%DESC%") == 0) {
432 READ_AND_STORE(pkg->desc);
433 } else if(strcmp(line, "%GROUPS%") == 0) {
434 READ_AND_STORE_ALL(pkg->groups);
435 } else if(strcmp(line, "%URL%") == 0) {
436 READ_AND_STORE(pkg->url);
437 } else if(strcmp(line, "%LICENSE%") == 0) {
438 READ_AND_STORE_ALL(pkg->licenses);
439 } else if(strcmp(line, "%ARCH%") == 0) {
440 READ_AND_STORE(pkg->arch);
441 } else if(strcmp(line, "%BUILDDATE%") == 0) {
442 READ_NEXT(line);
443 pkg->builddate = _alpm_parsedate(line);
444 } else if(strcmp(line, "%PACKAGER%") == 0) {
445 READ_AND_STORE(pkg->packager);
446 } else if(strcmp(line, "%CSIZE%") == 0) {
447 /* Note: the CSIZE and SIZE fields both share the "size" field in the
448 * pkginfo_t struct. This can be done b/c CSIZE is currently only used
449 * in sync databases, and SIZE is only used in local databases.
451 READ_NEXT(line);
452 pkg->size = atol(line);
453 /* also store this value to isize if isize is unset */
454 if(pkg->isize == 0) {
455 pkg->isize = pkg->size;
457 } else if(strcmp(line, "%ISIZE%") == 0) {
458 READ_NEXT(line);
459 pkg->isize = atol(line);
460 } else if(strcmp(line, "%MD5SUM%") == 0) {
461 READ_AND_STORE(pkg->md5sum);
462 } else if(strcmp(line, "%SHA256SUM%") == 0) {
463 /* we don't do anything with this value right now */
464 READ_NEXT(line);
465 } else if(strcmp(line, "%PGPSIG%") == 0) {
466 READ_AND_STORE(pkg->base64_sig);
467 } else if(strcmp(line, "%REPLACES%") == 0) {
468 READ_AND_STORE_ALL(pkg->replaces);
469 } else if(strcmp(line, "%DEPENDS%") == 0) {
470 /* Different than the rest because of the _alpm_splitdep call. */
471 while(1) {
472 READ_NEXT(line);
473 if(strlen(line) == 0) break;
474 pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line));
476 } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
477 READ_AND_STORE_ALL(pkg->optdepends);
478 } else if(strcmp(line, "%CONFLICTS%") == 0) {
479 READ_AND_STORE_ALL(pkg->conflicts);
480 } else if(strcmp(line, "%PROVIDES%") == 0) {
481 READ_AND_STORE_ALL(pkg->provides);
482 } else if(strcmp(line, "%DELTAS%") == 0) {
483 /* Different than the rest because of the _alpm_delta_parse call. */
484 while(1) {
485 READ_NEXT(line);
486 if(strlen(line) == 0) break;
487 pkg->deltas = alpm_list_add(pkg->deltas, _alpm_delta_parse(line));
491 if(ret != ARCHIVE_EOF) {
492 goto error;
494 } else if(strcmp(filename, "files") == 0) {
495 /* currently do nothing with this file */
496 } else {
497 /* unknown database file */
498 _alpm_log(PM_LOG_DEBUG, "unknown database file: %s\n", filename);
501 return 0;
503 error:
504 FREE(pkgname);
505 return -1;
508 static int sync_db_version(pmdb_t UNUSED *db)
510 return 2;
513 struct db_operations sync_db_ops = {
514 .populate = sync_db_populate,
515 .unregister = _alpm_db_unregister,
516 .version = sync_db_version,
519 pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename)
521 pmdb_t *db;
523 _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
525 db = _alpm_db_new(treename, 0);
526 if(db == NULL) {
527 RET_ERR(PM_ERR_DB_CREATE, NULL);
529 db->ops = &sync_db_ops;
530 db->handle = handle;
532 handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
533 return db;
537 /* vim: set ts=2 sw=2 noet: */