Просмотр исходного кода

[ABI] merged the libudev-dlopen branch, this allows to pass
"apt-udev-auto" to Acquire::Cdrom::mount and the cdrom method will
dynamically find/mount the cdrom device (if libhal is available)

Michael Vogt лет назад: 17
Родитель
Сommit
3e2d7cce4f
10 измененных файлов с 268 добавлено и 32 удалено
  1. 85 1
      apt-pkg/cdrom.cc
  2. 37 0
      apt-pkg/cdrom.h
  3. 10 3
      apt-pkg/contrib/cdromutl.cc
  4. 2 1
      apt-pkg/contrib/cdromutl.h
  5. 1 1
      apt-pkg/makefile
  6. 3 0
      debian/changelog
  7. 104 25
      methods/cdrom.cc
  8. 1 1
      methods/makefile
  9. 6 0
      test/makefile
  10. 19 0
      test/test_udevcdrom.cc

+ 85 - 1
apt-pkg/cdrom.cc

@@ -16,7 +16,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <algorithm>
-
+#include <dlfcn.h>
 
 #include "indexcopy.h"
 
@@ -840,3 +840,87 @@ bool pkgCdrom::Add(pkgCdromStatus *log)					/*{{{*/
    return true;
 }
 									/*}}}*/
+pkgUdevCdromDevices::pkgUdevCdromDevices()                     		/*{{{*/
+   : libudev_handle(NULL)
+{
+
+}
+									/*}}}*/
+
+bool
+pkgUdevCdromDevices::Dlopen()                     		        /*{{{*/
+{
+   // alread open
+   if(libudev_handle != NULL)
+      return true;
+
+   // see if we can get libudev
+   void *h = ::dlopen("libudev.so.0", RTLD_LAZY);
+   if(h == NULL)
+      return false;
+
+   // get the pointers to the udev structs
+   libudev_handle = h;
+   udev_new = (udev* (*)(void)) dlsym(h, "udev_new");
+   udev_enumerate_add_match_property = (int (*)(udev_enumerate*, const char*, const char*))dlsym(h, "udev_enumerate_add_match_property");
+   udev_enumerate_scan_devices = (int (*)(udev_enumerate*))dlsym(h, "udev_enumerate_scan_devices");
+   udev_enumerate_get_list_entry = (udev_list_entry* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_list_entry");
+   udev_device_new_from_syspath = (udev_device* (*)(udev*, const char*))dlsym(h, "udev_device_new_from_syspath");
+   udev_enumerate_get_udev = (udev* (*)(udev_enumerate*))dlsym(h, "udev_enumerate_get_udev");
+   udev_list_entry_get_name = (const char* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_name");
+   udev_device_get_devnode = (const char* (*)(udev_device*))dlsym(h, "udev_device_get_devnode");
+   udev_enumerate_new = (udev_enumerate* (*)(udev*))dlsym(h, "udev_enumerate_new");
+   udev_list_entry_get_next = (udev_list_entry* (*)(udev_list_entry*))dlsym(h, "udev_list_entry_get_next");
+   udev_device_get_property_value = (const char* (*)(udev_device *, const char *))dlsym(h, "udev_device_get_property_value");
+
+   return true;
+}
+									/*}}}*/
+vector<CdromDevice>
+pkgUdevCdromDevices::Scan()                                             /*{{{*/
+{
+   vector<CdromDevice> cdrom_devices;
+   struct udev_enumerate *enumerate;
+   struct udev_list_entry *l, *devices;
+   struct udev *udev_ctx;
+
+   if(libudev_handle == NULL)
+      return cdrom_devices;
+
+   udev_ctx = udev_new();
+   enumerate = udev_enumerate_new (udev_ctx);
+   udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
+
+   udev_enumerate_scan_devices (enumerate);
+   devices = udev_enumerate_get_list_entry (enumerate);
+   for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
+   {
+      CdromDevice cdrom;
+      struct udev_device *udevice;
+      udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l));
+      if (udevice == NULL)
+	 continue;
+      const char* devnode = udev_device_get_devnode(udevice);
+      const char* mountpath = udev_device_get_property_value(udevice, "FSTAB_DIR");
+
+      // fill in the struct
+      cdrom.DeviceName = string(devnode);
+      if (mountpath) {
+	 cdrom.MountPath = mountpath;
+	 string s = string(mountpath);
+	 cdrom.Mounted = IsMounted(s);
+      } else {
+	 cdrom.Mounted = false;
+	 cdrom.MountPath = "";
+      }
+      cdrom_devices.push_back(cdrom);
+   } 
+   return cdrom_devices;
+}
+									/*}}}*/
+
+pkgUdevCdromDevices::~pkgUdevCdromDevices()                             /*{{{*/
+{ 
+   dlclose(libudev_handle);
+}
+									/*}}}*/

