Bug#546365: pu: package pmount/0.9.18-2+lenny1
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu
Hello,
pmount in stable suffers from a rather painful bug: it is useless
with all kernels with deprecated sysfs features disabled (see
#528404). This does not affect (yet) users of the stock kernel
(2.6.26), but affects any user that compiles their own more recent
kernels, and it will probably affect lenny-and-a-half too.
A fix has been uploaded to squeeeze not long after lenny's release,
and it has been rather extensively tested; in particular, no security
flaws were found. An additional benefit is that it drops a dependency
on libsysfs.
Would that be a suitable candidate for an upload to spu ?
Many thanks,
Vincent
-- System Information:
Debian Release: squeeze/sid
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.30-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB, LC_CTYPE=en_GB (charmap=ISO-8859-1)
Shell: /bin/sh linked to /bin/dash
diff -u pmount-0.9.18/debian/changelog pmount-0.9.18/debian/changelog
--- pmount-0.9.18/debian/changelog
+++ pmount-0.9.18/debian/changelog
@@ -1,3 +1,10 @@
+pmount (0.9.18-2+lenny1) stable-proposed-updates; urgency=medium
+
+ * Import patch from the 0.9.19 release to have pmount working with
+ kernels without the deprecated sysfs elements (closes: #528404)
+
+ -- Vincent Fourmond <fourmond@debian.org> Sat, 12 Sep 2009 21:01:53 +0200
+
pmount (0.9.18-2) unstable; urgency=medium
* Adding Vcs-* fields
diff -u pmount-0.9.18/debian/control pmount-0.9.18/debian/control
--- pmount-0.9.18/debian/control
+++ pmount-0.9.18/debian/control
@@ -2,7 +2,7 @@
Section: utils
Priority: optional
Maintainer: Vincent Fourmond <fourmond@debian.org>
-Build-Depends: cdbs, debhelper (>= 4.1.0), libsysfs-dev,
+Build-Depends: cdbs, debhelper (>= 4.1.0),
libhal-dev (>= 0.5.2), libhal-storage-dev (>= 0.5.2),
intltool, dpatch, libblkid-dev
Standards-Version: 3.8.0
diff -u pmount-0.9.18/debian/rules pmount-0.9.18/debian/rules
--- pmount-0.9.18/debian/rules
+++ pmount-0.9.18/debian/rules
@@ -3,6 +3,8 @@
include /usr/share/cdbs/1/class/autotools.mk
include /usr/share/cdbs/1/rules/dpatch.mk
+DEB_AUTO_UPDATE_AUTOCONF = 1
+
common-post-build-arch::
# Generate a POT file
cd po; intltool-update -p --verbose
diff -u pmount-0.9.18/debian/patches/00list pmount-0.9.18/debian/patches/00list
--- pmount-0.9.18/debian/patches/00list
+++ pmount-0.9.18/debian/patches/00list
@@ -1,0 +2 @@
+10-fix-newer-sysfs
only in patch2:
unchanged:
--- pmount-0.9.18.orig/debian/patches/10-fix-newer-sysfs.dpatch
+++ pmount-0.9.18/debian/patches/10-fix-newer-sysfs.dpatch
@@ -0,0 +1,475 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 10-fix-newer-sysfs.dpatch by <fourmond@debian.org>
+##
+## DP: Pull patch from 0.9.19 to make pmount work with newer kernels
+
+diff --git a/configure.ac b/configure.ac
+index 5f392e1..54f8ba8 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -16,11 +16,12 @@ AC_PROG_INSTALL
+
+ AC_DEFINE([HAVE_BLKID], [], [Description])
+
+-AC_CHECK_HEADER(sysfs/libsysfs.h,
+- [AC_CHECK_LIB(sysfs, sysfs_open_attribute,
+- [LIBS="$LIBS -lsysfs"],
+- [AC_MSG_ERROR([Missing sysfs library (install libsysfs-dev or similar?)])])],
+- [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h (install libsysfs-dev or similar?)])])
++dnl AC_CHECK_HEADER(sysfs/libsysfs.h,
++dnl [AC_CHECK_LIB(sysfs, sysfs_open_attribute,
++dnl [LIBS="$LIBS -lsysfs"],
++dnl [AC_MSG_ERROR([Missing sysfs library (install libsysfs-dev or similar?)])])],
++dnl [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h (install libsysfs-dev or similar?)])])
++
+
+ AC_CHECK_HEADER(blkid/blkid.h,
+ [AC_CHECK_LIB(blkid, blkid_get_cache,
+@@ -82,6 +83,8 @@ AC_SUBST(GETTEXT_PACKAGE)
+ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
+ AM_GLIB_GNU_GETTEXT
+
++AC_MSG_WARN([This branch of pmount is experimental and currently does not work, USE WITH CARE !])
++
+ AC_OUTPUT([
+ Makefile
+ po/Makefile.in
+diff --git a/src/policy.c b/src/policy.c
+index 8d7ba1b..9c770f6 100644
+--- a/src/policy.c
++++ b/src/policy.c
+@@ -1,8 +1,10 @@
+ /**
+ * policy.c - functions for testing various policy parts for pmount
+ *
+- * Author: Martin Pitt <martin.pitt@canonical.com>
+- * (c) 2004 Canonical Ltd.
++ * Authors: Martin Pitt <martin.pitt@canonical.com>,
++ * Vincent Fourmond <fourmond@debian.org
++ * (c) 2004 Canonical Ltd,
++ * 2007, 2008, 2009 by Vincent Fourmond
+ *
+ * This software is distributed under the terms and conditions of the
+ * GNU General Public License. See file GPL for the full text of the license.
+@@ -20,13 +22,13 @@
+ #include <dirent.h>
+ #include <libintl.h>
+ #include <sys/stat.h>
+-#include <sysfs/libsysfs.h>
+ #include <regex.h>
+
+ /* For globs in /etc/pmount.allow */
+ #include <fnmatch.h>
+
+
++/* We use our own safe version of realpath */
+ #include "realpath.h"
+
+ /*************************************************************************
+@@ -35,81 +37,15 @@
+ *
+ *************************************************************************/
+
+-
+-/**
+- * Check whether a bus occurs anywhere in the ancestry of a device.
+- * @param dev sysfs device
+- * @param buses NULL-terminated array of bus names to scan for
+- * @return 0 if not found, 1 if found
+- */
+-int
+-find_bus_ancestry( struct sysfs_device* dev, char** buses ) {
+- char **i;
+- struct sysfs_bus * bus;
+- struct sysfs_device * found;
+-
+- if( !buses ) {
+- debug ( "find_bus_ancestry: no buses to check, fail\n" );
+- return 0;
+- }
+-
+- if( !dev ) {
+- debug ( "find_bus_ancestry: dev == NULL, fail\n" );
+- return 0;
+- }
+-
+- for( i = buses; *i; ++i ) {
+- if( !strcmp( dev->bus, *i ) ) {
+- debug ( "find_bus_ancestry: device %s (path %s, bus %s) matches query, success\n",
+- dev->name, dev->path, dev->bus );
+- return 1;
+- }
+- }
+- /* Try the hard way */
+- if(find_device_in_buses(dev, buses))
+- return 1;
+-
+- debug ( "find_bus_ancestry: device '%s' (path '%s', bus '%s') "
+- "does not match, trying parent\n",
+- dev->name, dev->path, dev->bus );
+- return find_bus_ancestry( sysfs_get_device_parent( dev ), buses );
+-}
+-
+ /**
+- * Check whether a particular device is found in a list of buses.
+- * @param dev sysfs device
+- * @param buses NULL-terminated array of bus names to scan for
+- * @return 0 if not found, 1 if found
++ The directories to search for to find the block subsystem. Null-terminated.
+ */
+-
+-int
+-find_device_in_buses( struct sysfs_device * dev, char** buses) {
+- struct sysfs_bus * bus;
+- struct sysfs_device * found;
+- char ** i;
+-
+- for(i = buses; *i; ++i)
+- {
+- bus = sysfs_open_bus(*i);
+- if(bus)
+- {
+- debug("find_device_in_buses : "
+- "successfully opened bus '%s' path '%s'\n",
+- bus->name, bus->path);
+- found = sysfs_get_bus_device(bus,dev->bus_id);
+- if(found)
+- {
+- debug("find_device_in_buses : "
+- "found '%s' in bus '%s'\n",
+- dev->name, *i);
+- sysfs_close_bus(bus);
+- return 1; /* We found it !*/
+- }
+- sysfs_close_bus(bus);
+- }
+- }
+- return 0;
+-}
++static const char * block_subsystem_directories[] = {
++ "/sys/subsystem/block",
++ "/sys/class/block",
++ "/sys/block",
++ NULL
++};
+
+
+
+@@ -121,20 +57,41 @@ find_device_in_buses( struct sysfs_device * dev, char** buses) {
+ * is written into this buffer; this can be used to query additional
+ * attributes
+ * @param blockdevpathsize size of blockdevpath buffer (if not NULL)
+- * @return Matching sysfs_device node (NULL if not found)
++ * @return 0 if device was found and -1 if it was not.
++ */
++
++/* This function needs a major rewrite to get rid of the
++ libsysfs dependencies...
++
++ Proposal:
++ - browse /sys/block or /sys/class/block for devices whose dev matches
++ the major/minor of the device we're interested in
++ - get the removable property
++
++ Problem: assumes too much about the directory structure, but is
++ already better and that would drop the dependency on libsysfs
++*/
++
++/*
++ The rationale of the steps found in this function are based on my
++ own experience and on Documentation/sysfs-rules.txt
+ */
+-struct sysfs_device*
+-find_sysfs_device( const char* dev, char* blockdevpath, size_t blockdevpathsize ) {
++
++int find_sysfs_device( const char* dev, char* blockdevpath,
++ size_t blockdevpathsize )
++{
+ unsigned char devmajor, devminor;
+ unsigned char sysmajor, sysminor;
+- char mntpath[PATH_MAX];
+ char blockdirname[255];
+ char devdirname[512]; // < 255 chars blockdir + max. 255 chars subdir
+ char devfilename[PATH_MAX];
+- char linkfilename[1024];
++
++ int ret_val = 0; /* Failing by default. */
++
++ const char ** looking_for_block = block_subsystem_directories;
++
+ DIR *devdir, *partdir;
+ struct dirent *devdirent, *partdirent;
+- struct sysfs_device *sysdev = NULL;
+ struct stat devstat;
+
+ /* determine major and minor of dev */
+@@ -148,12 +105,27 @@ find_sysfs_device( const char* dev, char* blockdevpath, size_t blockdevpathsize
+ debug( "find_sysfs_device: looking for sysfs directory for device %u:%u\n",
+ (unsigned) devmajor, (unsigned) devminor );
+
+- /* get /sys/block/ */
+- if( sysfs_get_mnt_path( mntpath, sizeof(mntpath) ) ) {
+- fputs( _("Error: could not get sysfs directory\n"), stderr );
+- exit( -1 );
++ /* We first need to find one of
++
++ /sys/subsystem/block, /sys/class/block or /sys/block
++
++ And then, we look for the right device number.
++
++ */
++ while(*looking_for_block) {
++ if(! stat( *looking_for_block, &devstat)) {
++ debug( "found block subsystem at: %s\n", *looking_for_block);
++ snprintf( blockdirname, sizeof( blockdirname ),
++ "%s/", *looking_for_block);
++ break;
++ }
++ looking_for_block++;
++ }
++
++ if(! *looking_for_block) {
++ perror( _("Error: could find the block subsystem directory") );
++ exit( -1 );
+ }
+- snprintf( blockdirname, sizeof( blockdirname ), "%s/block/", mntpath );
+
+ devdir = opendir( blockdirname );
+ if( !devdir ) {
+@@ -226,29 +198,32 @@ find_sysfs_device( const char* dev, char* blockdevpath, size_t blockdevpathsize
+ dev );
+
+
+- snprintf( devfilename, sizeof( devfilename ), "%s/device", devdirname );
+-
+- /* read out the link */
+- if( !sysfs_get_link( devfilename, linkfilename, 1024 ) )
+- sysdev = sysfs_open_device_path( linkfilename );
+-
+- /* return /sys/block/<drive> if requested */
++ /*
++ return /sys/block/<drive> if requested
++ */
+ if( blockdevpath )
+- snprintf( blockdevpath, blockdevpathsize, "%s", devdirname );
++ snprintf( blockdevpath, blockdevpathsize, "%s", devdirname );
++ else
++ debug( "WARNING: find_sysfs_device is called without blockdevpath argument\n");
++
++ ret_val = 1; /* We found it ! */
+ break;
+ }
+ }
+
+ closedir( devdir );
+
+- return sysdev;
++ return ret_val;
+ }
+
+ /**
+- * Return whether attribute attr in blockdevpath exists and has value '1'.
++ Return whether attribute attr in blockdevpath exists and has value '1'.
++
++ Or, in other words, if blockdevpath/attr exists and contains a '1' as
++ its first character.
+ */
+ int
+-get_blockdev_attr( const char* blockdevpath, const char* attr )
++is_blockdev_attr_true( const char* blockdevpath, const char* attr )
+ {
+ char path[PATH_MAX];
+ FILE* f;
+@@ -259,7 +234,7 @@ get_blockdev_attr( const char* blockdevpath, const char* attr )
+
+ f = fopen( path, "r" );
+ if( !f ) {
+- debug( "get_blockdev_attr: could not open %s\n", path );
++ debug( "is_blockdev_attr_true: could not open %s\n", path );
+ return 0;
+ }
+
+@@ -267,15 +242,129 @@ get_blockdev_attr( const char* blockdevpath, const char* attr )
+ fclose( f );
+
+ if( result != 1 ) {
+- debug( "get_blockdev_attr: could not read %s\n", path );
++ debug( "is_blockdev_attr_true: could not read %s\n", path );
+ return 0;
+ }
+
+- debug( "get_blockdev_attr: value of %s == %c\n", path, value );
++ debug( "is_blockdev_attr_true: value of %s == %c\n", path, value );
+
+ return value == '1';
+ }
+
++
++/*************************************************************************/
++/* Bus-related functions
++
++ WARNING. Quoting Documentation/sysfs-rules.txt:
++
++ - devices are only "devices"
++ There is no such thing like class-, bus-, physical devices,
++ interfaces, and such that you can rely on in userspace. Everything is
++ just simply a "device". Class-, bus-, physical, ... types are just
++ kernel implementation details which should not be expected by
++ applications that look for devices in sysfs.
++
++ Therefore, the notion of 'bus' is at best not reliable. But I still
++ keep the information, as it could help in corner cases.
++*/
++
++
++/**
++ Tries to find the 'bus' of the given *device* (ie, under
++ /sys/devices), and stores is into the bus string.
++
++ Note that this function is in no way guaranteed to work, as the bus
++ attribute is "fragile". But I'm not aware of anything better for
++ now.
++
++ This function was rewritten from scratch by
++ Heinz-Ado Arnolds <arnolds@mpa-garching.mpg.de>, with a much better
++ knowledge than me about the newer sysfs architecture.
++
++ Many thanks !
++ */
++
++const char * get_device_bus( const char* devicepath, const char **buses)
++{
++ char link[PATH_MAX];
++ char path[PATH_MAX];
++ char devfilename[PATH_MAX];
++ ssize_t link_size;
++ const char *res = NULL;
++ const char **i;
++ DIR *busdir;
++ struct dirent *busdirent;
++
++ for ( i = buses; *i; i++ ) {
++ snprintf(path, sizeof(path), "/sys/bus/%s/devices", *i);
++ if ( !(busdir = opendir(path)) ) {
++ debug( "can't open bus/devicedir: %s\n", path);
++ continue;
++ }
++ while( ( busdirent = readdir( busdir ) ) != NULL ) {
++ snprintf( devfilename, sizeof( devfilename ), "%s/%s", path, busdirent->d_name);
++ if(! realpath(devfilename, link)) {
++ debug( "Could not read link at %s/%s\n", path, busdirent->d_name);
++ continue;
++ }
++ if ( ! strcmp(devicepath, link) ) {
++ res = *i;
++ break;
++ }
++ }
++ closedir(busdir);
++ if ( res )
++ break;
++ }
++
++ return res;
++}
++
++
++/**
++ * Check whether a bus occurs anywhere in the ancestry of a device.
++ * @param blockdevpath is a device as returned by
++ * @param buses NULL-terminated array of bus names to scan for
++ * @return the name of the bus found, or NULL
++ */
++const char * bus_has_ancestry(const char * blockdevpath, const char** buses) {
++ char path[1024];
++ char full_device[1024];
++ char * tmp = "";
++ const char *bus;
++ struct stat sb;
++
++ // The sysfs structure has changed:
++ // in former times /sys/block/<dev> was a directory and
++ // /sys/block/<dev>/device a link to the real device dir.
++ // Now (linux-2.6.27.9) /sys/block/<dev> is a link to the
++ // real device dir.
++ lstat(blockdevpath, &sb);
++ if ( !S_ISLNK(sb.st_mode) )
++ tmp = "/device";
++ snprintf(path, sizeof(path), "%s%s", blockdevpath, tmp);
++ if(! realpath(path, full_device)) {
++ debug("Realpath failed to resolve %s\n", path);
++ return NULL;
++ }
++
++ /* We now have a full path to the device */
++
++ /* We loop on full_device until we are on the root directory */
++ while(full_device[0]) {
++ if(bus = get_device_bus(full_device, buses)) {
++ debug("Found bus %s for device %s\n", bus, full_device);
++ return bus;
++ }
++ tmp = strrchr(full_device, '/');
++ if(! tmp)
++ break;
++ *tmp = 0;
++ }
++ return NULL;
++}
++
++
+ /*************************************************************************
+ *
+ * Policy functions
+@@ -430,27 +519,38 @@ device_mounted( const char* device, int expect, char* mntpt )
+ /* The silent version of the device_removable function. */
+ int device_removable_silent(const char * device)
+ {
+- struct sysfs_device *dev;
+- static char* hotplug_buses[] = { "usb", "ieee1394", "mmc", "pcmcia", NULL };
++ static const char* hotplug_buses[] = { "usb", "ieee1394", "mmc",
++ "pcmcia", NULL };
+ int removable;
+ char blockdevpath[PATH_MAX];
+-
+- dev = find_sysfs_device( device, blockdevpath, sizeof( blockdevpath ) );
+- if( !dev ) {
+- debug( "device_removable: could not find a sysfs device for %s\n", device );
++ const char * whitelisted_bus;
++
++ if(! find_sysfs_device(device, blockdevpath, sizeof(blockdevpath))) {
++ debug("device_removable: could not find a sysfs device for %s\n",
++ device );
+ return 0;
+ }
+
+- debug( "device_removable: corresponding block device for %s is %s\n",
+- device, blockdevpath );
++ debug("device_removable: corresponding block device for %s is %s\n",
++ device, blockdevpath);
+
+ /* check whether device has "removable" attribute with value '1' */
+- removable = get_blockdev_attr( blockdevpath, "removable" );
++ removable = is_blockdev_attr_true(blockdevpath, "removable");
+
+- /* if not, fall back to bus scanning (regard USB and FireWire as removable) */
+- if( !removable )
+- removable = find_bus_ancestry( dev, hotplug_buses );
+- sysfs_close_device( dev );
++ /*
++ If not, fall back to bus scanning (regard USB and FireWire as
++ removable, see above).
++ */
++ if(! removable) {
++ whitelisted_bus = bus_has_ancestry(blockdevpath, hotplug_buses);
++ if(whitelisted_bus) {
++ removable = 1;
++ debug("Found that device %s belong to whitelisted bus %s\n",
++ blockdevpath, whitelisted_bus);
++ }
++ else
++ debug("Device %s does not belong to any whitelisted bus\n");
++ }
+ return removable;
+ }
+
\ No newline at end of file
Reply to: