0

I have a perl script that traverses a set of directories and when it hits one of them it blows up with an Invalid Argument and I want to be able to programmatically skip it. I thought I could start by finding out the file type with the file command but it too blows up like this:

$ file /sys/devices/virtual/net/br-ex/speed
/sys/devices/virtual/net/br-ex/speed: ERROR: cannot read `/sys/devices/virtual/net/br-ex/speed' (Invalid argument)

If I print out the mode of the file with the perl or python stat function it tells me 33060 but I'm not sure what all the bits mean and I'm hoping a particular one would tell me not to try to look inside. Any suggestions?

David W.
  • 105,218
  • 39
  • 216
  • 337
Mark J Seger
  • 367
  • 2
  • 12
  • 1
    What happens if you look at that `/sys/devices/virtual/net/br-ex` directory with `ls -l`? What the _permissions_ on that file? I suspect that this is not a real file (much like `/dev/null` isn't a **real** file). I bet you'll see something like `crw-rw-rw` or `brw-rw-rw` which mean it's a special file. – David W. Sep 16 '14 at 16:14
  • `/sys` is a virtual file system that provides hardware information stored by the kernel via the file system. The entries, however, do not correspond to real files. The metadata is misleading, though, as even `stat` reports such files as regular files. – chepner Sep 16 '14 at 16:36
  • It's probably safe to assume that `/sys` is the only name you'll see used for a `sysfs`, and so you can just hard-code your script to ignore it. – chepner Sep 16 '14 at 17:11

2 Answers2

0

To understand the stats number you got, you need to convert the number to octal (in python oct(...)).

Then you'll see that 33060 interprets to 100444. You're interested only in the last three digits (444). The first digit is file owner permissions, the second is group and the third is everyone else.

You can look at each of the numbers (in your case all are 4) as 3 binary bits in this order: read-write-execute.

Since in your case owner, group & other has 4, it is translated (for all of them) to 100 (in binary) which means that only the read bit is on for all three - meaning that all three can only read the file.

As far as file permissions go, you should have been successful reading /sys/devices/virtual/net/br-ex/speed.
There are two reasons for the read to fail:
- Either speed is a directory, (directories require execute permissions to read inside).
- Or it's a special file - which can be tested using the -f flag in perl or bash, or using os.path.isfile(...) in python.


Anyhow, you can use the following links to filter files & directories according to their permissions in the 3 languages you mentioned:

Community
  • 1
  • 1
ArnonZ
  • 3,822
  • 4
  • 32
  • 42
  • I know /sys is a specical file system and I'm trying to read the network interface speeds. Usually this file contains the speed but sometimes if doesn't and I'd like to know before I execute the cat the it's going to fail. I had hoped there might be a way to tell but as was mentioned earlier it's a 'special' file and so the normal rules don't apply. I suppose I could always just 2>/&1 with the cat. It's just that I've never see a cat of a /sys entry fail that way. – Mark J Seger Sep 16 '14 at 17:45
  • I see. You can also check if `cat` returned success code and decide whether to print the result at all, or ignore the warning with `2> /dev/null`. Good luck. – ArnonZ Sep 16 '14 at 17:51
  • Actually it's a little worse than I first reported, so here's some more ugly details. IF you familiar with collectl, this is in it's network discovery code. When a new network shows up, collectl tries to look up its speed in a directory like: /sys/devices/virtual/net/tap5d6261e0-75/speed, which it does a cat of. BUT, if /sys/devices/virtual/net/tap5d6261e0-75/operstate doesn't have a value of 'up' or 'unknown', the cat will blow up and the Invalid Arg goes directly to the terminal and cannot be surpressed with 2>&1. A real mess... – Mark J Seger Sep 17 '14 at 10:58
0

Not related to this particular case, but I hit the same error when I ran it on a malicious ELF (Linux executable) file. In that case it was because the program headers of the ELF was intentionally corrupted. Looking at the source code for file command, this is clear as it checks the ELF headers and bails out with the same error in case the headers are corrupted:

    /*
     * Loop through all the program headers.
     */
    for ( ; num; num--) {
        if (pread(fd, xph_addr, xph_sizeof, off) <
            CAST(ssize_t, xph_sizeof)) {
            file_badread(ms);
            return -1;
        }

TLDR; The file command checks not only the magic bytes, but it also performs other checks to validate a file type.