Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2013-12

cannot read /sys/class/net/eth1/address even as root user on linux

8 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Dennis Poon

I tried to read the mac address in the captioned file path. In terminal, I can simply 'cat' and display the mac address.

In FPC, when I tried to use TFileStream to read it,

   FS := TFileStream.Create('/sys/class/net/eth1/address',
fmOpenRead+fmShareDenyWrite);

it raised "stream read error"

If I tried to use TextFile and readln, it even halted the program.

My question is:
Why 'cat' command can easily display this special file 'address' but TFileStream cannot.

I was told to use this method to get the MAC address of a network card, what other methods are there?

Dennis

Michael Van Canneyt
to Dennis Poon
Dennis Poon wrote 9 lines
I tried to read the mac address in the captioned file path. In terminal, I can simply 'cat' and display the mac address. In FPC, when I tried to use TFileStream to read it, FS := TFileStream.Create('/sys/class/net/eth1/address', fmOpenRead+fmShareDenyWrite); it raised "stream read error"

home: >./t
00:1f:d0:a2:df:c4

home: >cat t.pp
{$mode objfpc}
{$H+}
uses sysutils, classes;
Var
   S : String;
begin
   SetLength(S,100);
   with TFileStream.Create('/sys/class/net/eth1/address', fmOpenRead+fmShareDenyWrite) do
     try
       SetLength(S,Read(S[1],100));
       Writeln(S);
     finally
       free;
     end;
end.

Works fine here. Permission problem on your machine maybe ?

Michael.

Mark Morgan Lloyd
to Dennis Poon: I tried to read the mac address in the captioned file path. In terminal, I can simply…
Dennis Poon wrote 18 lines
I tried to read the mac address in the captioned file path. In terminal, I can simply 'cat' and display the mac address. In FPC, when I tried to use TFileStream to read it, FS := TFileStream.Create('/sys/class/net/eth1/address', fmOpenRead+fmShareDenyWrite); it raised "stream read error" If I tried to use TextFile and readln, it even halted the program. My question is: Why 'cat' command can easily display this special file 'address' but TFileStream cannot. I was told to use this method to get the MAC address of a network card, what other methods are there?

Nothing portable. You can't even use /sys safely without first checking it's there: the filesystem support might not be compiled into the kernel, or the filesystem might not be mounted. One possibility would be looking at /etc/udev/rules.d/z25_persistent-net.rules but again there are serious portability issues here.

You do actually have an eth1 device on your system, don't you? Most if not all of the ones around here start off with eth0.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]
Henry Vermaak
to Dennis Poon: I tried to read the mac address in the captioned file path. In terminal, I can simply…
Dennis Poon wrote 18 lines
I tried to read the mac address in the captioned file path. In terminal, I can simply 'cat' and display the mac address. In FPC, when I tried to use TFileStream to read it, FS := TFileStream.Create('/sys/class/net/eth1/address', fmOpenRead+fmShareDenyWrite); it raised "stream read error" If I tried to use TextFile and readln, it even halted the program. My question is: Why 'cat' command can easily display this special file 'address' but TFileStream cannot. I was told to use this method to get the MAC address of a network card, what other methods are there?

While your method should work if that file actually exists, you probably want to use libudev for enumerating and getting device information from sysfs. libudev will also enable you to get hotplug notification.

Henry

Dennis Poon
to Henry Vermaak
Show quoted text 5 lines
While your method should work if that file actually exists, you probably want to use libudev for enumerating and getting device information from sysfs. libudev will also enable you to get hotplug notification.

For your your reply.
The fact is:
1) my linux distro starts with eth1 not eth0. Strange. I know.
2) my question was, why simply 'cat' works but I cannot read it from fpc usign Tfilestream or readlin(F, S);

Since I don't have time to invest in a portable solution, I am happy already if it works on my particular xubuntu distro.

Dennis

Lukasz Sokol
to Dennis Poon
Dennis Poon wrote 16 lines
> While your method should work if that file actually exists, you > probably want to use libudev for enumerating and getting device > information from sysfs. libudev will also enable you to get > hotplug notification. > > For your your reply. The fact is: 1) my linux distro starts with eth1 not eth0. Strange. I know. 2) my question was, why simply 'cat' works but I cannot read it from fpc usign Tfilestream or readlin(F, S); Since I don't have time to invest in a portable solution, I am happy already if it works on my particular xubuntu distro. Dennis

