revised code, making use of
fpAccess() to check we have RW access to each device:
program project1;
uses SysUtils, BaseUnix, TermIO;
var DeviceName:string;
SR:TSearchRec;
FD:longint;
// tios:TermIOS;
n, c, PT:integer;
begin
n:=0;
c:=0;
//if FindFirst('/dev/tty*', faAnyFile , SR) = 0 then // original (only finds tty* devices)
if FindFirst('/sys/class/tty/*', faAnyFile , SR) = 0 then // alternative: should ALSO find any rfcomm*
repeat
DeviceName:=SR.Name;
if (DeviceName<>'.') and (DeviceName<>'..') then // exclude '.' and '..'
if fpAccess('/dev/'+DeviceName, R_OK+W_OK)=0 then // exclude devices we have NO ACCESS to
if FileExists('/sys/class/tty/'+DeviceName+'/device/driver') or // this suffices with FPC prior to 3.20
DirectoryExists('/sys/class/tty/'+DeviceName+'/device/driver') then // from FPC 3.20 onwards we need this instead
begin
if FileExists('/sys/class/tty/'+DeviceName+'/type') then PT:=1 // port type 1 = fixed serial port
else PT:=2; // port type 2 = removable/USB
if PT=1 then
begin
FD:=fpOpen('/dev/'+DeviceName, O_RDWR or O_NONBLOCK or O_NOCTTY);
if FD<0 then PT:=0 else // -1, couldn't open /dev entry -> failure!
begin
if IsATTY(FD)=0 then PT:=0 // IsATTY (and TTYname) use ioctl/TCGETS
else inc(n); // count number of fixed serial ports
// if fpIOCtl(FD,TCGETS,@tios)<>0 then PT:=0 // TCGETS: on success 0 is returned,
// else inc(n); // on error -1 is returned
fpClose(FD)
end
end;
if PT<>0 then inc(c); // count total number of ports
case PT of 1:writeln('* ', DeviceName); // fixed serial port, verified as real
2:writeln(' ', DeviceName) // removable (USB) serial port
end
end
until FindNext(SR) <> 0;
if n<>0 then writeln('(', n, ' fixed devices)');
if c=0 then writeln('no serial ports found');
FindClose(SR)
end.
addendum 25-dec-2025: changed search from "/dev/tty*" to "/sys/class/tty/*". in theory this should now also catch /dev/rfcomm* (serial over bluetooth) devices.cheers,
rob :-)