- Reverted workaround parsing /proc/sys/dev/cdrom/info as fallback
[platform/upstream/libzypp.git] / zypp / media / MediaCD.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaCD.cc
10  *
11 */
12
13 #include <iostream>
14
15 #include "zypp/base/Logger.h"
16 #include "zypp/ExternalProgram.h"
17 #include "zypp/media/Mount.h"
18 #include "zypp/media/MediaCD.h"
19 #include "zypp/media/MediaManager.h"
20 #include "zypp/Url.h"
21 #include "zypp/target/hal/HalContext.h"
22
23 #include <cstring> // strerror
24 #include <cstdlib> // getenv
25
26 #include <errno.h>
27 #include <dirent.h>
28
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h> // geteuid, ...
33
34 #include <linux/cdrom.h>
35
36 /*
37 ** verify devices names as late as possible (while attach)
38 */
39 #define  DELAYED_VERIFY          1
40
41 /*
42 ** try umount of foreign (user/automounter) media on eject
43 **   0 = don't force, 1 = automounted only, 2 == all
44 */
45 #define  FORCE_RELEASE_FOREIGN   2
46
47 /*
48 ** Reuse foreign (user/automounter) mount points.
49 ** 0 = don't use, 1 = automounted only, 2 = all
50 */
51 #define  REUSE_FOREIGN_MOUNTS    2
52
53 /*
54 ** if to throw exception on eject errors or ignore them
55 */
56 #define  REPORT_EJECT_ERRORS     1
57
58 /*
59 ** If defined to the full path of the eject utility,
60 ** it will be used additionally to the eject-ioctl.
61 */
62 #define EJECT_TOOL_PATH "/bin/eject"
63
64
65 using namespace std;
66
67 namespace zypp {
68   namespace media {
69
70     namespace {
71
72       bool isNewDevice(const std::list<MediaSource> &devices,
73                        const MediaSource            &media)
74       {
75         std::list<MediaSource>::const_iterator d( devices.begin());
76         for( ; d != devices.end(); ++d)
77         {
78           if( media.equals( *d))
79             return false;
80         }
81         return true;
82       }
83
84       inline Pathname get_sysfs_path()
85       {
86         Pathname sysfs_path;
87         if(::getuid() == ::geteuid() && ::getgid() == ::getegid())
88         {
89           const char *env = ::getenv("SYSFS_PATH");
90           if( env && *env)
91           {
92             sysfs_path = env;
93             if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
94               return sysfs_path;
95           }
96         }
97         sysfs_path = "/sys";
98         if( PathInfo(sysfs_path, PathInfo::LSTAT).isDir())
99           return sysfs_path;
100         else
101           return Pathname();
102       }
103
104     }
105
106
107 ///////////////////////////////////////////////////////////////////
108 //
109 //      CLASS NAME : MediaCD
110 //
111 ///////////////////////////////////////////////////////////////////
112
113     ///////////////////////////////////////////////////////////////////
114     //
115     //
116     //  METHOD NAME : MediaCD::MediaCD
117     //  METHOD TYPE : Constructor
118     //
119     //  DESCRIPTION :
120     //
121     MediaCD::MediaCD( const Url &      url_r,
122                   const Pathname & attach_point_hint_r )
123       : MediaHandler( url_r, attach_point_hint_r,
124                     url_r.getPathName(), // urlpath below attachpoint
125                     false )
126       //, does_download
127       , _lastdev(-1)
128     {
129       MIL << "MediaCD::MediaCD(" << url_r << ", "
130           << attach_point_hint_r << ")" << endl;
131
132       if( url_r.getScheme() != "dvd" && url_r.getScheme() != "cd")
133       {
134         ERR << "Unsupported schema in the Url: " << url_r.asString()
135                                                  << std::endl;
136         ZYPP_THROW(MediaUnsupportedUrlSchemeException(_url));
137       }
138
139 #if !DELAYED_VERIFY
140       DeviceList detected( detectDevices(
141         url_r.getScheme() == "dvd" ? true : false
142       ));
143 #endif
144
145       string devices = _url.getQueryParam("devices");
146       if (!devices.empty())
147       {
148         string::size_type pos;
149         DBG << "parse " << devices << endl;
150         while(!devices.empty())
151         {
152             pos = devices.find(',');
153             string device = devices.substr(0,pos);
154             if (!device.empty())
155             {
156 #if DELAYED_VERIFY
157               MediaSource media("cdrom", device, 0, 0);
158               _devices.push_back( media);
159                DBG << "use device (delayed verify)" << device << endl;
160 #else
161               bool is_ok = false;
162               PathInfo dinfo(device);
163               if( dinfo.isBlk())
164               {
165                 MediaSource media("cdrom", device, dinfo.major(),
166                                                    dinfo.minor());
167                 DeviceList::const_iterator d( detected.begin());
168                 for( ; d != detected.end(); ++d)
169                 {
170                   if( media.equals( *d))
171                   {
172                     is_ok = true;
173                     _devices.push_back( *d);
174                     DBG << "use device " << device << endl;
175                   }
176                 }
177               }
178
179               if( !is_ok)
180               {
181                 ERR << "Device " << device << " is not acceptable "
182                     << "for " << _url.getScheme() << std::endl;
183                 ZYPP_THROW(MediaBadUrlException(_url,
184                   "Invalid device name in URL devices argument"
185                 ));
186               }
187 #endif
188             }
189             if (pos!=string::npos)
190                 devices=devices.substr(pos+1);
191             else
192                 devices.erase();
193         }
194       }
195       else
196       {
197 #if DELAYED_VERIFY
198         DBG << "going to use on-demand device list" << endl;
199         return;
200 #else
201         DBG << "going to use default device list" << endl;
202         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
203         string device( "/dev/cdrom" );
204         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
205           device = "/dev/dvd";
206         }
207
208         PathInfo dinfo(device);
209         if( dinfo.isBlk())
210         {
211           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
212
213           DeviceList::const_iterator d( detected.begin());
214           for( ; d != detected.end(); ++d)
215           {
216             // /dev/cdrom or /dev/dvd to the front
217             if( media.equals( *d))
218               _devices.push_front( *d);
219             else
220               _devices.push_back( *d);
221           }
222         }
223         else
224         {
225           // no /dev/cdrom or /dev/dvd link
226           _devices = detected;
227         }
228 #endif
229       }
230
231       if( _devices.empty())
232       {
233         ERR << "Unable to find any cdrom drive for " << _url.asString()
234                                                      << std::endl;
235         ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
236       }
237     }
238
239     ///////////////////////////////////////////////////////////////////
240     //
241     //
242     //  METHOD NAME : MediaCD::openTray
243     //  METHOD TYPE : bool
244     //
245     bool MediaCD::openTray( const std::string & device_r )
246     {
247       int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
248       int res = -1;
249
250       if ( fd != -1)
251       {
252         res = ::ioctl( fd, CDROMEJECT );
253         ::close( fd );
254       }
255
256       if ( res )
257       {
258         if( fd == -1)
259         {
260           WAR << "Unable to open '" << device_r
261               << "' (" << ::strerror( errno ) << ")" << endl;
262         }
263         else
264         {
265           WAR << "Eject " << device_r
266               << " failed (" << ::strerror( errno ) << ")" << endl;
267         }
268
269 #if defined(EJECT_TOOL_PATH)
270         DBG << "Try to eject " << device_r << " using "
271             << EJECT_TOOL_PATH << " utility" << std::endl;
272
273         const char *cmd[3];
274         cmd[0] = EJECT_TOOL_PATH;
275         cmd[1] = device_r.c_str();
276         cmd[2] = NULL;
277         ExternalProgram eject(cmd, ExternalProgram::Stderr_To_Stdout);
278
279         for(std::string out( eject.receiveLine());
280             out.length(); out = eject.receiveLine())
281         {
282           DBG << " " << out;
283         }
284
285         if(eject.close() != 0)
286         {
287           WAR << "Eject of " << device_r << " failed." << std::endl;
288           return false;
289         }
290 #else
291         return false;
292 #endif
293       }
294       MIL << "Eject of " << device_r << " successful." << endl;
295       return true;
296     }
297
298     ///////////////////////////////////////////////////////////////////
299     //
300     //
301     //  METHOD NAME : MediaCD::closeTray
302     //  METHOD TYPE : bool
303     //
304     bool MediaCD::closeTray( const std::string & device_r )
305     {
306       int fd = ::open( device_r.c_str(), O_RDONLY|O_NONBLOCK );
307       if ( fd == -1 ) {
308         WAR << "Unable to open '" << device_r << "' (" << ::strerror( errno ) << ")" << endl;
309         return false;
310       }
311       int res = ::ioctl( fd, CDROMCLOSETRAY );
312       ::close( fd );
313       if ( res ) {
314         WAR << "Close tray " << device_r << " failed (" << ::strerror( errno ) << ")" << endl;
315         return false;
316       }
317       DBG << "Close tray " << device_r << endl;
318       return true;
319     }
320
321     ///////////////////////////////////////////////////////////////////
322     //
323     //
324     //  METHOD NAME : MediaCD::detectDevices
325     //  METHOD TYPE : MediaCD::DeviceList
326     //
327     MediaCD::DeviceList
328     MediaCD::detectDevices(bool supportingDVD)
329     {
330       using namespace zypp::target::hal;
331
332       DeviceList detected;
333       try
334       {
335         HalContext hal(true);
336
337         std::vector<std::string> drv_udis;
338         drv_udis = hal.findDevicesByCapability("storage.cdrom");
339
340         DBG << "Found " << drv_udis.size() << " cdrom drive udis" << std::endl;
341         for(size_t d = 0; d < drv_udis.size(); d++)
342         {
343           HalDrive drv( hal.getDriveFromUDI( drv_udis[d]));
344
345           if( drv)
346           {
347             bool supportsDVD=false;
348             if( supportingDVD)
349             {
350               std::vector<std::string> caps;
351               try {
352                 caps = drv.getCdromCapabilityNames();
353               }
354               catch(const HalException &e)
355               {
356                 ZYPP_CAUGHT(e);
357               }
358
359               std::vector<std::string>::const_iterator ci;
360               for( ci=caps.begin(); ci != caps.end(); ++ci)
361               {
362                 if( *ci == "dvd")
363                   supportsDVD = true;
364               }
365             }
366
367             MediaSource media("cdrom", drv.getDeviceFile(),
368                                        drv.getDeviceMajor(),
369                                        drv.getDeviceMinor());
370             DBG << "Found " << drv_udis[d] << ": "
371                             << media.asString() << std::endl;
372             if( supportingDVD && supportsDVD)
373             {
374               detected.push_front(media);
375             }
376             else
377             {
378               detected.push_back(media);
379             }
380           }
381         }
382       }
383       catch(const zypp::target::hal::HalException &e)
384       {
385         ZYPP_CAUGHT(e);
386       }
387
388       //
389       // Bug #163971
390       // Hal does not include SCSI / Virtual CDROMs on iSeries ...
391       //
392       // Hmm... always? We can't detect DVD here.
393       if( detected.empty())
394       {
395         Pathname    sysfs_path( get_sysfs_path());
396         if(sysfs_path.empty())
397           return detected;
398
399         std::string sys_name;
400         std::string dev_name;
401
402         // SCSI cdrom devices (/dev/sr0, ...)
403         sys_name = sysfs_path.cat("block/sr").asString();
404         dev_name = "/dev/sr";
405         DBG << "Collecting SCSI CD-ROM devices ("
406             << dev_name << "X)" << std::endl;
407         for(size_t i=0; i < 16; i++)
408         {
409           PathInfo sys_info(sys_name + str::numstring(i));
410           PathInfo dev_info(dev_name + str::numstring(i));
411           if( sys_info.isDir() && dev_info.isBlk())
412           {
413             // Hmm.. how to check if it supports DVDs?
414             MediaSource media("cdrom", dev_info.asString(),
415                                        dev_info.major(),
416                                        dev_info.minor());
417             if( isNewDevice(detected, media))
418             {
419               DBG << "Found SCSI CDROM "
420                   << media.asString()
421                   << std::endl;
422               detected.push_back(media);
423             }
424           }
425         }
426
427         // IBM iSeries virtual CD-ROM devices (how many?)
428 #if powerpc
429         sys_name = sysfs_path.cat("block/iseries!vcd").asString();
430         dev_name = "/dev/iseries/vcd";
431         DBG << "Collecting iSeries virtual CD-ROM devices ("
432             << dev_name << "X)" << std::endl;
433         for(size_t i=0; i < 8; i++)
434         {
435           char drive_letter = 'a' + i;
436           PathInfo sys_info(sys_name + drive_letter);
437           PathInfo dev_info(dev_name + drive_letter);
438           if( sys_info.isDir() && dev_info.isBlk())
439           {
440             // Hmm.. how to check if it supports DVDs?
441             MediaSource media("cdrom", dev_info.asString(),
442                                        dev_info.major(),
443                                        dev_info.minor());
444             if( isNewDevice(detected, media))
445             {
446               DBG << "Found iSeries virtual CDROM "
447                   << media.asString()
448                   << std::endl;
449               detected.push_back(media);
450             }
451           }
452         }
453 #endif // powerpc
454
455         // Other device types?
456       }
457       return detected;
458     }
459
460
461     ///////////////////////////////////////////////////////////////////
462     //
463     //
464     //  METHOD NAME : MediaCD::attachTo
465     //  METHOD TYPE : PMError
466     //
467     //  DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
468     //
469     void MediaCD::attachTo(bool next)
470     {
471       DBG << "next " << next << " last " << _lastdev << endl;
472       if (next && _lastdev == -1)
473         ZYPP_THROW(MediaNotSupportedException(url()));
474
475 #if DELAYED_VERIFY
476       DeviceList detected( detectDevices(
477         _url.getScheme() == "dvd" ? true : false
478       ));
479
480       if(_devices.empty())
481       {
482         DBG << "creating on-demand device list" << endl;
483         //default is /dev/cdrom; for dvd: /dev/dvd if it exists
484         string device( "/dev/cdrom" );
485         if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
486           device = "/dev/dvd";
487         }
488
489         PathInfo dinfo(device);
490         if( dinfo.isBlk())
491         {
492           MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
493
494           DeviceList::const_iterator d( detected.begin());
495           for( ; d != detected.end(); ++d)
496           {
497             // /dev/cdrom or /dev/dvd to the front
498             if( media.equals( *d))
499               _devices.push_front( *d);
500             else
501               _devices.push_back( *d);
502           }
503         }
504         else
505         {
506           // no /dev/cdrom or /dev/dvd link
507           _devices = detected;
508         }
509       }
510 #endif
511
512       Mount mount;
513       string mountpoint = attachPoint().asString();
514       bool mountsucceeded = false;
515       int count = 0;
516       MediaMountException merr;
517
518       string options = _url.getQueryParam("mountoptions");
519       if (options.empty())
520       {
521         options="ro";
522       }
523
524       //TODO: make configurable
525       list<string> filesystems;
526
527       // if DVD, try UDF filesystem before iso9660
528       if ( _url.getScheme() == "dvd" )
529         filesystems.push_back("udf");
530
531       filesystems.push_back("iso9660");
532
533       // try all devices in sequence
534       for (DeviceList::iterator it = _devices.begin()
535         ; !mountsucceeded && it != _devices.end()
536         ; ++it, count++ )
537       {
538         DBG << "count " << count << endl;
539         if (next && count<=_lastdev )
540         {
541                 DBG << "skipping device " << it->name << endl;
542                 continue;
543         }
544 #if DELAYED_VERIFY
545         MediaSource temp( *it);
546         bool        valid=false;
547         PathInfo    dinfo(temp.name);
548         if( dinfo.isBlk())
549         {
550           temp.maj_nr = dinfo.major();
551           temp.min_nr = dinfo.minor();
552
553           DeviceList::const_iterator d( detected.begin());
554           for( ; d != detected.end(); ++d)
555           {
556             if( temp.equals( *d))
557             {
558               valid = true;
559               break;
560             }
561           }
562         }
563         if( !valid)
564         {
565                 DBG << "skipping invalid device: " << it->name << endl;
566                 continue;
567         }
568         MediaSourceRef media( new MediaSource(temp));
569 #else
570         MediaSourceRef media( new MediaSource( *it));
571 #endif
572
573         AttachedMedia ret( findAttachedMedia( media));
574
575         if( ret.mediaSource && ret.attachPoint &&
576            !ret.attachPoint->empty())
577         {
578           DBG << "Using a shared media "
579               << ret.mediaSource->name
580               << " attached on "
581               << ret.attachPoint->path
582               << endl;
583           removeAttachPoint();
584           setAttachPoint(ret.attachPoint);
585           setMediaSource(ret.mediaSource);
586           _lastdev = count;
587           mountsucceeded = true;
588           break;
589         }
590
591 #if REUSE_FOREIGN_MOUNTS > 0
592         {
593           MediaManager  manager;
594           MountEntries  entries( manager.getMountEntries());
595           MountEntries::const_iterator e;
596           for( e = entries.begin(); e != entries.end(); ++e)
597           {
598             bool        is_device = false;
599             std::string dev_path(Pathname(e->src).asString());
600             PathInfo    dev_info;
601
602             if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
603                 dev_info(e->src) && dev_info.isBlk())
604             {
605               is_device = true;
606             }
607
608             if( is_device && media->maj_nr == dev_info.major() &&
609                              media->min_nr == dev_info.minor())
610             {
611               AttachPointRef ap( new AttachPoint(e->dir, false));
612               AttachedMedia  am( media, ap);
613               //
614               // 1 = automounted only, 2 == all
615               //
616 #if REUSE_FOREIGN_MOUNTS == 1
617               if( isAutoMountedMedia(am))
618 #endif
619               {
620                 DBG << "Using a system mounted media "
621                     << media->name
622                     << " attached on "
623                     << ap->path
624                     << endl;
625
626                 media->iown = false; // mark attachment as foreign
627
628                 setMediaSource(media);
629                 setAttachPoint(ap);
630                 _lastdev = count;
631                 mountsucceeded = true;
632                 break;
633               }
634             }
635           }
636           if( mountsucceeded)
637             break;
638         }
639 #endif  // REUSE_FOREIGN_MOUNTS
640
641         // close tray
642         closeTray( it->name );
643
644         // try all filesystems in sequence
645         for(list<string>::iterator fsit = filesystems.begin()
646             ; !mountsucceeded && fsit != filesystems.end()
647             ; ++fsit)
648         {
649           try {
650             if( !isUseableAttachPoint(Pathname(mountpoint)))
651             {
652               mountpoint = createAttachPoint().asString();
653               setAttachPoint( mountpoint, true);
654               if( mountpoint.empty())
655               {
656                 ZYPP_THROW( MediaBadAttachPointException(url()));
657               }
658             }
659
660             mount.mount(it->name, mountpoint, *fsit, options);
661
662             setMediaSource(media);
663
664             // wait for /etc/mtab update ...
665             // (shouldn't be needed)
666             int limit = 5;
667             while( !(mountsucceeded=isAttached()) && --limit)
668             {
669               sleep(1);
670             }
671
672             if( mountsucceeded)
673             {
674               _lastdev = count;
675             }
676             else
677             {
678               setMediaSource(MediaSourceRef());
679               try
680               {
681                 mount.umount(attachPoint().asString());
682               }
683               catch (const MediaException & excpt_r)
684               {
685                 ZYPP_CAUGHT(excpt_r);
686               }
687               ZYPP_THROW(MediaMountException(
688                 "Unable to verify that the media was mounted",
689                 it->name, mountpoint
690               ));
691             }
692           }
693           catch (const MediaMountException &e)
694           {
695             merr = e;
696             removeAttachPoint();
697             ZYPP_CAUGHT(e);
698           }
699           catch (const MediaException & excpt_r)
700           {
701             removeAttachPoint();
702             ZYPP_CAUGHT(excpt_r);
703           }
704         }
705       }
706
707       if (!mountsucceeded)
708       {
709         _lastdev = -1;
710
711         if( !merr.mountOutput().empty())
712         {
713           ZYPP_THROW(MediaMountException(merr.mountError(),
714                                          _url.asString(),
715                                          mountpoint,
716                                          merr.mountOutput()));
717         }
718         else
719         {
720           ZYPP_THROW(MediaMountException("Mounting media failed",
721                                          _url.asString(), mountpoint));
722         }
723       }
724       DBG << _lastdev << " " << count << endl;
725     }
726
727
728     ///////////////////////////////////////////////////////////////////
729     //
730     //
731     //  METHOD NAME : MediaCD::releaseFrom
732     //  METHOD TYPE : PMError
733     //
734     //  DESCRIPTION : Asserted that media is attached.
735     //
736     void MediaCD::releaseFrom( bool eject )
737     {
738       Mount mount;
739       try {
740         AttachedMedia am( attachedMedia());
741         if(am.mediaSource && am.mediaSource->iown)
742           mount.umount(am.attachPoint->path.asString());
743       }
744       catch (const Exception & excpt_r)
745       {
746         ZYPP_CAUGHT(excpt_r);
747         if (eject)
748         {
749 #if FORCE_RELEASE_FOREIGN > 0
750           /* 1 = automounted only, 2 = all */
751           forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
752 #endif
753           if(openTray( mediaSourceName()))
754             return;
755         }
756         ZYPP_RETHROW(excpt_r);
757       }
758
759       // eject device
760       if (eject)
761       {
762 #if FORCE_RELEASE_FOREIGN > 0
763         /* 1 = automounted only, 2 = all */
764         forceRelaseAllMedia(false, FORCE_RELEASE_FOREIGN == 1);
765 #endif
766         if( !openTray( mediaSourceName() ))
767         {
768 #if REPORT_EJECT_ERRORS
769           ZYPP_THROW(MediaNotEjectedException(mediaSourceName()));
770 #endif
771         }
772       }
773     }
774
775     ///////////////////////////////////////////////////////////////////
776     //
777     //
778     //  METHOD NAME : MediaCD::forceEject
779     //  METHOD TYPE : void
780     //
781     // Asserted that media is not attached.
782     //
783     void MediaCD::forceEject()
784     {
785       bool ejected=false;
786       if ( !isAttached()) {     // no device mounted in this instance
787 #if DELAYED_VERIFY
788         DeviceList detected( detectDevices(
789           _url.getScheme() == "dvd" ? true : false
790         ));
791
792         if(_devices.empty())
793         {
794           DBG << "creating on-demand device list" << endl;
795           //default is /dev/cdrom; for dvd: /dev/dvd if it exists
796           string device( "/dev/cdrom" );
797           if ( _url.getScheme() == "dvd" && PathInfo( "/dev/dvd" ).isBlk() ) {
798            device = "/dev/dvd";
799           }
800
801           PathInfo dinfo(device);
802           if( dinfo.isBlk())
803           {
804             MediaSource media("cdrom", device, dinfo.major(), dinfo.minor());
805
806             DeviceList::const_iterator d( detected.begin());
807             for( ; d != detected.end(); ++d)
808             {
809               // /dev/cdrom or /dev/dvd to the front
810               if( media.equals( *d))
811                 _devices.push_front( *d);
812               else
813                 _devices.push_back( *d);
814             }
815           }
816           else
817           {
818             // no /dev/cdrom or /dev/dvd link
819             _devices = detected;
820           }
821         }
822 #endif
823
824         DeviceList::iterator it;
825         for( it = _devices.begin(); it != _devices.end(); ++it ) {
826           MediaSourceRef media( new MediaSource( *it));
827 #if DELAYED_VERIFY
828           bool        valid=false;
829           PathInfo    dinfo(media->name);
830           if( dinfo.isBlk())
831           {
832             media->maj_nr = dinfo.major();
833             media->min_nr = dinfo.minor();
834
835             DeviceList::const_iterator d( detected.begin());
836             for( ; d != detected.end(); ++d)
837             {
838               if( media->equals( *d))
839               {
840                 valid = true;
841                 break;
842               }
843             }
844           }
845           if( !valid)
846           {
847             DBG << "skipping invalid device: " << it->name << endl;
848             continue;
849           }
850 #endif
851
852           // FIXME: we have also to check if it is mounted in the system
853           AttachedMedia ret( findAttachedMedia( media));
854           if( !ret.mediaSource)
855           {
856 #if FORCE_RELEASE_FOREIGN > 0
857             /* 1 = automounted only, 2 = all */
858             forceRelaseAllMedia(media, false, FORCE_RELEASE_FOREIGN == 1);
859 #endif
860             if ( openTray( it->name ) )
861             {
862               ejected = true;
863               break; // on 1st success
864             }
865           }
866         }
867       }
868       if( !ejected)
869       {
870 #if REPORT_EJECT_ERRORS
871         ZYPP_THROW(MediaNotEjectedException());
872 #endif
873       }
874     }
875
876     bool MediaCD::isAutoMountedMedia(const AttachedMedia &media)
877     {
878       bool is_automounted = false;
879       if( media.mediaSource && !media.mediaSource->name.empty())
880       {
881         using namespace zypp::target::hal;
882
883         try
884         {
885           HalContext hal(true);
886
887           HalVolume vol = hal.getVolumeFromDeviceFile(media.mediaSource->name);
888           if( vol)
889           {
890             std::string udi = vol.getUDI();
891             std::string key;
892             std::string mnt;
893
894             try
895             {
896               key = "info.hal_mount.created_mount_point";
897               mnt = hal.getDevicePropertyString(udi, key);
898
899               if(media.attachPoint->path == mnt)
900                 is_automounted = true;
901             }
902             catch(const HalException &e1)
903             {
904               ZYPP_CAUGHT(e1);
905
906               try
907               {
908                 key = "volume.mount_point";
909                 mnt = hal.getDevicePropertyString(udi, key);
910
911                 if(media.attachPoint->path == mnt)
912                   is_automounted = true;
913               }
914               catch(const HalException &e2)
915               {
916                 ZYPP_CAUGHT(e2);
917               }
918             }
919           }
920         }
921         catch(const HalException &e)
922         {
923           ZYPP_CAUGHT(e);
924         }
925       }
926       DBG << "Media "       << media.mediaSource->asString()
927           << " attached on " << media.attachPoint->path
928           << " is"           << (is_automounted ? "" : " not")
929           << " automounted"  << std::endl;
930       return is_automounted;
931     }
932
933     ///////////////////////////////////////////////////////////////////
934     //
935     //  METHOD NAME : MediaCD::isAttached
936     //  METHOD TYPE : bool
937     //
938     //  DESCRIPTION : Override check if media is attached.
939     //
940     bool
941     MediaCD::isAttached() const
942     {
943       return checkAttached(false);
944     }
945
946     ///////////////////////////////////////////////////////////////////
947     //
948     //  METHOD NAME : MediaCD::getFile
949     //  METHOD TYPE : PMError
950     //
951     //  DESCRIPTION : Asserted that media is attached.
952     //
953     void MediaCD::getFile( const Pathname & filename ) const
954     {
955       MediaHandler::getFile( filename );
956     }
957
958     ///////////////////////////////////////////////////////////////////
959     //
960     //  METHOD NAME : MediaCD::getDir
961     //  METHOD TYPE : PMError
962     //
963     //  DESCRIPTION : Asserted that media is attached.
964     //
965     void MediaCD::getDir( const Pathname & dirname, bool recurse_r ) const
966     {
967       MediaHandler::getDir( dirname, recurse_r );
968     }
969
970     ///////////////////////////////////////////////////////////////////
971     //
972     //
973     //  METHOD NAME : MediaCD::getDirInfo
974     //  METHOD TYPE : PMError
975     //
976     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
977     //
978     void MediaCD::getDirInfo( std::list<std::string> & retlist,
979                               const Pathname & dirname, bool dots ) const
980     {
981       MediaHandler::getDirInfo( retlist, dirname, dots );
982     }
983
984     ///////////////////////////////////////////////////////////////////
985     //
986     //
987     //  METHOD NAME : MediaCD::getDirInfo
988     //  METHOD TYPE : PMError
989     //
990     //  DESCRIPTION : Asserted that media is attached and retlist is empty.
991     //
992     void MediaCD::getDirInfo( filesystem::DirContent & retlist,
993                               const Pathname & dirname, bool dots ) const
994     {
995       MediaHandler::getDirInfo( retlist, dirname, dots );
996     }
997
998     bool MediaCD::getDoesFileExist( const Pathname & filename ) const
999     {
1000       return MediaHandler::getDoesFileExist( filename );
1001     }
1002
1003   } // namespace media
1004 } // namespace zypp
1005 // vim: set ts=8 sts=2 sw=2 ai noet: