2005-03-14 20:51:43 -05:00
|
|
|
/*
|
|
|
|
* query.c
|
2007-06-02 12:34:01 -04:00
|
|
|
*
|
2011-01-05 23:45:15 -05:00
|
|
|
* Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
|
2009-07-01 03:08:33 -04:00
|
|
|
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
|
2007-06-02 12:34:01 -04:00
|
|
|
*
|
2005-03-14 20:51:43 -05:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2007-12-10 23:55:22 -05:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2005-03-14 20:51:43 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2011-09-07 21:41:09 -04:00
|
|
|
#include <stdint.h>
|
2005-03-14 20:51:43 -05:00
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
2011-09-01 19:01:33 -04:00
|
|
|
#include <unistd.h>
|
2007-03-20 23:08:19 -04:00
|
|
|
#include <errno.h>
|
2005-03-14 20:51:43 -05:00
|
|
|
|
|
|
|
#include <alpm.h>
|
2007-01-19 04:28:44 -05:00
|
|
|
#include <alpm_list.h>
|
2007-03-05 17:13:33 -05:00
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
/* pacman */
|
2007-04-25 02:21:12 -04:00
|
|
|
#include "pacman.h"
|
2007-03-05 17:13:33 -05:00
|
|
|
#include "package.h"
|
2005-10-28 08:20:40 -04:00
|
|
|
#include "conf.h"
|
2005-12-13 21:23:14 -05:00
|
|
|
#include "util.h"
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2011-01-22 15:29:02 -05:00
|
|
|
static char *resolve_path(const char *file)
|
2007-03-22 03:32:54 -04:00
|
|
|
{
|
2007-05-18 02:20:49 -04:00
|
|
|
char *str = NULL;
|
2007-03-22 03:32:54 -04:00
|
|
|
|
2011-06-09 14:41:08 -04:00
|
|
|
str = calloc(PATH_MAX, sizeof(char));
|
2007-05-18 02:20:49 -04:00
|
|
|
if(!str) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return NULL;
|
2007-03-22 03:32:54 -04:00
|
|
|
}
|
|
|
|
|
2007-05-20 02:20:07 -04:00
|
|
|
if(!realpath(file, str)) {
|
2007-10-30 00:11:49 -04:00
|
|
|
free(str);
|
2011-03-20 20:45:57 -04:00
|
|
|
return NULL;
|
2007-03-22 03:32:54 -04:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return str;
|
2007-03-22 03:32:54 -04:00
|
|
|
}
|
|
|
|
|
2010-03-06 22:02:37 -05:00
|
|
|
/* check if filename exists in PATH */
|
|
|
|
static int search_path(char **filename, struct stat *bufptr)
|
|
|
|
{
|
|
|
|
char *envpath, *envpathsplit, *path, *fullname;
|
|
|
|
size_t flen;
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if((envpath = getenv("PATH")) == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2010-03-06 22:02:37 -05:00
|
|
|
}
|
2011-04-20 20:45:16 -04:00
|
|
|
if((envpath = envpathsplit = strdup(envpath)) == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2010-03-06 22:02:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
flen = strlen(*filename);
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
while((path = strsep(&envpathsplit, ":")) != NULL) {
|
2010-03-06 22:02:37 -05:00
|
|
|
size_t plen = strlen(path);
|
|
|
|
|
|
|
|
/* strip the trailing slash if one exists */
|
|
|
|
while(path[plen - 1] == '/') {
|
|
|
|
path[--plen] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
fullname = malloc(plen + flen + 2);
|
2011-05-19 17:59:53 -04:00
|
|
|
if(!fullname) {
|
|
|
|
free(envpath);
|
2011-06-13 18:43:09 -04:00
|
|
|
return -1;
|
2011-05-19 17:59:53 -04:00
|
|
|
}
|
2010-03-06 22:02:37 -05:00
|
|
|
sprintf(fullname, "%s/%s", path, *filename);
|
|
|
|
|
|
|
|
if(lstat(fullname, bufptr) == 0) {
|
|
|
|
free(*filename);
|
|
|
|
*filename = fullname;
|
|
|
|
free(envpath);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2010-03-06 22:02:37 -05:00
|
|
|
}
|
|
|
|
free(fullname);
|
|
|
|
}
|
|
|
|
free(envpath);
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2010-03-06 22:02:37 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 09:26:39 -04:00
|
|
|
static void print_query_fileowner(const char *filename, alpm_pkg_t *info)
|
2011-04-02 15:03:03 -04:00
|
|
|
{
|
2011-04-20 20:45:16 -04:00
|
|
|
if(!config->quiet) {
|
2011-04-02 15:03:03 -04:00
|
|
|
printf(_("%s is owned by %s %s\n"), filename,
|
|
|
|
alpm_pkg_get_name(info), alpm_pkg_get_version(info));
|
|
|
|
} else {
|
|
|
|
printf("%s\n", alpm_pkg_get_name(info));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
static int query_fileowner(alpm_list_t *targets)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-06-02 12:34:01 -04:00
|
|
|
int ret = 0;
|
2011-01-22 15:29:02 -05:00
|
|
|
char path[PATH_MAX];
|
|
|
|
const char *root;
|
2011-07-05 15:16:17 -04:00
|
|
|
size_t rootlen;
|
2007-06-02 12:34:01 -04:00
|
|
|
alpm_list_t *t;
|
2011-06-28 00:11:43 -04:00
|
|
|
alpm_db_t *db_local;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-06-12 23:55:14 -04:00
|
|
|
/* This code is here for safety only */
|
2007-06-02 12:34:01 -04:00
|
|
|
if(targets == NULL) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("no file was specified for --owns\n"));
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2011-01-22 15:29:02 -05:00
|
|
|
/* Set up our root path buffer. We only need to copy the location of root in
|
|
|
|
* once, then we can just overwrite whatever file was there on the previous
|
|
|
|
* iteration. */
|
2011-06-07 14:15:43 -04:00
|
|
|
root = alpm_option_get_root(config->handle);
|
2011-07-05 15:16:17 -04:00
|
|
|
rootlen = strlen(root);
|
|
|
|
if(rootlen + 1 > PATH_MAX) {
|
|
|
|
/* we are in trouble here */
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, "");
|
2011-07-05 15:16:17 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
strcpy(path, root);
|
2011-01-22 15:29:02 -05:00
|
|
|
|
2011-06-07 14:15:43 -04:00
|
|
|
db_local = alpm_option_get_localdb(config->handle);
|
2011-01-28 18:41:15 -05:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
for(t = targets; t; t = alpm_list_next(t)) {
|
2011-01-22 15:29:02 -05:00
|
|
|
char *filename, *dname, *rpath;
|
|
|
|
const char *bname;
|
|
|
|
struct stat buf;
|
|
|
|
alpm_list_t *i;
|
2007-06-02 12:34:01 -04:00
|
|
|
int found = 0;
|
2011-01-22 15:29:02 -05:00
|
|
|
|
2011-10-06 01:55:47 -04:00
|
|
|
filename = strdup(t->data);
|
2007-06-02 12:34:01 -04:00
|
|
|
|
2009-07-25 14:00:06 -04:00
|
|
|
if(lstat(filename, &buf) == -1) {
|
2010-03-06 22:02:37 -05:00
|
|
|
/* if it is not a path but a program name, then check in PATH */
|
|
|
|
if(strchr(filename, '/') == NULL) {
|
|
|
|
if(search_path(&filename, &buf) == -1) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("failed to find '%s' in PATH: %s\n"),
|
2010-03-06 22:02:37 -05:00
|
|
|
filename, strerror(errno));
|
|
|
|
ret++;
|
|
|
|
free(filename);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("failed to read file '%s': %s\n"),
|
2010-03-06 22:02:37 -05:00
|
|
|
filename, strerror(errno));
|
|
|
|
ret++;
|
|
|
|
free(filename);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2007-03-20 23:08:19 -04:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
if(S_ISDIR(buf.st_mode)) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR,
|
2011-02-25 10:48:20 -05:00
|
|
|
_("cannot determine ownership of directory '%s'\n"), filename);
|
2007-06-02 12:34:01 -04:00
|
|
|
ret++;
|
2010-03-06 22:02:37 -05:00
|
|
|
free(filename);
|
2007-06-02 12:34:01 -04:00
|
|
|
continue;
|
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-11-25 17:13:56 -05:00
|
|
|
bname = mbasename(filename);
|
2008-02-05 18:29:49 -05:00
|
|
|
dname = mdirname(filename);
|
2011-04-02 15:03:03 -04:00
|
|
|
/* for files in '/', there is no directory name to match */
|
2011-04-20 20:45:16 -04:00
|
|
|
if(strcmp(dname, "") == 0) {
|
2011-04-02 15:03:03 -04:00
|
|
|
rpath = NULL;
|
|
|
|
} else {
|
|
|
|
rpath = resolve_path(dname);
|
|
|
|
|
|
|
|
if(!rpath) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"),
|
2011-04-02 15:03:03 -04:00
|
|
|
filename, strerror(errno));
|
|
|
|
free(filename);
|
|
|
|
free(dname);
|
|
|
|
free(rpath);
|
|
|
|
ret++;
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2011-01-22 15:29:02 -05:00
|
|
|
free(dname);
|
2008-05-04 20:15:49 -04:00
|
|
|
|
2011-02-25 09:22:09 -05:00
|
|
|
for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_pkg_t *info = i->data;
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
alpm_filelist_t *filelist = alpm_pkg_get_files(info);
|
2011-08-11 20:26:20 -04:00
|
|
|
size_t j;
|
2007-03-22 03:32:54 -04:00
|
|
|
|
2011-08-11 20:26:20 -04:00
|
|
|
for(j = 0; j < filelist->count; j++) {
|
|
|
|
const alpm_file_t *file = filelist->files + j;
|
2011-01-22 15:29:02 -05:00
|
|
|
char *ppath, *pdname;
|
2011-06-16 14:16:49 -04:00
|
|
|
const char *pkgfile = file->name;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-11-25 17:13:56 -05:00
|
|
|
/* avoid the costly resolve_path usage if the basenames don't match */
|
2011-01-22 15:29:02 -05:00
|
|
|
if(strcmp(mbasename(pkgfile), bname) != 0) {
|
2007-11-25 17:13:56 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-04-02 15:03:03 -04:00
|
|
|
/* for files in '/', there is no directory name to match */
|
|
|
|
if(!rpath) {
|
|
|
|
print_query_fileowner(filename, info);
|
|
|
|
found = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-05 15:16:17 -04:00
|
|
|
if(rootlen + 1 + strlen(pkgfile) > PATH_MAX) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, pkgfile);
|
2011-01-22 15:29:02 -05:00
|
|
|
}
|
|
|
|
/* concatenate our file and the root path */
|
2011-07-05 15:16:17 -04:00
|
|
|
strcpy(path + rootlen, pkgfile);
|
2011-01-22 15:29:02 -05:00
|
|
|
|
2008-02-05 18:29:49 -05:00
|
|
|
pdname = mdirname(path);
|
|
|
|
ppath = resolve_path(pdname);
|
|
|
|
free(pdname);
|
2007-03-22 03:32:54 -04:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
if(ppath && strcmp(ppath, rpath) == 0) {
|
2011-04-02 15:03:03 -04:00
|
|
|
print_query_fileowner(filename, info);
|
2007-06-02 12:34:01 -04:00
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
free(ppath);
|
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
if(!found) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("No package owns %s\n"), filename);
|
2007-06-02 12:34:01 -04:00
|
|
|
ret++;
|
|
|
|
}
|
2010-03-06 22:02:37 -05:00
|
|
|
free(filename);
|
2007-06-02 12:34:01 -04:00
|
|
|
free(rpath);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-03-22 03:32:54 -04:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
/* search the local database for a matching package */
|
|
|
|
static int query_search(alpm_list_t *targets)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-06-02 12:34:01 -04:00
|
|
|
alpm_list_t *i, *searchlist;
|
|
|
|
int freelist;
|
2011-06-28 00:11:43 -04:00
|
|
|
alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
|
2007-06-02 12:34:01 -04:00
|
|
|
|
|
|
|
/* if we have a targets list, search for packages matching it */
|
|
|
|
if(targets) {
|
|
|
|
searchlist = alpm_db_search(db_local, targets);
|
|
|
|
freelist = 1;
|
|
|
|
} else {
|
2011-02-25 09:22:09 -05:00
|
|
|
searchlist = alpm_db_get_pkgcache(db_local);
|
2007-06-02 12:34:01 -04:00
|
|
|
freelist = 0;
|
|
|
|
}
|
|
|
|
if(searchlist == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
for(i = searchlist; i; i = alpm_list_next(i)) {
|
|
|
|
alpm_list_t *grp;
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_pkg_t *pkg = i->data;
|
2007-06-02 12:34:01 -04:00
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(!config->quiet) {
|
2007-11-07 02:05:33 -05:00
|
|
|
printf("local/%s %s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
|
|
|
|
} else {
|
2011-10-03 11:54:08 -04:00
|
|
|
fputs(alpm_pkg_get_name(pkg), stdout);
|
2007-11-07 02:05:33 -05:00
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
|
2007-06-01 11:00:39 -04:00
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(!config->quiet) {
|
2007-11-07 02:05:33 -05:00
|
|
|
if((grp = alpm_pkg_get_groups(pkg)) != NULL) {
|
2008-03-30 17:41:13 -04:00
|
|
|
alpm_list_t *k;
|
2011-10-03 11:54:08 -04:00
|
|
|
fputs(" (", stdout);
|
2008-03-30 17:41:13 -04:00
|
|
|
for(k = grp; k; k = alpm_list_next(k)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
const char *group = k->data;
|
2011-10-03 11:54:08 -04:00
|
|
|
fputs(group, stdout);
|
2008-03-30 17:41:13 -04:00
|
|
|
if(alpm_list_next(k)) {
|
|
|
|
/* only print a spacer if there are more groups */
|
2011-10-03 11:54:08 -04:00
|
|
|
putchar(' ');
|
2008-03-30 17:41:13 -04:00
|
|
|
}
|
|
|
|
}
|
2011-10-03 11:54:08 -04:00
|
|
|
putchar(')');
|
2007-11-07 02:05:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* we need a newline and initial indent first */
|
|
|
|
printf("\n ");
|
|
|
|
indentprint(alpm_pkg_get_desc(pkg), 4);
|
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
printf("\n");
|
|
|
|
}
|
2007-09-10 20:13:38 -04:00
|
|
|
|
|
|
|
/* we only want to free if the list was a search list */
|
|
|
|
if(freelist) {
|
|
|
|
alpm_list_free(searchlist);
|
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2007-05-14 01:21:42 -04:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
static int query_group(alpm_list_t *targets)
|
|
|
|
{
|
|
|
|
alpm_list_t *i, *j;
|
2011-10-06 01:55:47 -04:00
|
|
|
const char *grpname = NULL;
|
2007-06-02 12:34:01 -04:00
|
|
|
int ret = 0;
|
2011-06-28 00:11:43 -04:00
|
|
|
alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
|
2011-01-28 18:41:15 -05:00
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
if(targets == NULL) {
|
2011-06-29 01:46:49 -04:00
|
|
|
for(j = alpm_db_get_groupcache(db_local); j; j = alpm_list_next(j)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_group_t *grp = j->data;
|
2011-06-16 12:55:26 -04:00
|
|
|
const alpm_list_t *p;
|
2007-06-02 12:34:01 -04:00
|
|
|
|
2011-06-16 12:55:26 -04:00
|
|
|
for(p = grp->packages; p; p = alpm_list_next(p)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_pkg_t *pkg = p->data;
|
2011-06-16 12:55:26 -04:00
|
|
|
printf("%s %s\n", grp->name, alpm_pkg_get_name(pkg));
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(i = targets; i; i = alpm_list_next(i)) {
|
2011-06-28 00:37:16 -04:00
|
|
|
alpm_group_t *grp;
|
2011-10-06 01:55:47 -04:00
|
|
|
grpname = i->data;
|
2011-06-29 01:46:49 -04:00
|
|
|
grp = alpm_db_readgroup(db_local, grpname);
|
2007-06-02 12:34:01 -04:00
|
|
|
if(grp) {
|
2011-06-16 12:55:26 -04:00
|
|
|
const alpm_list_t *p;
|
|
|
|
for(p = grp->packages; p; p = alpm_list_next(p)) {
|
2008-07-16 08:42:25 -04:00
|
|
|
if(!config->quiet) {
|
|
|
|
printf("%s %s\n", grpname,
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_pkg_get_name(p->data));
|
2008-07-16 08:42:25 -04:00
|
|
|
} else {
|
2011-10-06 01:55:47 -04:00
|
|
|
printf("%s\n", alpm_pkg_get_name(p->data));
|
2008-07-16 08:42:25 -04:00
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2007-01-24 03:51:50 -05:00
|
|
|
} else {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("group '%s' was not found\n"), grpname);
|
2007-06-02 12:34:01 -04:00
|
|
|
ret++;
|
2007-01-24 03:51:50 -05:00
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2007-01-24 03:51:50 -05:00
|
|
|
|
2011-06-28 09:26:39 -04:00
|
|
|
static int is_foreign(alpm_pkg_t *pkg)
|
2007-06-12 23:55:14 -04:00
|
|
|
{
|
2007-07-14 14:45:30 -04:00
|
|
|
const char *pkgname = alpm_pkg_get_name(pkg);
|
|
|
|
alpm_list_t *j;
|
2011-06-07 14:15:43 -04:00
|
|
|
alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle);
|
2007-07-14 14:45:30 -04:00
|
|
|
|
|
|
|
int match = 0;
|
|
|
|
for(j = sync_dbs; j; j = alpm_list_next(j)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
alpm_db_t *db = j->data;
|
2011-06-28 09:26:39 -04:00
|
|
|
alpm_pkg_t *findpkg = alpm_db_get_pkg(db, pkgname);
|
2007-09-10 20:13:38 -04:00
|
|
|
if(findpkg) {
|
2007-07-14 14:45:30 -04:00
|
|
|
match = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(match == 0) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2007-06-12 23:55:14 -04:00
|
|
|
|
2011-06-28 09:26:39 -04:00
|
|
|
static int is_unrequired(alpm_pkg_t *pkg)
|
2007-07-14 14:45:30 -04:00
|
|
|
{
|
2007-11-12 20:40:08 -05:00
|
|
|
alpm_list_t *requiredby = alpm_pkg_compute_requiredby(pkg);
|
|
|
|
if(requiredby == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-05-31 15:48:16 -04:00
|
|
|
}
|
2007-11-12 20:40:08 -05:00
|
|
|
FREELIST(requiredby);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
2007-05-31 15:48:16 -04:00
|
|
|
|
2011-06-28 09:26:39 -04:00
|
|
|
static int filter(alpm_pkg_t *pkg)
|
2007-06-12 23:55:14 -04:00
|
|
|
{
|
2007-07-14 18:44:06 -04:00
|
|
|
/* check if this package was explicitly installed */
|
|
|
|
if(config->op_q_explicit &&
|
2011-07-01 12:01:38 -04:00
|
|
|
alpm_pkg_get_reason(pkg) != ALPM_PKG_REASON_EXPLICIT) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-07-14 18:44:06 -04:00
|
|
|
}
|
|
|
|
/* check if this package was installed as a dependency */
|
|
|
|
if(config->op_q_deps &&
|
2011-07-01 12:01:38 -04:00
|
|
|
alpm_pkg_get_reason(pkg) != ALPM_PKG_REASON_DEPEND) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-07-14 18:44:06 -04:00
|
|
|
}
|
2007-07-14 14:45:30 -04:00
|
|
|
/* check if this pkg isn't in a sync DB */
|
|
|
|
if(config->op_q_foreign && !is_foreign(pkg)) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2008-01-10 09:59:43 -05:00
|
|
|
/* check if this pkg is unrequired */
|
|
|
|
if(config->op_q_unrequired && !is_unrequired(pkg)) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2008-10-23 20:05:12 -04:00
|
|
|
/* check if this pkg is outdated */
|
2011-06-07 14:15:43 -04:00
|
|
|
if(config->op_q_upgrade && (alpm_sync_newversion(pkg,
|
|
|
|
alpm_option_get_syncdbs(config->handle)) == NULL)) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2008-10-23 20:05:12 -04:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2007-01-19 04:28:44 -05:00
|
|
|
|
2009-03-30 12:48:15 -04:00
|
|
|
/* Loop through the packages. For each package,
|
|
|
|
* loop through files to check if they exist. */
|
2011-06-28 09:26:39 -04:00
|
|
|
static int check(alpm_pkg_t *pkg)
|
2007-07-14 14:45:30 -04:00
|
|
|
{
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
const char *root, *pkgname;
|
2011-09-07 21:41:09 -04:00
|
|
|
size_t errors = 0;
|
2009-03-30 12:48:15 -04:00
|
|
|
size_t rootlen;
|
|
|
|
char f[PATH_MAX];
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
alpm_filelist_t *filelist;
|
|
|
|
size_t i;
|
2009-03-30 12:48:15 -04:00
|
|
|
|
2011-06-07 14:15:43 -04:00
|
|
|
root = alpm_option_get_root(config->handle);
|
2009-03-30 12:48:15 -04:00
|
|
|
rootlen = strlen(root);
|
|
|
|
if(rootlen + 1 > PATH_MAX) {
|
|
|
|
/* we are in trouble here */
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, "");
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2009-03-30 12:48:15 -04:00
|
|
|
}
|
|
|
|
strcpy(f, root);
|
|
|
|
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
pkgname = alpm_pkg_get_name(pkg);
|
|
|
|
filelist = alpm_pkg_get_files(pkg);
|
|
|
|
for(i = 0; i < filelist->count; i++) {
|
|
|
|
const alpm_file_t *file = filelist->files + i;
|
2009-03-30 12:48:15 -04:00
|
|
|
struct stat st;
|
2011-06-16 14:16:49 -04:00
|
|
|
const char *path = file->name;
|
2009-03-30 12:48:15 -04:00
|
|
|
|
|
|
|
if(rootlen + 1 + strlen(path) > PATH_MAX) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_WARNING, _("path too long: %s%s\n"), root, path);
|
2009-03-30 12:48:15 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
strcpy(f + rootlen, path);
|
|
|
|
/* use lstat to prevent errors from symlinks */
|
|
|
|
if(lstat(f, &st) != 0) {
|
|
|
|
if(config->quiet) {
|
|
|
|
printf("%s %s\n", pkgname, f);
|
|
|
|
} else {
|
2011-07-01 12:01:38 -04:00
|
|
|
pm_printf(ALPM_LOG_WARNING, "%s: %s (%s)\n",
|
2009-03-30 12:48:15 -04:00
|
|
|
pkgname, f, strerror(errno));
|
|
|
|
}
|
|
|
|
errors++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!config->quiet) {
|
2011-09-07 21:41:09 -04:00
|
|
|
printf(_n("%s: %jd total file, ", "%s: %jd total files, ",
|
|
|
|
(unsigned long)filelist->count), pkgname, (intmax_t)filelist->count);
|
|
|
|
printf(_n("%jd missing file\n", "%jd missing files\n",
|
|
|
|
(unsigned long)errors), (intmax_t)errors);
|
2009-03-30 12:48:15 -04:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return (errors != 0 ? 1 : 0);
|
2009-03-30 12:48:15 -04:00
|
|
|
}
|
|
|
|
|
2011-06-28 09:26:39 -04:00
|
|
|
static int display(alpm_pkg_t *pkg)
|
2009-03-30 12:48:15 -04:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2007-07-14 14:45:30 -04:00
|
|
|
if(config->op_q_info) {
|
2007-11-11 16:02:33 -05:00
|
|
|
if(config->op_q_isfile) {
|
2011-08-29 00:41:17 -04:00
|
|
|
dump_pkg_full(pkg, 0);
|
2007-11-11 16:02:33 -05:00
|
|
|
} else {
|
2011-08-29 00:41:17 -04:00
|
|
|
dump_pkg_full(pkg, config->op_q_info > 1);
|
2007-11-11 16:02:33 -05:00
|
|
|
}
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
|
|
|
if(config->op_q_list) {
|
2009-05-10 16:41:29 -04:00
|
|
|
dump_pkg_files(pkg, config->quiet);
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
|
|
|
if(config->op_q_changelog) {
|
2007-12-09 00:42:04 -05:00
|
|
|
dump_pkg_changelog(pkg);
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2009-03-30 12:48:15 -04:00
|
|
|
if(config->op_q_check) {
|
|
|
|
ret = check(pkg);
|
|
|
|
}
|
|
|
|
if(!config->op_q_info && !config->op_q_list
|
|
|
|
&& !config->op_q_changelog && !config->op_q_check) {
|
2011-04-20 20:45:16 -04:00
|
|
|
if(!config->quiet) {
|
2007-11-07 02:05:33 -05:00
|
|
|
printf("%s %s\n", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
|
|
|
|
} else {
|
|
|
|
printf("%s\n", alpm_pkg_get_name(pkg));
|
|
|
|
}
|
2005-12-13 21:23:14 -05:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int pacman_query(alpm_list_t *targets)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2009-08-18 10:56:19 -04:00
|
|
|
int match = 0;
|
2007-06-12 23:55:14 -04:00
|
|
|
alpm_list_t *i;
|
2011-06-28 09:26:39 -04:00
|
|
|
alpm_pkg_t *pkg = NULL;
|
2011-06-28 00:11:43 -04:00
|
|
|
alpm_db_t *db_local;
|
2005-12-13 21:23:14 -05:00
|
|
|
|
2007-06-12 23:55:14 -04:00
|
|
|
/* First: operations that do not require targets */
|
|
|
|
|
|
|
|
/* search for a package */
|
|
|
|
if(config->op_q_search) {
|
|
|
|
ret = query_search(targets);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
|
|
|
|
2007-06-02 12:34:01 -04:00
|
|
|
/* looking for groups */
|
|
|
|
if(config->group) {
|
|
|
|
ret = query_group(targets);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2011-06-08 00:08:06 -04:00
|
|
|
if(config->op_q_foreign || config->op_q_upgrade) {
|
|
|
|
if(check_syncdbs(1, 1)) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
2007-06-02 12:34:01 -04:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2011-06-07 14:15:43 -04:00
|
|
|
db_local = alpm_option_get_localdb(config->handle);
|
2011-01-28 18:41:15 -05:00
|
|
|
|
2007-06-12 23:55:14 -04:00
|
|
|
/* operations on all packages in the local DB
|
2009-03-30 12:48:15 -04:00
|
|
|
* valid: no-op (plain -Q), list, info, check
|
2007-06-12 23:55:14 -04:00
|
|
|
* invalid: isfile, owns */
|
2007-07-14 14:45:30 -04:00
|
|
|
if(targets == NULL) {
|
|
|
|
if(config->op_q_isfile || config->op_q_owns) {
|
2011-07-01 12:01:38 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2007-07-14 14:45:30 -04:00
|
|
|
}
|
|
|
|
|
2011-02-25 09:22:09 -05:00
|
|
|
for(i = alpm_db_get_pkgcache(db_local); i; i = alpm_list_next(i)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
pkg = i->data;
|
2007-07-14 14:45:30 -04:00
|
|
|
if(filter(pkg)) {
|
2009-03-30 12:48:15 -04:00
|
|
|
int value = display(pkg);
|
|
|
|
if(value != 0) {
|
|
|
|
ret = 1;
|
|
|
|
}
|
2009-08-18 10:56:19 -04:00
|
|
|
match = 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
2009-08-18 10:56:19 -04:00
|
|
|
if(!match) {
|
|
|
|
ret = 1;
|
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-06-12 23:55:14 -04:00
|
|
|
/* Second: operations that require target(s) */
|
|
|
|
|
|
|
|
/* determine the owner of a file */
|
|
|
|
if(config->op_q_owns) {
|
|
|
|
ret = query_fileowner(targets);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* operations on named packages in the local DB
|
2009-03-30 12:48:15 -04:00
|
|
|
* valid: no-op (plain -Q), list, info, check */
|
2007-06-12 23:55:14 -04:00
|
|
|
for(i = targets; i; i = alpm_list_next(i)) {
|
2011-10-06 01:55:47 -04:00
|
|
|
const char *strname = i->data;
|
2007-07-14 14:45:30 -04:00
|
|
|
|
|
|
|
if(config->op_q_isfile) {
|
2011-06-27 17:29:49 -04:00
|
|
|
alpm_pkg_load(config->handle, strname, 1, 0, &pkg);
|
2007-07-14 14:45:30 -04:00
|
|
|
} else {
|
|
|
|
pkg = alpm_db_get_pkg(db_local, strname);
|
|
|
|
}
|
|
|
|
|
2007-06-12 23:55:14 -04:00
|
|
|
if(pkg == NULL) {
|
2011-08-25 19:29:00 -04:00
|
|
|
switch(alpm_errno(config->handle)) {
|
|
|
|
case ALPM_ERR_PKG_NOT_FOUND:
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR,
|
2011-08-25 19:29:00 -04:00
|
|
|
_("package '%s' was not found\n"), strname);
|
2011-09-01 19:01:33 -04:00
|
|
|
if(!config->op_q_isfile && access(strname, R_OK) == 0) {
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_WARNING,
|
2011-09-05 13:16:07 -04:00
|
|
|
_("'%s' is a file, you might want to use %s.\n"),
|
2011-09-01 19:01:33 -04:00
|
|
|
strname, "-p/--file");
|
|
|
|
}
|
2011-08-25 19:29:00 -04:00
|
|
|
break;
|
|
|
|
default:
|
2011-10-21 11:44:19 -04:00
|
|
|
pm_printf(ALPM_LOG_ERROR,
|
2011-08-25 19:29:00 -04:00
|
|
|
_("could not load package '%s': %s\n"), strname,
|
|
|
|
alpm_strerror(alpm_errno(config->handle)));
|
|
|
|
break;
|
|
|
|
}
|
2009-03-30 12:48:15 -04:00
|
|
|
ret = 1;
|
2007-06-12 23:55:14 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-07-14 14:45:30 -04:00
|
|
|
if(filter(pkg)) {
|
2009-03-30 12:48:15 -04:00
|
|
|
int value = display(pkg);
|
|
|
|
if(value != 0) {
|
|
|
|
ret = 1;
|
|
|
|
}
|
2009-08-18 10:56:19 -04:00
|
|
|
match = 1;
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
2007-11-25 15:12:00 -05:00
|
|
|
|
|
|
|
if(config->op_q_isfile) {
|
|
|
|
alpm_pkg_free(pkg);
|
|
|
|
pkg = NULL;
|
|
|
|
}
|
2007-06-12 23:55:14 -04:00
|
|
|
}
|
|
|
|
|
2009-08-18 10:56:19 -04:00
|
|
|
if(!match) {
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* vim: set ts=2 sw=2 noet: */
|