+ 37 - 0
apt-pkg/cdrom.h

@@ -67,4 +67,41 @@ class pkgCdrom								/*{{{*/
 };
 									/*}}}*/
 
+
+// class that uses libudev to find cdrom devices dynamically
+struct CdromDevice							/*{{{*/
+{
+   string DeviceName;
+   bool Mounted;
+   string MountPath;
+};
+									/*}}}*/
+class pkgUdevCdromDevices						/*{{{*/
+{
+ protected:
+   // libudev dlopen stucture
+   void *libudev_handle;
+   struct udev* (*udev_new)(void);
+   int (*udev_enumerate_add_match_property)(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
+   int (*udev_enumerate_scan_devices)(struct udev_enumerate *udev_enumerate);
+   struct udev_list_entry* (*udev_enumerate_get_list_entry)(struct udev_enumerate *udev_enumerate);
+   struct udev_device* (*udev_device_new_from_syspath)(struct udev *udev, const char *syspath);
+   struct udev* (*udev_enumerate_get_udev)(struct udev_enumerate *udev_enumerate);
+   const char* (*udev_list_entry_get_name)(struct udev_list_entry *list_entry);
+   const char* (*udev_device_get_devnode)(struct udev_device *udev_device);
+   struct udev_enumerate *(*udev_enumerate_new) (struct udev *udev);
+   struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *list_entry);
+   const char* (*udev_device_get_property_value)(struct udev_device *udev_device, const char *key);
+   // end libudev dlopen
+   
+ public:
+   pkgUdevCdromDevices();
+   virtual ~pkgUdevCdromDevices();
+
+   // try to open 
+   bool Dlopen();
+   vector<CdromDevice> Scan();
+};
+									/*}}}*/
+
 #endif

+ 10 - 3
apt-pkg/contrib/cdromutl.cc

@@ -98,7 +98,7 @@ bool UnmountCdrom(string Path)
 // MountCdrom - Mount a cdrom						/*{{{*/
 // ---------------------------------------------------------------------
 /* We fork mount and drop all messages */
-bool MountCdrom(string Path)
+bool MountCdrom(string Path, string DeviceName)
 {
    if (IsMounted(Path) == true)
       return true;
@@ -122,8 +122,15 @@ bool MountCdrom(string Path)
       {
 	 const char *Args[10];
 	 Args[0] = "mount";
-	 Args[1] = Path.c_str();
-	 Args[2] = 0;
+	 if (DeviceName == "") 
+	 {
+	    Args[1] = Path.c_str();
+	    Args[2] = 0;
+	 } else {
+	    Args[1] = DeviceName.c_str();
+	    Args[2] = Path.c_str();
+	    Args[3] = 0;
+	 }
 	 execvp(Args[0],(char **)Args);      
 	 _exit(100);
       }      

+ 2 - 1
apt-pkg/contrib/cdromutl.h

@@ -14,7 +14,8 @@
 
 using std::string;
 
-bool MountCdrom(string Path);
+// mount cdrom, DeviceName (e.g. /dev/sr0) is optional
+bool MountCdrom(string Path, string DeviceName="");
 bool UnmountCdrom(string Path);
 bool IdentCdrom(string CD,string &Res,unsigned int Version = 2);
 bool IsMounted(string &Path);

+ 1 - 1
apt-pkg/makefile

@@ -15,7 +15,7 @@ LIBRARY=apt-pkg
 LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER)
 MAJOR=4.8
 MINOR=0
-SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil
+SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil -ldl
 APT_DOMAIN:=libapt-pkg$(MAJOR)
 
 # Source code for the contributed non-core things

+ 3 - 0
debian/changelog

@@ -96,6 +96,9 @@ apt (0.7.22) UNRELEASED; urgency=low
   * doc/apt.conf.5.xml:
     - merged patch from Aurélien Couderc to improve the text
       (thanks!)
+  * [ABI] merged the libudev-dlopen branch, this allows to pass
+    "apt-udev-auto" to Acquire::Cdrom::mount and the cdrom method will  
+    dynamically find/mount the cdrom device (if libhal is available)
 
   [ Julian Andres Klode ]
   * apt-pkg/contrib/configuration.cc: Fix a small memory leak in

+ 104 - 25
methods/cdrom.cc

@@ -9,6 +9,7 @@
 									/*}}}*/
 // Include Files							/*{{{*/
 #include <apt-pkg/acquire-method.h>
+#include <apt-pkg/cdrom.h>
 #include <apt-pkg/cdromutl.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
@@ -17,6 +18,7 @@
 
 #include <sys/stat.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
 #include <iostream>
 #include <apti18n.h>
@@ -27,15 +29,20 @@ using namespace std;
 class CDROMMethod : public pkgAcqMethod
 {
    bool DatabaseLoaded;
+   bool Debug;
+
    ::Configuration Database;
    string CurrentID;
    string CDROM;
    bool MountedByApt;
-   
+   pkgUdevCdromDevices UdevCdroms;
+ 
+   bool IsCorrectCD(URI want, string MountPath);
+   bool AutoDetectAndMount(URI);
    virtual bool Fetch(FetchItem *Itm);
    string GetID(string Name);
    virtual void Exit();
-   
+      
    public:
    
    CDROMMethod();
@@ -50,14 +57,15 @@ CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly |
                                           DatabaseLoaded(false), 
                                           MountedByApt(false)
 {
+   UdevCdroms.Dlopen();
 };
 									/*}}}*/
 // CDROMMethod::Exit - Unmount the disc if necessary			/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 void CDROMMethod::Exit()
-{
-   if (MountedByApt == true)
+{ 
+  if (MountedByApt == true)
       UnmountCdrom(CDROM);
 }
 									/*}}}*/
@@ -81,16 +89,94 @@ string CDROMMethod::GetID(string Name)
    return string();
 }
 									/*}}}*/
+// CDROMMethod::AutoDetectAndMount                                      /*{{{*/
+// ---------------------------------------------------------------------
+/* Modifies class varaiable CDROM to the mountpoint */
+bool CDROMMethod::AutoDetectAndMount(URI Get)
+{
+   vector<struct CdromDevice> v = UdevCdroms.Scan();
+
+   // first check if its mounted somewhere already
+   for (unsigned int i=0; i < v.size(); i++)
+   {
+      if (v[i].Mounted)
+      {
+	 if (Debug)
+	    clog << "Checking mounted cdrom device " << v[i].DeviceName << endl;
+	 if (IsCorrectCD(Get, v[i].MountPath))
+	 {
+	    CDROM = v[i].MountPath;
+	    return true;
+	 }
+      }
+   }
+
+   // we are not supposed to mount, exit
+   if (_config->FindB("APT::CDROM::NoMount",false) == true)
+      return false;
+
+   // check if we have the mount point
+   if (!FileExists("/media/apt"))
+      mkdir("/media/apt", 0755);
+
+   // now try mounting
+   for (unsigned int i=0; i < v.size(); i++)
+   {
+      if (!v[i].Mounted)
+      {
+	 if(MountCdrom("/media/apt", v[i].DeviceName)) 
+	 {
+	    if (IsCorrectCD(Get, "/media/apt"))
+	    {
+	       MountedByApt = true;
+	       CDROM = "/media/apt";
+	       return true;
+	    } else {
+	       UnmountCdrom("/media/apt");
+	    }
+	 }
+      }
+   }
+
+   return false;
+}
+									/*}}}*/
+// CDROMMethod::IsCorrectCD                                             /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool CDROMMethod::IsCorrectCD(URI want, string MountPath)
+{
+   string NewID;
+
+   for (unsigned int Version = 2; Version != 0; Version--)
+   {
+      if (IdentCdrom(MountPath,NewID,Version) == false)
+	 return false;
+      
+      if (Debug)
+	 clog << "ID " << Version << " " << NewID << endl;
+      
+      // A hit
+      if (Database.Find("CD::" + NewID) == want.Host)
+	 return true;
+   }
+   
+   return false;
+}
+									/*}}}*/
 // CDROMMethod::Fetch - Fetch a file					/*{{{*/
 // ---------------------------------------------------------------------
 /* */
 bool CDROMMethod::Fetch(FetchItem *Itm)
 {
+   FetchResult Res;
+
    URI Get = Itm->Uri;
    string File = Get.Path;
-   FetchResult Res;
+   Debug = _config->FindB("Debug::Acquire::cdrom", false);
 
-   bool Debug = _config->FindB("Debug::Acquire::cdrom",false);
+   if (Debug)
+      clog << "CDROMMethod::Fetch " << Itm->Uri << endl;
 
    /* All IMS queries are returned as a hit, CDROMs are readonly so 
       time stamps never change */
@@ -126,38 +212,31 @@ bool CDROMMethod::Fetch(FetchItem *Itm)
    }
 
    // We already have a CD inserted, but it is the wrong one
-   if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host)
+   if (CurrentID.empty() == false && 
+       CurrentID != "FAIL" &&
+       Database.Find("CD::" + CurrentID) != Get.Host)
    {
       Fail(_("Wrong CD-ROM"),true);
       return true;
    }
