4 * Copyright (c) 2006-2010 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/>.
30 #include <archive_entry.h>
36 #include "alpm_list.h"
43 /** Update a package database
45 * An update of the package database \a db will be attempted. Unless
46 * \a force is true, the update will only be performed if the remote
47 * database was modified since the last update.
49 * A transaction is necessary for this operation, in order to obtain a
50 * database lock. During this transaction the front-end will be informed
51 * of the download progress of the database via the download callback.
57 * db = alpm_list_getdata(alpm_option_get_syncdbs());
58 * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
59 * result = alpm_db_update(0, db);
60 * alpm_trans_release();
63 * printf("Unable to update database: %s\n", alpm_strerrorlast());
64 * } else if(result < 0) {
65 * printf("Database already up to date\n");
67 * printf("Database updated\n");
72 * @ingroup alpm_databases
73 * @note After a successful update, the \link alpm_db_get_pkgcache()
74 * package cache \endlink will be invalidated
75 * @param force if true, then forces the update, otherwise update only in case
76 * the database isn't up to date
77 * @param db pointer to the package database to update
78 * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
81 int SYMEXPORT
alpm_db_update(int force
, pmdb_t
*db
)
83 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));
93 /* Verify we are in a transaction. This is done _mainly_ because we need a DB
94 * lock - if we update without a db lock, we may kludge some other pacman
95 * process that _has_ a lock.
97 ASSERT(handle
->trans
!= NULL
, RET_ERR(PM_ERR_TRANS_NULL
, -1));
98 ASSERT(handle
->trans
->state
== STATE_INITIALIZED
, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED
, -1));
100 if(!alpm_list_find_ptr(handle
->dbs_sync
, db
)) {
101 RET_ERR(PM_ERR_DB_NOT_FOUND
, -1);
104 len
= strlen(db
->treename
) + 4;
105 MALLOC(dbfile
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
106 sprintf(dbfile
, "%s.db", db
->treename
);
108 dbpath
= alpm_option_get_dbpath();
109 len
= strlen(dbpath
) + 6;
110 MALLOC(syncpath
, len
, RET_ERR(PM_ERR_MEMORY
, -1));
111 sprintf(syncpath
, "%s%s", dbpath
, "sync/");
113 ret
= _alpm_download_single_file(dbfile
, db
->servers
, syncpath
, force
);
118 /* files match, do nothing */
121 } else if(ret
== -1) {
122 /* pm_errno was set by the download code */
123 _alpm_log(PM_LOG_DEBUG
, "failed to sync db: %s\n", alpm_strerrorlast());
127 /* Cache needs to be rebuilt */
128 _alpm_db_free_pkgcache(db
);
133 int _alpm_sync_db_populate(pmdb_t
*db
)
136 struct archive
*archive
;
137 struct archive_entry
*entry
;
138 const char * archive_path
;
142 ASSERT(db
!= NULL
, RET_ERR(PM_ERR_DB_NULL
, -1));
144 if((archive
= archive_read_new()) == NULL
)
145 RET_ERR(PM_ERR_LIBARCHIVE
, 1);
147 archive_read_support_compression_all(archive
);
148 archive_read_support_format_all(archive
);
150 if(archive_read_open_filename(archive
, _alpm_db_path(db
),
151 ARCHIVE_DEFAULT_BYTES_PER_BLOCK
) != ARCHIVE_OK
) {
152 _alpm_log(PM_LOG_ERROR
, _("could not open %s: %s\n"), _alpm_db_path(db
),
153 archive_error_string(archive
));
154 RET_ERR(PM_ERR_PKG_OPEN
, 1);
157 while(archive_read_next_header(archive
, &entry
) == ARCHIVE_OK
) {
158 const struct stat
*st
;
162 st
= archive_entry_stat(entry
);
164 if(S_ISDIR(st
->st_mode
)) {
165 archive_path
= archive_entry_pathname(entry
);
167 pkg
= _alpm_pkg_new();
169 archive_read_finish(archive
);
173 name
= archive_entry_pathname(entry
);
175 if(splitname(name
, pkg
) != 0) {
176 _alpm_log(PM_LOG_ERROR
, _("invalid name for database entry '%s'\n"),
182 /* duplicated database entries are not allowed */
183 if(_alpm_pkg_find(db
->pkgcache
, pkg
->name
)) {
184 _alpm_log(PM_LOG_ERROR
, _("duplicated database entry '%s'\n"), pkg
->name
);
189 pkg
->origin
= PKG_FROM_SYNCDB
;
190 pkg
->ops
= &default_pkg_ops
;
191 pkg
->origin_data
.db
= db
;
193 /* add to the collection */
194 _alpm_log(PM_LOG_FUNCTION
, "adding '%s' to package cache for db '%s'\n",
195 pkg
->name
, db
->treename
);
196 db
->pkgcache
= alpm_list_add(db
->pkgcache
, pkg
);
199 /* we have desc, depends or deltas - parse it */
200 _alpm_sync_db_read(db
, archive
, entry
);
204 db
->pkgcache
= alpm_list_msort(db
->pkgcache
, count
, _alpm_pkg_cmp
);
205 archive_read_finish(archive
);
210 int _alpm_sync_db_read(pmdb_t
*db
, struct archive
*archive
, struct archive_entry
*entry
)
213 const char *entryname
;
214 char *filename
, *pkgname
, *p
, *q
;
220 RET_ERR(PM_ERR_DB_NULL
, -1);
224 _alpm_log(PM_LOG_DEBUG
, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
228 entryname
= archive_entry_pathname(entry
);
230 _alpm_log(PM_LOG_FUNCTION
, "loading package data from archive entry %s\n",
233 /* get package and db file names */
234 STRDUP(pkgname
, entryname
, RET_ERR(PM_ERR_MEMORY
, -1));
235 p
= pkgname
+ strlen(pkgname
);
236 for(q
= --p
; *q
&& *q
!= '/'; q
--);
237 STRDUP(filename
, q
+1, RET_ERR(PM_ERR_MEMORY
, -1));
238 for(p
= --q
; *p
&& *p
!= '-'; p
--);
239 for(q
= --p
; *q
&& *q
!= '-'; q
--);
242 /* package is already in db due to parsing of directory name */
243 pkg
= _alpm_pkg_find(db
->pkgcache
, pkgname
);
245 _alpm_log(PM_LOG_DEBUG
, "package %s not found in %s sync database",
246 pkgname
, db
->treename
);
250 if(strcmp(filename
, "desc") == 0) {
251 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) != NULL
) {
253 if(strcmp(line
, "%NAME%") == 0) {
254 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
257 if(strcmp(_alpm_strtrim(line
), pkg
->name
) != 0) {
258 _alpm_log(PM_LOG_ERROR
, _("%s database is inconsistent: name "
259 "mismatch on package %s\n"), db
->treename
, pkg
->name
);
261 } else if(strcmp(line
, "%VERSION%") == 0) {
262 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
265 if(strcmp(_alpm_strtrim(line
), pkg
->version
) != 0) {
266 _alpm_log(PM_LOG_ERROR
, _("%s database is inconsistent: version "
267 "mismatch on package %s\n"), db
->treename
, pkg
->name
);
269 } else if(strcmp(line
, "%FILENAME%") == 0) {
270 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
273 STRDUP(pkg
->filename
, _alpm_strtrim(line
), goto error
);
274 } else if(strcmp(line
, "%DESC%") == 0) {
275 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
278 STRDUP(pkg
->desc
, _alpm_strtrim(line
), goto error
);
279 } else if(strcmp(line
, "%GROUPS%") == 0) {
280 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) && strlen(_alpm_strtrim(line
))) {
282 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
283 pkg
->groups
= alpm_list_add(pkg
->groups
, linedup
);
285 } else if(strcmp(line
, "%URL%") == 0) {
286 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
289 STRDUP(pkg
->url
, _alpm_strtrim(line
), goto error
);
290 } else if(strcmp(line
, "%LICENSE%") == 0) {
291 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
292 strlen(_alpm_strtrim(line
))) {
294 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
295 pkg
->licenses
= alpm_list_add(pkg
->licenses
, linedup
);
297 } else if(strcmp(line
, "%ARCH%") == 0) {
298 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
301 STRDUP(pkg
->arch
, _alpm_strtrim(line
), goto error
);
302 } else if(strcmp(line
, "%BUILDDATE%") == 0) {
303 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
308 char first
= tolower((unsigned char)line
[0]);
309 if(first
> 'a' && first
< 'z') {
310 struct tm tmp_tm
= {0}; /* initialize to null in case of failure */
311 setlocale(LC_TIME
, "C");
312 strptime(line
, "%a %b %e %H:%M:%S %Y", &tmp_tm
);
313 pkg
->builddate
= mktime(&tmp_tm
);
314 setlocale(LC_TIME
, "");
316 pkg
->builddate
= atol(line
);
318 } else if(strcmp(line
, "%INSTALLDATE%") == 0) {
319 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
324 char first
= tolower((unsigned char)line
[0]);
325 if(first
> 'a' && first
< 'z') {
326 struct tm tmp_tm
= {0}; /* initialize to null in case of failure */
327 setlocale(LC_TIME
, "C");
328 strptime(line
, "%a %b %e %H:%M:%S %Y", &tmp_tm
);
329 pkg
->installdate
= mktime(&tmp_tm
);
330 setlocale(LC_TIME
, "");
332 pkg
->installdate
= atol(line
);
334 } else if(strcmp(line
, "%PACKAGER%") == 0) {
335 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
338 STRDUP(pkg
->packager
, _alpm_strtrim(line
), goto error
);
339 } else if(strcmp(line
, "%REASON%") == 0) {
340 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
343 pkg
->reason
= (pmpkgreason_t
)atol(_alpm_strtrim(line
));
344 } else if(strcmp(line
, "%SIZE%") == 0 || strcmp(line
, "%CSIZE%") == 0) {
345 /* NOTE: the CSIZE and SIZE fields both share the "size" field
346 * in the pkginfo_t struct. This can be done b/c CSIZE
347 * is currently only used in sync databases, and SIZE is
348 * only used in local databases.
350 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
353 pkg
->size
= atol(_alpm_strtrim(line
));
354 /* also store this value to isize if isize is unset */
355 if(pkg
->isize
== 0) {
356 pkg
->isize
= pkg
->size
;
358 } else if(strcmp(line
, "%ISIZE%") == 0) {
359 /* ISIZE (installed size) tag only appears in sync repositories,
360 * not the local one. */
361 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
364 pkg
->isize
= atol(_alpm_strtrim(line
));
365 } else if(strcmp(line
, "%MD5SUM%") == 0) {
366 /* MD5SUM tag only appears in sync repositories,
367 * not the local one. */
368 if(_alpm_archive_fgets(line
, sizeof(line
), archive
) == NULL
) {
371 STRDUP(pkg
->md5sum
, _alpm_strtrim(line
), goto error
);
372 } else if(strcmp(line
, "%REPLACES%") == 0) {
373 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
374 strlen(_alpm_strtrim(line
))) {
376 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
377 pkg
->replaces
= alpm_list_add(pkg
->replaces
, linedup
);
379 } else if(strcmp(line
, "%FORCE%") == 0) {
383 } else if(strcmp(filename
, "depends") == 0) {
384 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) != NULL
) {
386 if(strcmp(line
, "%DEPENDS%") == 0) {
387 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
388 strlen(_alpm_strtrim(line
))) {
389 pmdepend_t
*dep
= _alpm_splitdep(_alpm_strtrim(line
));
390 pkg
->depends
= alpm_list_add(pkg
->depends
, dep
);
392 } else if(strcmp(line
, "%OPTDEPENDS%") == 0) {
393 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
394 strlen(_alpm_strtrim(line
))) {
396 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
397 pkg
->optdepends
= alpm_list_add(pkg
->optdepends
, linedup
);
399 } else if(strcmp(line
, "%CONFLICTS%") == 0) {
400 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
401 strlen(_alpm_strtrim(line
))) {
403 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
404 pkg
->conflicts
= alpm_list_add(pkg
->conflicts
, linedup
);
406 } else if(strcmp(line
, "%PROVIDES%") == 0) {
407 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) &&
408 strlen(_alpm_strtrim(line
))) {
410 STRDUP(linedup
, _alpm_strtrim(line
), goto error
);
411 pkg
->provides
= alpm_list_add(pkg
->provides
, linedup
);
415 } else if(strcmp(filename
, "deltas") == 0) {
416 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) != NULL
) {
418 if(strcmp(line
, "%DELTAS%") == 0) {
419 while(_alpm_archive_fgets(line
, sizeof(line
), archive
) && strlen(_alpm_strtrim(line
))) {
420 pmdelta_t
*delta
= _alpm_delta_parse(line
);
422 pkg
->deltas
= alpm_list_add(pkg
->deltas
, delta
);
428 /* unknown database file */
429 _alpm_log(PM_LOG_DEBUG
, "unknown database file: %s", filename
);
438 struct db_operations sync_db_ops
= {
439 .populate
= _alpm_sync_db_populate
,
440 .unregister
= _alpm_db_unregister
,
443 pmdb_t
*_alpm_db_register_sync(const char *treename
)
450 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
451 pmdb_t
*sdb
= i
->data
;
452 if(strcmp(treename
, sdb
->treename
) == 0) {
453 _alpm_log(PM_LOG_DEBUG
, "attempt to re-register the '%s' database, using existing\n", sdb
->treename
);
458 _alpm_log(PM_LOG_DEBUG
, "registering sync database '%s'\n", treename
);
460 db
= _alpm_db_new(treename
, 0);
461 db
->ops
= &sync_db_ops
;
463 RET_ERR(PM_ERR_DB_CREATE
, NULL
);
466 handle
->dbs_sync
= alpm_list_add(handle
->dbs_sync
, db
);
471 /* vim: set ts=2 sw=2 noet: */