ADD: Detect disk devices via UDev

This commit is contained in:
Alexander Koblov 2014-03-15 15:02:10 +00:00
commit 2fa2fe214f
3 changed files with 611 additions and 8 deletions

View file

@ -57,7 +57,7 @@ uses
, BSD, BaseUnix, StrUtils, FileUtil
{$ENDIF}
{$IFDEF LINUX}
, uUDisks, uMountWatcher, DCStrUtils, uOSUtils, FileUtil
, uUDisks, uUDev, uMountWatcher, DCStrUtils, uOSUtils, FileUtil
{$ENDIF}
{$ENDIF}
{$IFDEF MSWINDOWS}
@ -231,7 +231,12 @@ begin
end
else
begin
DCDebug('Detecting devices through /proc/self/mounts');
if HasUdev then
begin
if uUDev.Initialize then
uUDev.AddObserver(@FakeClass.OnUDisksNotify);
end;
DCDebug('Detecting mounts through /proc/self/mounts');
MountWatcher:= TMountWatcher.Create(True);
MountWatcher.OnMountEvent:= @FakeClass.OnMountWatcherNotify;
MountWatcher.Start;
@ -262,6 +267,11 @@ begin
uUDisks.RemoveObserver(@FakeClass.OnUDisksNotify);
uUDisks.Finalize;
IsUDisksAvailable := False;
end
else if HasUdev then
begin
uUDev.RemoveObserver(@FakeClass.OnUDisksNotify);
uUDev.Finalize;
end;
FreeAndNil(MountWatcher);
if Assigned(FakeClass) then
@ -330,10 +340,15 @@ begin
end;
Result := False;
end
else
else if IsUDisksAvailable then
begin
// Devices not supplied, retrieve info from UDisks.
Result := uUDisks.GetDeviceInfo(DeviceObjectPath, DeviceInfo);
end
else
begin
// Devices not supplied, retrieve info from UDev.
Result := uUDev.GetDeviceInfo(DeviceObjectPath, DeviceInfo);
end;
end;
@ -691,7 +706,9 @@ begin
AddedMountPoints := TStringList.Create;
if IsUDisksAvailable then
HaveUDisksDevices := uUDisks.EnumerateDevices(UDisksDevices);
HaveUDisksDevices := uUDisks.EnumerateDevices(UDisksDevices)
else if HasUdev then
HaveUDisksDevices := uUDev.EnumerateDevices(UDisksDevices);
// Storage devices have to be in fstab or mtab and reported by UDisks.
for I:= Low(MntEntFileList) to High(MntEntFileList) do
@ -1064,10 +1081,16 @@ end;
procedure TFakeClass.OnUDisksNotify(Reason: TUDisksMethod; const ObjectPath: UTF8String);
var
Result: Boolean;
ADrive: PDrive = nil;
DeviceInfo: TUDisksDeviceInfo;
begin
if uUDisks.GetDeviceInfo(ObjectPath, DeviceInfo) then
if IsUDisksAvailable = False then
Result:= uUDev.GetDeviceInfo(ObjectPath, DeviceInfo)
else
Result:= uUDisks.GetDeviceInfo(ObjectPath, DeviceInfo);
if Result then
UDisksDeviceToDrive(nil, DeviceInfo, ADrive);
try
case Reason of

579
src/platform/unix/uudev.pas Normal file
View file