-   
+
    CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
+   if (Debug)
+      clog << "Looking for CDROM at " << CDROM << endl;
+
    if (CDROM[0] == '.')
       CDROM= SafeGetCWD() + '/' + CDROM;
    string NewID;
+
    while (CurrentID.empty() == true)
    {
-      bool Hit = false;
+      if (CDROM == "apt-udev-auto/") 
+	 AutoDetectAndMount(Get);
+
       if(!IsMounted(CDROM))
 	 MountedByApt = MountCdrom(CDROM);
-      for (unsigned int Version = 2; Version != 0; Version--)
-      {
-	 if (IdentCdrom(CDROM,NewID,Version) == false)
-	    return false;
-	 
-	 if (Debug == true)
-	    clog << "ID " << Version << " " << NewID << endl;
       
-	 // A hit
-	 if (Database.Find("CD::" + NewID) == Get.Host)
-	 {
-	    Hit = true;
-	    break;
-	 }	 
-      }
-
-      if (Hit == true)
+      if (IsCorrectCD(Get, CDROM))
 	 break;
 	 
       // I suppose this should prompt somehow?

+ 1 - 1
methods/makefile

@@ -40,7 +40,7 @@ include $(PROGRAM_H)
 
 # The cdrom method
 PROGRAM=cdrom
-SLIBS = -lapt-pkg $(INTLLIBS)
+SLIBS = -lapt-pkg -ldl $(INTLLIBS)
 LIB_MAKES = apt-pkg/makefile
 SOURCE = cdrom.cc
 include $(PROGRAM_H)

+ 6 - 0
test/makefile

@@ -68,6 +68,12 @@ SLIBS = -lapt-pkg
 SOURCE = hash.cc
 include $(PROGRAM_H)
 
+# Program for testing udevcdrom
+PROGRAM=test_udevcdrom
+SLIBS = -lapt-pkg 
+SOURCE = test_udevcdrom.cc
+include $(PROGRAM_H)
+
 # Program for checking rpm versions
 PROGRAM=rpmver
 SLIBS = -lapt-pkg -lrpm

+ 19 - 0
test/test_udevcdrom.cc

@@ -0,0 +1,19 @@
+#include <apt-pkg/cdrom.h>
+#include <stdio.h>
+#include <assert.h>
+
+int main()
+{
+   int i;
+   pkgUdevCdromDevices c;
+   assert(c.Dlopen());
+
+   vector<CdromDevice> l;
+   l = c.Scan();
+   assert(l.size() > 0);
+   for (i=0;i<l.size();i++)
+      std::cerr << l[i].DeviceName << " " 
+		<< l[i].Mounted << " " 
+		<< l[i].MountPath << std::endl;
+   
+}