The following commit has been merged in the master branch:
commit 0680aef0b534cb219f36788e25520c667e9e7ba7
Author: Guillem Jover <[email protected]>
Date:   Sun Sep 6 08:14:00 2009 +0200

    dpkg-query: Add installed package control path query support
    
    This new command is to be used in special cirmcumstances when the
    maintainer scripts, or external programs need to know the paths to an
    installed package control files, without needing to hardcode or assume
    any file system layout for the dpkg database.

diff --git a/debian/changelog b/debian/changelog
index 1778368..469d002 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -44,6 +44,7 @@ dpkg (1.15.4) UNRELEASED; urgency=low
   * On configuration error print file name and line number.
   * Allow quoting values in configuration file options.
   * Add new --pre-invoke and --post-invoke hooks in dpkg.
+  * Add new --control-path command to dpkg-query.
 
   [ Raphael Hertzog ]
   * Replace install-info by a wrapper around GNU's install-info. The wrapper
diff --git a/man/dpkg-query.1 b/man/dpkg-query.1
index 09180b1..8fc7bf9 100644
--- a/man/dpkg-query.1
+++ b/man/dpkg-query.1
@@ -1,4 +1,4 @@
-.TH dpkg\-query 1 "2008-08-18" "Debian Project" "dpkg suite"
+.TH dpkg\-query 1 "2009-09-06" "Debian Project" "dpkg suite"
 .SH NAME
 dpkg\-query \- a tool to query the dpkg database
 .
@@ -47,6 +47,14 @@ List files installed to your system from \fIpackage-name\fP.
 However, note that files created by package-specific
 installation-scripts are not listed.
 .TP
+.BR \-c ", " \-\-control\-path " \fIpackage-name\fP [\fIcontrol-file\fP]"
+List paths for control files installed to your system from \fIpackage-name\fP.
+If \fIcontrol-file\fP is specified then only list the path for that control
+file if it is present. \fBWarning\fP: this command is semi-public, it should
+be used only as a last resort solution, and if no other interface is
+available. It might get deprecated later on if better interfaces or the
+current architectural deficiencies have been solved.
+.TP
 .BR \-S ", " \-\-search " \fIfilename-search-pattern\fP..."
 Search for a filename from installed packages. All standard shell
 wildchars can be used in the pattern. This command will not list