@ -0,0 +1,579 @@
{
Double Commander
-------------------------------------------------------------------------
Interface to UDev service via libudev.
Copyright (C) 2014 Alexander Koblov (alexx2000@mail.ru)
Based on udisks-1.0.4/src/device.c
Copyright (C) 2008 David Zeuthen <david@fubar.dk>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
}
unit uUDev;
{$mode delphi}
{$assertions on}
interface
uses
Classes, SysUtils, CTypes, Unix, BaseUnix, uUDisks;
function Initialize: Boolean;
procedure Finalize;
procedure AddObserver(Func: TUDisksDeviceNotify);
procedure RemoveObserver(Func: TUDisksDeviceNotify);
function EnumerateDevices(out DevicesInfos: TUDisksDevicesInfos): Boolean;
function GetDeviceInfo(const ObjectPath: UTF8String; out Info: TUDisksDeviceInfo): Boolean; overload;
var
HasUdev: Boolean = False;
implementation
uses
DynLibs, DCOSUtils, DCStrUtils, uDebug;
type
{ TMonitorThread }
TMonitorThread = class(TThread)
private
FAction: String;
FDevicePath: String;
private
procedure ReceiveDevice;
protected
procedure Execute; override;
end;
type
Pudev = ^Tudev;
Tudev = record end;
Pudev_device = ^Tudev_device;
Tudev_device = record end;
Pudev_monitor = ^Tudev_monitor;
Tudev_monitor = record end;
Pudev_enumerate = ^Tudev_enumerate;
Tudev_enumerate = record end;
Pudev_list_entry = ^Tudev_list_entry;
Tudev_list_entry = record end;
var
// udev — libudev context
udev_new: function(): Pudev; cdecl;
udev_unref: function(udev: Pudev): Pudev; cdecl;
// udev_list — list operation
udev_list_entry_get_next: function(list_entry: Pudev_list_entry): Pudev_list_entry; cdecl;
udev_list_entry_get_name: function(list_entry: Pudev_list_entry): PAnsiChar; cdecl;
// udev_device — kernel sys devices
udev_device_unref: procedure(udev_device: Pudev_device); cdecl;
udev_device_new_from_syspath: function(udev: Pudev; const syspath: PAnsiChar): Pudev_device; cdecl;
udev_device_get_devnode: function(udev_device: Pudev_device): PAnsiChar; cdecl;
udev_device_get_devtype: function(udev_device: Pudev_device): PAnsiChar; cdecl;
udev_device_get_syspath: function(udev_device: Pudev_device): PAnsiChar; cdecl;
udev_device_get_action: function(udev_device: Pudev_device): PAnsiChar; cdecl;
udev_device_get_property_value: function(udev_device: Pudev_device;
const key: PAnsiChar): PAnsiChar; cdecl;
udev_device_get_sysattr_value: function(udev_device: Pudev_device;
const sysattr: PAnsiChar): PAnsiChar; cdecl;
// udev_monitor — device event source
udev_monitor_unref: procedure(udev_monitor: Pudev_monitor); cdecl;
udev_monitor_new_from_netlink: function(udev: Pudev; const name: PAnsiChar): Pudev_monitor; cdecl;
udev_monitor_filter_add_match_subsystem_devtype: function(udev_monitor: Pudev_monitor;
const subsystem: PAnsiChar;
const devtype: PAnsiChar): cint; cdecl;
udev_monitor_enable_receiving: function(udev_monitor: Pudev_monitor): cint; cdecl;
udev_monitor_get_fd: function(udev_monitor: Pudev_monitor): cint; cdecl;
udev_monitor_receive_device: function(udev_monitor: Pudev_monitor): Pudev_device; cdecl;
// udev_enumerate — lookup and sort sys devices
udev_enumerate_new: function(udev: Pudev): Pudev_enumerate; cdecl;
udev_enumerate_unref: function(udev_enumerate: Pudev_enumerate): Pudev_enumerate; cdecl;
udev_enumerate_add_match_subsystem: function(udev_enumerate: Pudev_enumerate;
const subsystem: PAnsiChar): cint; cdecl;
udev_enumerate_scan_devices: function(udev_enumerate: Pudev_enumerate): cint; cdecl;
udev_enumerate_get_list_entry: function(udev_enumerate: Pudev_enumerate): Pudev_list_entry; cdecl;
const
LibraryName = 'libudev.so.%d';
var
udev: Pudev = nil;
libudev: TLibHandle = NilHandle;
udev_monitor: Pudev_monitor = nil;
udev_monitor_thread: TMonitorThread = nil;
observers: TUDisksObserverList = nil;
const
UDEV_DEVICE_TYPE_DISK = 'disk';
UDEV_DEVICE_TYPE_PARTITION = 'partition';
drive_media_mapping: array [0..29, 0..1] of String =
(
( 'ID_DRIVE_FLASH', 'flash' ),
( 'ID_DRIVE_FLASH_CF', 'flash_cf' ),
( 'ID_DRIVE_FLASH_MS', 'flash_ms' ),
( 'ID_DRIVE_FLASH_SM', 'flash_sm' ),
( 'ID_DRIVE_FLASH_SD', 'flash_sd' ),
( 'ID_DRIVE_FLASH_SDHC', 'flash_sdhc' ),
( 'ID_DRIVE_FLASH_MMC', 'flash_mmc' ),
( 'ID_DRIVE_FLOPPY', 'floppy' ),
( 'ID_DRIVE_FLOPPY_ZIP', 'floppy_zip' ),
( 'ID_DRIVE_FLOPPY_JAZ', 'floppy_jaz' ),
( 'ID_CDROM', 'optical_cd' ),
( 'ID_CDROM_CD_R', 'optical_cd_r' ),
( 'ID_CDROM_CD_RW', 'optical_cd_rw' ),
( 'ID_CDROM_DVD', 'optical_dvd' ),
( 'ID_CDROM_DVD_R', 'optical_dvd_r' ),
( 'ID_CDROM_DVD_RW', 'optical_dvd_rw' ),
( 'ID_CDROM_DVD_RAM', 'optical_dvd_ram' ),
( 'ID_CDROM_DVD_PLUS_R', 'optical_dvd_plus_r' ),
( 'ID_CDROM_DVD_PLUS_RW', 'optical_dvd_plus_rw' ),
( 'ID_CDROM_DVD_PLUS_R_DL', 'optical_dvd_plus_r_dl' ),
( 'ID_CDROM_DVD_PLUS_RW_DL', 'optical_dvd_plus_rw_dl' ),
( 'ID_CDROM_BD', 'optical_bd' ),
( 'ID_CDROM_BD_R', 'optical_bd_r' ),
( 'ID_CDROM_BD_RE', 'optical_bd_re' ),
( 'ID_CDROM_HDDVD', 'optical_hddvd' ),
( 'ID_CDROM_HDDVD_R', 'optical_hddvd_r' ),
( 'ID_CDROM_HDDVD_RW', 'optical_hddvd_rw' ),
( 'ID_CDROM_MO', 'optical_mo' ),
( 'ID_CDROM_MRW', 'optical_mrw' ),
( 'ID_CDROM_MRW_W', 'optical_mrw_w' )
);
procedure Print(const sMessage: String);
begin
WriteLn('UDev: ', sMessage);
end;
procedure Load;
var
Version: Integer;
begin
for Version:= 1 downto 0 do
begin
libudev:= LoadLibrary(Format(LibraryName, [Version]));
if libudev <> NilHandle then Break;
end;
HasUdev:= libudev <> NilHandle;
if HasUdev then
try
// udev — libudev context
udev_new:= SafeGetProcAddress(libudev, 'udev_new');
udev_unref:= SafeGetProcAddress(libudev, 'udev_unref');
// udev_list — list operation
udev_list_entry_get_next:= SafeGetProcAddress(libudev, 'udev_list_entry_get_next');
udev_list_entry_get_name:= SafeGetProcAddress(libudev, 'udev_list_entry_get_name');
// udev_device — kernel sys devices
udev_device_unref:= SafeGetProcAddress(libudev, 'udev_device_unref');
udev_device_new_from_syspath:= SafeGetProcAddress(libudev, 'udev_device_new_from_syspath');
udev_device_get_devnode:= SafeGetProcAddress(libudev, 'udev_device_get_devnode');
udev_device_get_devtype:= SafeGetProcAddress(libudev, 'udev_device_get_devtype');
udev_device_get_syspath:= SafeGetProcAddress(libudev, 'udev_device_get_syspath');
udev_device_get_action:= SafeGetProcAddress(libudev, 'udev_device_get_action');
udev_device_get_property_value:= SafeGetProcAddress(libudev, 'udev_device_get_property_value');
udev_device_get_sysattr_value:= SafeGetProcAddress(libudev, 'udev_device_get_sysattr_value');
// udev_monitor — device event source
udev_monitor_new_from_netlink:= SafeGetProcAddress(libudev, 'udev_monitor_new_from_netlink');
udev_monitor_filter_add_match_subsystem_devtype:= SafeGetProcAddress(libudev, 'udev_monitor_filter_add_match_subsystem_devtype');
udev_monitor_enable_receiving:= SafeGetProcAddress(libudev, 'udev_monitor_enable_receiving');
udev_monitor_get_fd:= SafeGetProcAddress(libudev, 'udev_monitor_get_fd');
udev_monitor_receive_device:= SafeGetProcAddress(libudev, 'udev_monitor_receive_device');
// udev_enumerate — lookup and sort sys devices
udev_enumerate_new:= SafeGetProcAddress(libudev, 'udev_enumerate_new');
udev_enumerate_unref:= SafeGetProcAddress(libudev, 'udev_enumerate_unref');
udev_enumerate_add_match_subsystem:= SafeGetProcAddress(libudev, 'udev_enumerate_add_match_subsystem');
udev_enumerate_scan_devices:= SafeGetProcAddress(libudev, 'udev_enumerate_scan_devices');
udev_enumerate_get_list_entry:= SafeGetProcAddress(libudev, 'udev_enumerate_get_list_entry');
// Create the udev object
udev:= udev_new();
if udev = nil then Raise Exception.Create('Can''t create udev');
except
on E: Exception do
begin
HasUdev:= False;
UnloadLibrary(libudev);
Print(E.Message);
end;
end;
end;
procedure Free;
begin
if Assigned(udev) then udev_unref(udev);
if libudev <> NilHandle then UnloadLibrary(libudev);
end;
function GetDeviceProperty(const Device: Pudev_device;
const PropertyName: UTF8String;
out Value: Boolean): Boolean; overload;
var
pacValue: PAnsiChar;
begin
pacValue:= udev_device_get_property_value(Device, PAnsiCHar(PropertyName));
Result:= Assigned(pacValue);
if (Result = False) then
Value:= False
else
Value:= StrToBool(pacValue);
end;
function GetDeviceProperty(const Device: Pudev_device;
const PropertyName: UTF8String;
out Value: UTF8String): Boolean; overload;
var
pacValue: PAnsiChar;
begin
pacValue:= udev_device_get_property_value(Device, PAnsiCHar(PropertyName));
Result:= Assigned(pacValue);
if (Result = False) then
Value:= EmptyStr
else
Value:= StrPas(pacValue);
end;
function GetDeviceAttribute(const Device: Pudev_device;
const AttributeName: UTF8String;
out Value: UTF8String): Boolean; overload;
var
pacValue: PAnsiChar;
begin
pacValue:= udev_device_get_sysattr_value(Device, PAnsiCHar(AttributeName));
Result:= Assigned(pacValue);
if (Result = False) then
Value:= EmptyStr
else
Value:= StrPas(pacValue);
end;
function GetDeviceAttribute(const Device: Pudev_device;
const AttributeName: UTF8String;
out Value: Boolean): Boolean; overload;
var
S: UTF8String;
begin
Result:= GetDeviceAttribute(Device, AttributeName, S);
if Result then Result:= TryStrToBool(S, Value);
end;
function DecodeString(const EncodedString: String): String;
var
Finish: Integer;
Index: Integer = 1;
StartIndex: Integer = 1;
begin
Result:= EmptyStr;
Finish:= Length(EncodedString);
while Index <= Finish - 3 do
begin
if EncodedString[Index] <> '\' then
Inc(Index)
else begin
if EncodedString[Index + 1] <> 'x' then
begin
Print('**** NOTE: malformed encoded string: ' + EncodedString);
Exit(EncodedString);
end;
Result:= Result + Copy(EncodedString, StartIndex, Index - StartIndex)
+ Chr(StrToInt('$' + Copy(EncodedString, Index + 2, 2)));
Index:= Index + 4;
StartIndex:= Index;
end;
end;
Result:= Result + Copy(EncodedString, StartIndex, Finish - StartIndex + 1);
end;
procedure UpdateDriveConnectionInterface(SystemPath: PAnsiChar; var Info: TUDisksDeviceInfo);
var
Path,
Connection: String;
begin
Path:= IncludeTrailingPathDelimiter(SystemPath);
repeat
Connection:= fpReadLink(Path + 'subsystem');
Connection:= ExtractFileName(ExcludeTrailingPathDelimiter(Connection));
if Connection = 'usb' then
begin
// Both the interface and the device will be 'usb'.
// However only the device will have the 'speed' property.
if mbFileExists(Path + 'speed') then
begin
Info.DriveConnectionInterface:= Connection;
Break;
end;
end;
Path:= ExtractFilePath(ExcludeTrailingPathDelimiter(Path));
until (Length(Path) = 0) or (CompareStr(Path, '/sys/devices/') = 0);
end;
procedure GetDeviceInfo(SystemPath: PAnsiChar; Device: Pudev_device; out Info: TUDisksDeviceInfo); overload;
var
I: Integer;
Value: UTF8String;
begin
with Info do
begin
DeviceFile:= udev_device_get_devnode(Device);
DeviceObjectPath:= SystemPath;
GetDeviceProperty(Device, 'ID_BUS', DriveConnectionInterface);
GetDeviceProperty(Device, 'ID_FS_USAGE', IdUsage);
GetDeviceProperty(Device, 'ID_FS_TYPE', IdType);
GetDeviceProperty(Device, 'ID_FS_VERSION', IdVersion);
GetDeviceProperty(Device, 'ID_FS_UUID', IdUuid);
GetDeviceProperty(Device, 'ID_FS_LABEL_ENC', IdLabel);
if Length(IdLabel) > 0 then
IdLabel:= DecodeString(IdLabel)
else
GetDeviceProperty(Device, 'ID_FS_LABEL', IdLabel);
if not GetDeviceProperty(Device, 'ID_DRIVE_EJECTABLE', DriveIsMediaEjectable) then
begin
DriveIsMediaEjectable:= FALSE;
DriveIsMediaEjectable:= DriveIsMediaEjectable or (udev_device_get_property_value(Device, 'ID_CDROM' ) <> nil);
DriveIsMediaEjectable:= DriveIsMediaEjectable or (udev_device_get_property_value(Device, 'ID_DRIVE_FLOPPY_ZIP' ) <> nil);
DriveIsMediaEjectable:= DriveIsMediaEjectable or (udev_device_get_property_value(Device, 'ID_DRIVE_FLOPPY_JAZ' ) <> nil);
end;
GetDeviceProperty(Device, 'UDISKS_SYSTEM_INTERNAL', DeviceIsSystemInternal);
GetDeviceProperty(Device, 'UDISKS_PRESENTATION_HIDE', DevicePresentationHide);
GetDeviceProperty(Device, 'UDISKS_PRESENTATION_NAME', DevicePresentationName);
GetDeviceProperty(Device, 'UDISKS_PRESENTATION_ICON_NAME', DevicePresentationIconName);
GetDeviceProperty(Device, 'UDISKS_AUTOMOUNT_HINT', DeviceAutomountHint);
GetDeviceProperty(Device, 'ID_DRIVE_DETACHABLE', DriveCanDetach);
Value:= udev_device_get_devtype(Device);
DeviceIsDrive:= (Value = UDEV_DEVICE_TYPE_DISK);
DeviceIsPartition:= (Value = UDEV_DEVICE_TYPE_PARTITION);
GetDeviceProperty(Device, 'UDISKS_PARTITION_TABLE', DeviceIsPartitionTable);
if DeviceIsPartition then
begin
GetDeviceProperty(Device, 'UDISKS_PARTITION_SLAVE', PartitionSlave);
end;
GetDeviceAttribute(Device, 'removable', DeviceIsRemovable);
UpdateDriveConnectionInterface(SystemPath, Info);
DeviceIsMediaAvailable:= (Length(IdUsage) > 0) or (Length(IdType) > 0) or
(Length(IdUuid) > 0) or (Length(IdLabel) > 0);
if not DeviceIsMediaAvailable then
begin
GetDeviceProperty(Device, 'ID_CDROM_MEDIA', DeviceIsMediaAvailable);
end;
for I:= Low(drive_media_mapping) to High(drive_media_mapping) do
begin
if Assigned(udev_device_get_property_value(Device, PAnsiChar(drive_media_mapping[I, 0]))) then
begin
SetLength(DriveMediaCompatibility, Length(DriveMediaCompatibility) + 1);
DriveMediaCompatibility[High(DriveMediaCompatibility)]:= drive_media_mapping[I, 1];
end;
end;
{
WriteLn('Device: ', DeviceFile);
WriteLn(' Devtype: ', Value);
WriteLn(' IdType: ', IdType);
WriteLn(' IdLabel: ', IdLabel );
WriteLn(' IdVersion: ', IdVersion );
WriteLn(' IdUsage: ', IdUsage );
WriteLn(' IdUuid: ', IdUuid );
WriteLn(' DriveIsMediaEjectable: ', DriveIsMediaEjectable );
WriteLn(' DeviceIsSystemInternal: ', DeviceIsSystemInternal );
WriteLn(' DeviceIsPartitionTable: ', DeviceIsPartitionTable );
WriteLn(' DevicePresentationHide: ', DevicePresentationHide );
WriteLn(' DevicePresentationName: ', DevicePresentationName );
WriteLn(' DevicePresentationIconName: ', DevicePresentationIconName );
WriteLn(' DeviceAutomountHint: ', DeviceAutomountHint );
WriteLn(' DriveCanDetach: ', DriveCanDetach );
WriteLn(' PartitionSlave: ', PartitionSlave );
WriteLn(' DeviceIsRemovable: ', DeviceIsRemovable );
WriteLn(' DriveConnectionInterface: ', DriveConnectionInterface );
}
end;
end;
function EnumerateDevices(out DevicesInfos: TUDisksDevicesInfos): Boolean;
var
path: PAnsiChar;
device: Pudev_device;
devices: Pudev_list_entry;
enumerate: Pudev_enumerate;
begin
// Create a list of the devices in the 'block' subsystem
enumerate:= udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, 'block');
udev_enumerate_scan_devices(enumerate);
devices:= udev_enumerate_get_list_entry(enumerate);
while devices <> nil do
begin
// Get the filename of the /sys entry for the device
// and create a udev_device object (dev) representing it
path:= udev_list_entry_get_name(devices);
device:= udev_device_new_from_syspath(udev, path);
if Assigned(device) then
begin
SetLength(DevicesInfos, Length(DevicesInfos) + 1);
GetDeviceInfo(path, device, DevicesInfos[High(DevicesInfos)]);
udev_device_unref(Device);
end;
devices:= udev_list_entry_get_next(devices);
end;
// Free the enumerator object
udev_enumerate_unref(enumerate);
Result:= Length(DevicesInfos) > 0;
end;
function GetDeviceInfo(const ObjectPath: UTF8String; out Info: TUDisksDeviceInfo): Boolean;
var
Device: Pudev_device;
begin
Device:= udev_device_new_from_syspath(udev, PAnsiChar(ObjectPath));
Result:= Assigned(Device);
if Result then
begin
GetDeviceInfo(PAnsiChar(ObjectPath), Device, Info);
udev_device_unref(Device);
end;
end;
function Initialize: Boolean;
var
Return: cint;
begin
// Set up a monitor to monitor block devices
udev_monitor:= udev_monitor_new_from_netlink(udev, 'udev');
Result:= Assigned(udev_monitor);
if Result then
try
Return:= udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, 'block', nil);
Assert(Return = 0, 'udev_monitor_filter_add_match_subsystem_devtype');
Return:= udev_monitor_enable_receiving(udev_monitor);
Assert(Return = 0, 'udev_monitor_enable_receiving');
observers:= TUDisksObserverList.Create;
udev_monitor_thread:= TMonitorThread.Create(False);
except
Result:= False;
udev_monitor_unref(udev_monitor);
udev_monitor:= nil;
end;
end;
procedure Finalize;
begin
FreeAndNil(udev_monitor_thread);
FreeAndNil(observers);
udev_monitor_unref(udev_monitor);
end;
procedure AddObserver(Func: TUDisksDeviceNotify);
begin
if Observers.IndexOf(Func) < 0 then
Observers.Add(Func);
end;
procedure RemoveObserver(Func: TUDisksDeviceNotify);
begin
Observers.Remove(Func);
end;
{ TMonitorThread }
procedure TMonitorThread.ReceiveDevice;
var
I: Integer;
Method: TUDisksMethod;
begin
if FAction = 'add' then
Method:= UDisks_DeviceAdded
else if FAction = 'remove' then
Method:= UDisks_DeviceRemoved
else if FAction = 'change' then
Method:= UDisks_DeviceChanged
else
Method:= UDisks_DeviceChanged;
Print('Device ' + FAction + ': ' + FDevicePath);
for I := 0 to Observers.Count - 1 do
Observers[I](Method, FDevicePath);
end;
procedure TMonitorThread.Execute;
var
fds: TFDSet;
fd, ret: cint;
device: Pudev_device;
begin
// Get the file descriptor (fd) for the monitor
// This fd will get passed to select()
fd := udev_monitor_get_fd(udev_monitor);
Print('Begin monitoring');
while not Terminated do
begin
fpFD_ZERO(fds);
fpFD_SET(fd, fds);
// Wait device event
ret:= fpSelect(fd + 1, @fds, nil, nil, 100);
// Check if our file descriptor has received data
if (ret > 0) and (fpFD_ISSET(fd, fds) = 1) then
begin
// Make the call to ReceiveDevice the device
// select() ensured that this will not block
device:= udev_monitor_receive_device(udev_monitor);
if Assigned(device) then
begin
FAction:= udev_device_get_action(device);
FDevicePath:= udev_device_get_syspath(device);
Synchronize(ReceiveDevice);
udev_device_unref(device);
end;
end
else if (ret = -1) then
begin
Print(SysErrorMessage(fpGetErrNo));
Exit;
end;
end; // while
end;
initialization
Load;
finalization
Free;
end.

View file

@ -27,7 +27,7 @@ unit uUDisks;
interface
uses
Classes, SysUtils;
Classes, SysUtils, fgl;
type
TStringArray = array of string;
@ -69,6 +69,8 @@ type
TUDisksDeviceNotify = procedure(Reason: TUDisksMethod; const ObjectPath: UTF8String) of object;
TUDisksObserverList = specialize TFPGList<TUDisksDeviceNotify>;
const
UDisksDevicePathPrefix = '/org/freedesktop/UDisks/devices/';
@ -102,7 +104,7 @@ procedure RemoveObserver(Func: TUDisksDeviceNotify);
implementation
uses
dbus, fgl, ExtCtrls;
dbus, ExtCtrls;
{$IF (FPC_VERSION <= 2) and (FPC_RELEASE <= 4) and (FPC_PATCH <= 2)}
type
@ -119,7 +121,6 @@ procedure dbus_connection_remove_filter (connection: PDBusConnection;
{$ENDIF}
type
TUDisksObserverList = specialize TFPGList<TUDisksDeviceNotify>;
TDummy = class
procedure OnTimer(Sender: TObject);