2 * testdb.c : Test a pacman local database for validity
4 * Copyright (c) 2007 by Aaron Griffin <aaronmgriffin@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <alpm_list.h>
30 #define BASENAME "testdb"
32 alpm_handle_t
*handle
= NULL
;
34 static void cleanup(int signum
)
36 if(handle
&& alpm_release(handle
) == -1) {
37 fprintf(stderr
, "error releasing alpm\n");
43 static void output_cb(alpm_loglevel_t level
, const char *fmt
, va_list args
)
47 case ALPM_LOG_ERROR
: printf("error: "); break;
48 case ALPM_LOG_WARNING
: printf("warning: "); break;
55 static int check_localdb_files(void)
63 dbpath
= alpm_option_get_dbpath(handle
);
64 snprintf(path
, sizeof(path
), "%slocal", dbpath
);
65 if(!(dir
= opendir(path
))) {
66 fprintf(stderr
, "error : %s : %s\n", path
, strerror(errno
));
70 while((ent
= readdir(dir
)) != NULL
) {
71 if(strcmp(ent
->d_name
, ".") == 0 || strcmp(ent
->d_name
, "..") == 0
72 || ent
->d_name
[0] == '.') {
75 /* check for known db files in local database */
76 snprintf(path
, sizeof(path
), "%slocal/%s/desc", dbpath
, ent
->d_name
);
77 if(access(path
, F_OK
)) {
78 printf("%s: description file is missing\n", ent
->d_name
);
81 snprintf(path
, sizeof(path
), "%slocal/%s/files", dbpath
, ent
->d_name
);
82 if(access(path
, F_OK
)) {
83 printf("%s: file list is missing\n", ent
->d_name
);
88 fprintf(stderr
, "error closing dbpath : %s\n", strerror(errno
));
95 static int check_deps(alpm_list_t
*pkglist
)
97 alpm_list_t
*data
, *i
;
99 /* check dependencies */
100 data
= alpm_checkdeps(handle
, pkglist
, NULL
, pkglist
, 0);
101 for(i
= data
; i
; i
= alpm_list_next(i
)) {
102 alpm_depmissing_t
*miss
= i
->data
;
103 char *depstring
= alpm_dep_compute_string(miss
->depend
);
104 printf("missing %s dependency for %s\n", depstring
, miss
->target
);
112 static int check_conflicts(alpm_list_t
*pkglist
)
114 alpm_list_t
*data
, *i
;
116 /* check conflicts */
117 data
= alpm_checkconflicts(handle
, pkglist
);
118 for(i
= data
; i
; i
= i
->next
) {
119 alpm_conflict_t
*conflict
= i
->data
;
120 printf("%s conflicts with %s\n",
121 conflict
->package1
, conflict
->package2
);
133 static int fileitem_cmp(const void *p1
, const void *p2
)
135 const struct fileitem
* fi1
= p1
;
136 const struct fileitem
* fi2
= p2
;
137 return strcmp(fi1
->file
->name
, fi2
->file
->name
);
140 static int check_filelists(alpm_list_t
*pkglist
)
144 size_t list_size
= 4096;
145 size_t offset
= 0, j
;
146 struct fileitem
*all_files
;
147 struct fileitem
*prev_fileitem
= NULL
;
149 all_files
= malloc(list_size
* sizeof(struct fileitem
));
151 for(i
= pkglist
; i
; i
= i
->next
) {
152 alpm_pkg_t
*pkg
= i
->data
;
153 alpm_filelist_t
*filelist
= alpm_pkg_get_files(pkg
);
154 for(j
= 0; j
< filelist
->count
; j
++) {
155 alpm_file_t
*file
= filelist
->files
+ j
;
156 /* only add files, not directories, to our big list */
157 if(file
->name
[strlen(file
->name
) - 1] == '/') {
161 /* do we need to reallocate and grow our array? */
162 if(offset
>= list_size
) {
163 struct fileitem
*new_files
;
164 new_files
= realloc(all_files
, list_size
* 2 * sizeof(struct fileitem
));
169 all_files
= new_files
;
173 /* we can finally add it to the list */
174 all_files
[offset
].file
= file
;
175 all_files
[offset
].pkg
= pkg
;
180 /* now sort the list so we can find duplicates */
181 qsort(all_files
, offset
, sizeof(struct fileitem
), fileitem_cmp
);
183 /* do a 'uniq' style check on the list */
184 for(j
= 0; j
< offset
; j
++) {
185 struct fileitem
*fileitem
= all_files
+ j
;
186 if(prev_fileitem
&& fileitem_cmp(prev_fileitem
, fileitem
) == 0) {
187 printf("file owned by %s and %s: %s\n",
188 alpm_pkg_get_name(prev_fileitem
->pkg
),
189 alpm_pkg_get_name(fileitem
->pkg
),
190 fileitem
->file
->name
);
192 prev_fileitem
= fileitem
;
199 static int check_localdb(void)
202 alpm_db_t
*db
= NULL
;
203 alpm_list_t
*pkglist
;
205 ret
= check_localdb_files();
210 db
= alpm_get_localdb(handle
);
211 pkglist
= alpm_db_get_pkgcache(db
);
212 ret
+= check_deps(pkglist
);
213 ret
+= check_conflicts(pkglist
);
214 ret
+= check_filelists(pkglist
);
218 static int check_syncdbs(alpm_list_t
*dbnames
)
221 alpm_db_t
*db
= NULL
;
222 alpm_list_t
*i
, *pkglist
, *syncpkglist
= NULL
;
223 const alpm_siglevel_t level
= ALPM_SIG_DATABASE
| ALPM_SIG_DATABASE_OPTIONAL
;
225 for(i
= dbnames
; i
; i
= alpm_list_next(i
)) {
226 const char *dbname
= i
->data
;
227 db
= alpm_register_syncdb(handle
, dbname
, level
);
229 fprintf(stderr
, "error: could not register sync database (%s)\n",
230 alpm_strerror(alpm_errno(handle
)));
234 pkglist
= alpm_db_get_pkgcache(db
);
235 syncpkglist
= alpm_list_join(syncpkglist
, alpm_list_copy(pkglist
));
237 ret
+= check_deps(syncpkglist
);
240 alpm_list_free(syncpkglist
);
244 static void usage(void)
246 fprintf(stderr
, "usage:\n");
248 "\t%s [-b <pacman db>] : check the local database\n", BASENAME
);
250 "\t%s [-b <pacman db>] core extra ... : check the listed sync databases\n", BASENAME
);
254 int main(int argc
, char *argv
[])
258 const char *dbpath
= DBPATH
;
260 alpm_list_t
*dbnames
= NULL
;
263 if(strcmp(argv
[a
], "-b") == 0) {
269 } else if(strcmp(argv
[a
], "-h") == 0 ||
270 strcmp(argv
[a
], "--help") == 0 ) {
273 dbnames
= alpm_list_add(dbnames
, argv
[a
]);
278 handle
= alpm_initialize(ROOTDIR
, dbpath
, &err
);
280 fprintf(stderr
, "cannot initialize alpm: %s\n", alpm_strerror(err
));
284 /* let us get log messages from libalpm */
285 alpm_option_set_logcb(handle
, output_cb
);
288 errors
= check_localdb();
290 errors
= check_syncdbs(dbnames
);
291 alpm_list_free(dbnames
);
297 /* vim: set ts=2 sw=2 noet: */