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/>.
32 #include <alpm_list.h>
40 static char *resolve_path(const char *file
)
44 str
= calloc(PATH_MAX
+ 1, sizeof(char));
49 if(!realpath(file
, str
)) {
57 /* check if filename exists in PATH */
58 static int search_path(char **filename
, struct stat
*bufptr
)
60 char *envpath
, *envpathsplit
, *path
, *fullname
;
63 if ((envpath
= getenv("PATH")) == NULL
) {
66 if ((envpath
= envpathsplit
= strdup(envpath
)) == NULL
) {
70 flen
= strlen(*filename
);
72 while ((path
= strsep(&envpathsplit
, ":")) != NULL
) {
73 size_t plen
= strlen(path
);
75 /* strip the trailing slash if one exists */
76 while(path
[plen
- 1] == '/') {
80 fullname
= malloc(plen
+ flen
+ 2);
81 sprintf(fullname
, "%s/%s", path
, *filename
);
83 if(lstat(fullname
, bufptr
) == 0) {
95 static void print_query_fileowner(const char *filename
, pmpkg_t
*info
)
98 printf(_("%s is owned by %s %s\n"), filename
,
99 alpm_pkg_get_name(info
), alpm_pkg_get_version(info
));
101 printf("%s\n", alpm_pkg_get_name(info
));
105 static int query_fileowner(alpm_list_t
*targets
)
115 /* This code is here for safety only */
116 if(targets
== NULL
) {
117 pm_fprintf(stderr
, PM_LOG_ERROR
, _("no file was specified for --owns\n"));
121 /* Set up our root path buffer. We only need to copy the location of root in
122 * once, then we can just overwrite whatever file was there on the previous
124 root
= alpm_option_get_root();
125 strncpy(path
, root
, PATH_MAX
- 1);
126 append
= path
+ strlen(path
);
127 max_length
= PATH_MAX
- (append
- path
) - 1;
129 db_local
= alpm_option_get_localdb();
131 for(t
= targets
; t
; t
= alpm_list_next(t
)) {
132 char *filename
, *dname
, *rpath
;
138 filename
= strdup(alpm_list_getdata(t
));
140 if(lstat(filename
, &buf
) == -1) {
141 /* if it is not a path but a program name, then check in PATH */
142 if(strchr(filename
, '/') == NULL
) {
143 if(search_path(&filename
, &buf
) == -1) {
144 pm_fprintf(stderr
, PM_LOG_ERROR
, _("failed to find '%s' in PATH: %s\n"),
145 filename
, strerror(errno
));
151 pm_fprintf(stderr
, PM_LOG_ERROR
, _("failed to read file '%s': %s\n"),
152 filename
, strerror(errno
));
159 if(S_ISDIR(buf
.st_mode
)) {
160 pm_fprintf(stderr
, PM_LOG_ERROR
,
161 _("cannot determine ownership of directory '%s'\n"), filename
);
167 bname
= mbasename(filename
);
168 dname
= mdirname(filename
);
169 /* for files in '/', there is no directory name to match */
170 if (strcmp(dname
, "") == 0) {
173 rpath
= resolve_path(dname
);
176 pm_fprintf(stderr
, PM_LOG_ERROR
, _("cannot determine real path for '%s': %s\n"),
177 filename
, strerror(errno
));
187 for(i
= alpm_db_get_pkgcache(db_local
); i
&& !found
; i
= alpm_list_next(i
)) {
189 pmpkg_t
*info
= alpm_list_getdata(i
);
191 for(j
= alpm_pkg_get_files(info
); j
&& !found
; j
= alpm_list_next(j
)) {
192 char *ppath
, *pdname
;
193 const char *pkgfile
= alpm_list_getdata(j
);
195 /* avoid the costly resolve_path usage if the basenames don't match */
196 if(strcmp(mbasename(pkgfile
), bname
) != 0) {
200 /* for files in '/', there is no directory name to match */
202 print_query_fileowner(filename
, info
);
207 if(strlen(pkgfile
) > max_length
) {
208 pm_fprintf(stderr
, PM_LOG_ERROR
, _("path too long: %s%s\n"), root
, pkgfile
);
210 /* concatenate our file and the root path */
211 strcpy(append
, pkgfile
);
213 pdname
= mdirname(path
);
214 ppath
= resolve_path(pdname
);
217 if(ppath
&& strcmp(ppath
, rpath
) == 0) {
218 print_query_fileowner(filename
, info
);
225 pm_fprintf(stderr
, PM_LOG_ERROR
, _("No package owns %s\n"), filename
);
235 /* search the local database for a matching package */
236 static int query_search(alpm_list_t
*targets
)
238 alpm_list_t
*i
, *searchlist
;
240 pmdb_t
*db_local
= alpm_option_get_localdb();
242 /* if we have a targets list, search for packages matching it */
244 searchlist
= alpm_db_search(db_local
, targets
);
247 searchlist
= alpm_db_get_pkgcache(db_local
);
250 if(searchlist
== NULL
) {
254 for(i
= searchlist
; i
; i
= alpm_list_next(i
)) {
256 pmpkg_t
*pkg
= alpm_list_getdata(i
);
258 if (!config
->quiet
) {
259 printf("local/%s %s", alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
261 printf("%s", alpm_pkg_get_name(pkg
));
264 /* print the package size with the output if ShowSize option set */
265 if(!config
->quiet
&& config
->showsize
) {
266 /* Convert byte size to MB */
267 double mbsize
= (double)alpm_pkg_get_size(pkg
) / (1024.0 * 1024.0);
269 printf(" [%.2f MB]", mbsize
);
273 if (!config
->quiet
) {
274 if((grp
= alpm_pkg_get_groups(pkg
)) != NULL
) {
277 for(k
= grp
; k
; k
= alpm_list_next(k
)) {
278 const char *group
= alpm_list_getdata(k
);
280 if(alpm_list_next(k
)) {
281 /* only print a spacer if there are more groups */
288 /* we need a newline and initial indent first */
290 indentprint(alpm_pkg_get_desc(pkg
), 4);
295 /* we only want to free if the list was a search list */
297 alpm_list_free(searchlist
);
302 static int query_group(alpm_list_t
*targets
)
305 char *grpname
= NULL
;
307 pmdb_t
*db_local
= alpm_option_get_localdb();
309 if(targets
== NULL
) {
310 for(j
= alpm_db_get_grpcache(db_local
); j
; j
= alpm_list_next(j
)) {
311 pmgrp_t
*grp
= alpm_list_getdata(j
);
312 const alpm_list_t
*p
, *packages
;
315 grpname
= alpm_grp_get_name(grp
);
316 packages
= alpm_grp_get_pkgs(grp
);
318 for(p
= packages
; p
; p
= alpm_list_next(p
)) {
319 printf("%s %s\n", grpname
, alpm_pkg_get_name(alpm_list_getdata(p
)));
323 for(i
= targets
; i
; i
= alpm_list_next(i
)) {
325 grpname
= alpm_list_getdata(i
);
326 grp
= alpm_db_readgrp(db_local
, grpname
);
328 const alpm_list_t
*p
, *packages
= alpm_grp_get_pkgs(grp
);
329 for(p
= packages
; p
; p
= alpm_list_next(p
)) {
331 printf("%s %s\n", grpname
,
332 alpm_pkg_get_name(alpm_list_getdata(p
)));
334 printf("%s\n", alpm_pkg_get_name(alpm_list_getdata(p
)));
338 pm_fprintf(stderr
, PM_LOG_ERROR
, _("group \"%s\" was not found\n"), grpname
);
346 static int is_foreign(pmpkg_t
*pkg
)
348 const char *pkgname
= alpm_pkg_get_name(pkg
);
350 alpm_list_t
*sync_dbs
= alpm_option_get_syncdbs();
353 for(j
= sync_dbs
; j
; j
= alpm_list_next(j
)) {
354 pmdb_t
*db
= alpm_list_getdata(j
);
355 pmpkg_t
*findpkg
= alpm_db_get_pkg(db
, pkgname
);
367 static int is_unrequired(pmpkg_t
*pkg
)
369 alpm_list_t
*requiredby
= alpm_pkg_compute_requiredby(pkg
);
370 if(requiredby
== NULL
) {
373 FREELIST(requiredby
);
377 static int filter(pmpkg_t
*pkg
)
379 /* check if this package was explicitly installed */
380 if(config
->op_q_explicit
&&
381 alpm_pkg_get_reason(pkg
) != PM_PKG_REASON_EXPLICIT
) {
384 /* check if this package was installed as a dependency */
385 if(config
->op_q_deps
&&
386 alpm_pkg_get_reason(pkg
) != PM_PKG_REASON_DEPEND
) {
389 /* check if this pkg isn't in a sync DB */
390 if(config
->op_q_foreign
&& !is_foreign(pkg
)) {
393 /* check if this pkg is unrequired */
394 if(config
->op_q_unrequired
&& !is_unrequired(pkg
)) {
397 /* check if this pkg is outdated */
398 if(config
->op_q_upgrade
&& (alpm_sync_newversion(pkg
, alpm_option_get_syncdbs()) == NULL
)) {
404 /* Loop through the packages. For each package,
405 * loop through files to check if they exist. */
406 static int check(pmpkg_t
*pkg
)
410 int allfiles
= 0, errors
= 0;
414 root
= alpm_option_get_root();
415 rootlen
= strlen(root
);
416 if(rootlen
+ 1 > PATH_MAX
) {
417 /* we are in trouble here */
418 pm_fprintf(stderr
, PM_LOG_ERROR
, _("path too long: %s%s\n"), root
, "");
423 const char *pkgname
= alpm_pkg_get_name(pkg
);
424 for(i
= alpm_pkg_get_files(pkg
); i
; i
= alpm_list_next(i
)) {
426 const char *path
= alpm_list_getdata(i
);
428 if(rootlen
+ 1 + strlen(path
) > PATH_MAX
) {
429 pm_fprintf(stderr
, PM_LOG_WARNING
, _("path too long: %s%s\n"), root
, path
);
432 strcpy(f
+ rootlen
, path
);
434 /* use lstat to prevent errors from symlinks */
435 if(lstat(f
, &st
) != 0) {
437 printf("%s %s\n", pkgname
, f
);
439 pm_printf(PM_LOG_WARNING
, "%s: %s (%s)\n",
440 pkgname
, f
, strerror(errno
));
447 printf(_n("%s: %d total file, ", "%s: %d total files, ",
448 (unsigned long)allfiles
), pkgname
, allfiles
);
449 printf(_n("%d missing file\n", "%d missing files\n",
450 (unsigned long)errors
), errors
);
453 return (errors
!= 0 ? 1 : 0);
456 static int display(pmpkg_t
*pkg
)
460 if(config
->op_q_info
) {
461 if(config
->op_q_isfile
) {
462 /* omit info that isn't applicable for a file package */
463 dump_pkg_full(pkg
, 0);
465 dump_pkg_full(pkg
, config
->op_q_info
);
468 if(config
->op_q_list
) {
469 dump_pkg_files(pkg
, config
->quiet
);
471 if(config
->op_q_changelog
) {
472 dump_pkg_changelog(pkg
);
474 if(config
->op_q_check
) {
477 if(!config
->op_q_info
&& !config
->op_q_list
478 && !config
->op_q_changelog
&& !config
->op_q_check
) {
479 if (!config
->quiet
) {
480 printf("%s %s\n", alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
));
482 printf("%s\n", alpm_pkg_get_name(pkg
));
488 int pacman_query(alpm_list_t
*targets
)
496 /* First: operations that do not require targets */
498 /* search for a package */
499 if(config
->op_q_search
) {
500 ret
= query_search(targets
);
504 /* looking for groups */
506 ret
= query_group(targets
);
510 if(config
->op_q_foreign
) {
511 /* ensure we have at least one valid sync db set up */
512 alpm_list_t
*sync_dbs
= alpm_option_get_syncdbs();
513 if(sync_dbs
== NULL
|| alpm_list_count(sync_dbs
) == 0) {
514 pm_printf(PM_LOG_ERROR
, _("no usable package repositories configured.\n"));
519 db_local
= alpm_option_get_localdb();
521 /* operations on all packages in the local DB
522 * valid: no-op (plain -Q), list, info, check
523 * invalid: isfile, owns */
524 if(targets
== NULL
) {
525 if(config
->op_q_isfile
|| config
->op_q_owns
) {
526 pm_printf(PM_LOG_ERROR
, _("no targets specified (use -h for help)\n"));
530 for(i
= alpm_db_get_pkgcache(db_local
); i
; i
= alpm_list_next(i
)) {
531 pkg
= alpm_list_getdata(i
);
533 int value
= display(pkg
);
546 /* Second: operations that require target(s) */
548 /* determine the owner of a file */
549 if(config
->op_q_owns
) {
550 ret
= query_fileowner(targets
);
554 /* operations on named packages in the local DB
555 * valid: no-op (plain -Q), list, info, check */
556 for(i
= targets
; i
; i
= alpm_list_next(i
)) {
557 char *strname
= alpm_list_getdata(i
);
559 if(config
->op_q_isfile
) {
560 alpm_pkg_load(strname
, 1, &pkg
);
562 pkg
= alpm_db_get_pkg(db_local
, strname
);
566 pm_fprintf(stderr
, PM_LOG_ERROR
, _("package \"%s\" not found\n"), strname
);
572 int value
= display(pkg
);
579 if(config
->op_q_isfile
) {
592 /* vim: set ts=2 sw=2 noet: */