Difference between "test -a file" and "test file -ef file"
Asked Answered
I

2

6

QNX (Neutrino 6.5.0) uses an open source implementation of ksh as its shell. A lot of the provided scripts, including the system startup scripts, use constructs such as

if ! test /dev/slog -ef /dev/slog; then
    # do something
fi

to check whether a resource manager exists or not in the filesystem. I've searched and could only find very dray explanations that -ef checks to see whether the two parameters are in fact the same file. Since the filename specified is the same it seems to just reduce to checking that the file exists.

I have checked the behaviour of test -a and test -e (both seem to check for file existance of any type of file according to the various docs I've read) and they seem to also work.

Is there any difference in the checks performed between -ef and -a/-e? Is using -ef some kind of attempt to protect against a race condition in the existence of the file?

Infatuation answered 5/7, 2012 at 13:16 Comment(5)
It seems like it could, indeed, be checking that the file exists for two different stat() calls. Does the /dev entry get removed by the driver/manager (e.g., after being shutdown) only if someone checks for its existence?Store
@jhfrontz: I'm not entirely sure what you mean but (as an example) the /dev/slog pseudo device only gets removed when the driver is killed which would not normally happen in the middle of the call to test since it is part of the initial system startup script. In the normal case of /dev/slog a process can write to the device to log to a file/console/memory, and while it may end up with a different filename, the device exposed in /dev should be the same as before the write to /dev/slog.Infatuation
I'm speculating that stat'ing the device has some side effect (e.g., prompting the driver/manager to do some sort of housekeeping) such that as the first stat() call (from test) is completed, the file/device is removed/replaced by the driver -- thus causing the second stat() to get different information, in turn causing the test to fail. It's been a while since I've used QNX, but the slogger man page suggests there are side effects from interacting with /dev/slog (e.g., unlinking it purges the log).Store
I did some more digging - test -a and test -e are relatively new. At one point, they don't seem to have been part of the Posix shell that was in use by QNX (see qnx.com/developers/docs/qnx_4.25_docs/qnx4/utils/s/sh.html . So I now suspect that this is just a legacy pattern.Store
@jhfrontz: Thanks for your efforts, most informative and useful.Infatuation
A
4

Reviewing the strace on Ubuntu Linux's copy of ksh reveals no substantial differences. One call to stat vs two.

$ strace test /tmp/tmp.geLaoPkXXC -ef /tmp/tmp.geLaoPkXXC

showed this:

mmap(NULL, 7220736, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f11dc80b000
close(3)                                = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
close(1)                                = 0
close(2)                                = 0

...whereas

$  strace test -a /tmp/tmp.geLaoPkXXC

showed this:

fstat(3, {st_mode=S_IFREG|0644, st_size=7220736, ...}) = 0
mmap(NULL, 7220736, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6b49e2b000
close(3)                                = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
close(1)                                = 0
close(2)                                = 0

One stat vs two.

$ ksh --version
  version         sh (AT&T Research) 93u 2011-02-08
Autogamy answered 13/7, 2012 at 3:39 Comment(0)
B
1

We don't know how the code use the stat exactly without code, we need to find the difference via the code.

/* code for -ef */
return (stat (argv[op - 1], &stat_buf) == 0
                  && stat (argv[op + 1], &stat_spare) == 0
                  && stat_buf.st_dev == stat_spare.st_dev
                  && stat_buf.st_ino == stat_spare.st_ino);


/* code for -e/-a */
    case 'a':                   /* file exists in the file system? */
    case 'e':
      return stat (argv[pos - 1], &stat_buf) == 0;

So, if the names are the same and two stat() with the same name will return the same value, then, test -a/-e file is the same as test file -ef file. We know the first condition is true, and we know the second condition is also true from the comments from @tinman

Bowles answered 13/7, 2012 at 15:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.