diff --git a/src/main.h b/src/main.h
index 8f8dba5..8f1829e 100644
--- a/src/main.h
+++ b/src/main.h
@@ -66,6 +66,7 @@ enum action {
        act_listpackages,
        act_listfiles,
        act_searchfiles,
+       act_controlpath,
 
        act_cmpversions,
 
diff --git a/src/query.c b/src/query.c
index 0ca9a87..68244ac 100644
--- a/src/query.c
+++ b/src/query.c
@@ -4,6 +4,7 @@
  *
  * Copyright © 1995,1996 Ian Jackson <[email protected]>
  * Copyright © 2000,2001 Wichert Akkerman <[email protected]>
+ * Copyright © 2006-2009 Guillem Jover <[email protected]>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as
@@ -34,6 +35,7 @@
 #include <sys/ioctl.h>
 #include <sys/termios.h>
 #include <fcntl.h>
+#include <dirent.h>
 
 #if HAVE_LOCALE_H
 #include <locale.h>
@@ -436,6 +438,121 @@ void showpackages(const char *const *argv) {
   modstatdb_shutdown();
 }
 
+static void
+control_path_file(struct pkginfo *pkg, const char *control_file)
+{
+  const char *control_path;
+  struct stat st;
+
+  /* Do not expose internal database files. */
+  if (strcmp(control_file, LISTFILE) == 0 ||
+      strcmp(control_file, CONFFILESFILE) == 0)
+    return;
+
+  control_path = pkgadminfile(pkg, control_file);
+
+  if (stat(control_path, &st) < 0)
+    return;
+
+  if (!S_ISREG(st.st_mode))
+    return;
+
+  printf("%s\n", control_path);
+}
+
+static void
+control_path_pkg(struct pkginfo *pkg)
+{
+  DIR *db_dir;
+  struct dirent *db_de;
+  struct varbuf db_path;
+  size_t db_path_len;
+
+  varbufinit(&db_path, 0);
+  varbufaddstr(&db_path, admindir);
+  varbufaddstr(&db_path, "/" INFODIR);
+  db_path_len = db_path.used;
+  varbufaddc(&db_path, '\0');
+
+  db_dir = opendir(db_path.buf);
+  if (!db_dir)
+    ohshite(_("cannot read info directory"));
+
+  push_cleanup(cu_closedir, ~0, NULL, 0, 1, (void *)db_dir);
+  while ((db_de = readdir(db_dir)) != NULL) {
+    const char *p;
+
+    /* Ignore dotfiles, including ‘.’ and ‘..’. */
+    if (db_de->d_name[0] == '.')
+      continue;
+
+    /* Ignore anything odd. */
+    p = strrchr(db_de->d_name, '.');
+    if (!p)
+      continue;
+
+    /* Ignore files from other packages. */
+    if (strlen(pkg->name) != (size_t)(p - db_de->d_name) ||
+        strncmp(db_de->d_name, pkg->name, p - db_de->d_name))
+      continue;
+
+    /* Skip past the full stop. */
+    p++;
+
+    /* Do not expose internal database files. */
+    if (strcmp(p, LISTFILE) == 0 ||
+        strcmp(p, CONFFILESFILE) == 0)
+      continue;
+
+    if (strlen(p) > MAXCONTROLFILENAME)
+      continue;
+
+    db_path.used = db_path_len;
+    varbufaddstr(&db_path, db_de->d_name);
+    varbufaddc(&db_path, '\0');
+
+    printf("%s\n", db_path.buf);
+  }
+  pop_cleanup(ehflag_normaltidy); /* closedir */
+
+  varbuffree(&db_path);
+}
+
+static void
+control_path(const char *const *argv)
+{
+  struct pkginfo *pkg;
+  const char *pkg_name;
+  const char *control_file;
+
+  pkg_name = *argv++;
+  control_file = *argv++;
+
+  if (!pkg_name)
+    badusage(_("--%s needs at least one package name argument"),
+             cipaction->olong);
+
+  /* Validate control file name for sanity. */
+  if (control_file) {
+    for (const char *c = "/."; *c; c++)
+      if (strchr(control_file, *c))
+        badusage(_("control file contains %c"), *c);
+  }
+
+  modstatdb_init(admindir, msdbrw_readonly | msdbrw_noavail);
+
+  pkg = findpackage(pkg_name);
+  if (pkg->status == stat_notinstalled)
+    badusage(_("Package `%s' is not installed.\n"), pkg->name);
+
+  if (control_file)
+    control_path_file(pkg, control_file);
+  else
+    control_path_pkg(pkg);
+
+  modstatdb_shutdown();
+}
+
 void
 printversion(void)
 {
@@ -463,6 +580,8 @@ usage(void)
 "  -l|--list [<pattern> ...]        List packages concisely.\n"
 "  -W|--show <pattern> ...          Show information on package(s).\n"
 "  -S|--search <pattern> ...        Find package(s) owning file(s).\n"
+"  -c|--control-path <package> [<file>]\n"
+"                                   Print path for package control file.\n"
 "\n"));
 
   printf(_(
@@ -529,6 +648,7 @@ static const struct cmdinfo cmdinfos[]= {
   ACTION( "list",                           'l', act_listpackages,  
listpackages    ),
   ACTION( "search",                         'S', act_searchfiles,   
searchfiles     ),
   ACTION( "show",                           'W', act_listpackages,  
showpackages    ),
+  ACTION( "control-path",                   'c', act_controlpath,   
control_path    ),
 
   { "admindir",   0,   1, NULL, &admindir,   NULL          },
   { "showformat", 'f', 1, NULL, &showformat, NULL          },

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to