Try installing strace and use it :

strace <your executable name>

from command line/terminal ?

-L.

Dennis Poon
to Michael Van Canneyt: home: >./t 00:1f:d0:a2:df:c4 home: >cat t.pp {$mode objfpc} {$H+} uses sysutils, classes;…
Michael Van Canneyt wrote 42 lines
On Thu, 5 Dec 2013, Dennis Poon wrote: > I tried to read the mac address in the captioned file path. > In terminal, I can simply 'cat' and display the mac address. > > In FPC, when I tried to use TFileStream to read it, > > FS := TFileStream.Create('/sys/class/net/eth1/address', > fmOpenRead+fmShareDenyWrite); > > it raised "stream read error" home: >./t 00:1f:d0:a2:df:c4 home: >cat t.pp {$mode objfpc} {$H+} uses sysutils, classes; Var S : String; begin SetLength(S,100); with TFileStream.Create('/sys/class/net/eth1/address', fmOpenRead+fmShareDenyWrite) do try SetLength(S,Read(S[1],100)); Writeln(S); finally free; end; end. Works fine here. Permission problem on your machine maybe ? Michael.

So, strange.
I tried again and found that it works if I uses BaseUnix and then call fpRead but not with TFileStream.Read

My interface uses are:

uses
   Classes, SysUtils, DB, iniFiles;
My implementation uses:
uses md5, uStrUtils
   {$IFDEF UNIX}
      ,BaseUnix
   {$ENDIF}
   ;
function GetUnixMac(TheDevice : String) : String;
const
   UnixPath = '/sys/class/net/%s/address';
   var s,
       FileName : String;
       FS : TFilestream;
     Var fHandle : cint;
         len : longint;
         buffer :string[255];
   begin
     result := '';
     FileName := Format(UnixPath,[TheDevice]);
     if FileExists(FileName) then begin
//this fpread will work and give me mac address
         fHandle:=fpOpen(FileName,O_RdOnly);
         If fHandle > 0 then
           try
             len := fpRead (fHandle,buffer[1],255);
             setlength(Buffer,len);
             Log(TheDevice+' Mac:'+buffer);
             result := StringReplace(buffer,#10,';',[rfReplaceAll]);
           finally
             fpClose(fHandle);
           end;
{//strange, the following will raise stream read error
         FS := TFilestream.Create(FileName, fmOpenRead+fmShareDenyWrite );
         try
           if FS.Size > 0 then begin
             SetLength(s, FS.Size);
             FS.ReadBuffer(s[1], FS.Size);
             Log(TheDevice+' Mac:'+S);
             result := StringReplace(s,#10,';',[rfReplaceAll]);
           end;
         finally
           FreeAndNil(FS);
         end;
}
     end;
   end;

Why your machine works but my does not and has to rely on fpRead instead of TFileStream???

Dennis

Michael Van Canneyt
to Dennis Poon
Dennis Poon wrote 16 lines
Michael Van Canneyt wrote: > > > On Thu, 5 Dec 2013, Dennis Poon wrote: > >> I tried to read the mac address in the captioned file path. >> In terminal, I can simply 'cat' and display the mac address. >> >> In FPC, when I tried to use TFileStream to read it, >> >> FS := TFileStream.Create('/sys/class/net/eth1/address', >> fmOpenRead+fmShareDenyWrite); >> >> it raised "stream read error"

The problem is not there.

Show quoted text 6 lines
{//strange, the following will raise stream read error FS := TFilestream.Create(FileName, fmOpenRead+fmShareDenyWrite ); try if FS.Size > 0 then begin SetLength(s, FS.Size); FS.ReadBuffer(s[1], FS.Size);

This is the source of your problem.
ReadBuffer raises an error if LESS THAN FS.Size bytes have been read.

The size *reported* by the linux kernel is 4K, but actually read bytes is only 16 or so.

So, just change this line to
SetLength(S,FS.Read(s[1], FS.Size));

And all will be well. I tested.

Michael.