Procházet zdrojové kódy

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.
Guillem Jover před 17 roky
rodič
revize
0680aef0b5
4 změnil soubory, kde provedl 131 přidání a 1 odebrání
  1. 1 0
      debian/changelog
  2. 9 1
      man/dpkg-query.1
  3. 1 0
      src/main.h
  4. 120 0
      src/query.c

+ 1 - 0
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

+ 9 - 1
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

+ 1 - 0
src/main.h

@@ -66,6 +66,7 @@ enum action {
 	act_listpackages,
 	act_listfiles,
 	act_searchfiles,
+	act_controlpath,
 
 	act_cmpversions,
 

+ 120 - 0
src/query.c

@@ -4,6 +4,7 @@
  *
  * Copyright © 1995,1996 Ian Jackson <ian@chiark.greenend.org.uk>
  * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
+ * Copyright © 2006-2009 Guillem Jover <guillem@debian.org>
  *
  * 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          },