Bug in ln(1), its manpage, or just misunderstanding?
Alexey Dokuchaev
danfe at nsu.ru
Tue Jan 27 08:57:55 UTC 2015
Hi there,
Per man ln(1), it has -F option which:
-F If the target file already exists and is a directory, then remove
it so that the link may occur. The -F option should be used with
either -f or -i options. If none is specified, -f is implied. The
-F option is a no-op unless -s option is specified.
As I read it correctly, it basically removes empty directory so I can place
a link of the same name there:
$ mkdir foo
$ ln -sF /etc foo # result should be: foo -> /etc
However, in ln.c, static int linkit(const char *source, const char *target,
int isdir) contains:
/*
* If the target is a directory (and not a symlink if hflag),
* append the source's name.
*/
if (isdir ||
(lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
(!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) {
if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) ||
(p = basename(bbuf)) == NULL ||
snprintf(path, sizeof(path), "%s/%s", target, p) >=
...
It seems that this logic should be dependent on -F flag, as otherwise source
name is always appended to target and condition that "target file already
exists and is a directory" is impossible to specify and assess:
$ mkdir foo
$ ln -sF /etc foo # result is "foo/etc -> /etc", not "foo -> /etc"
The code is even more bogus: it silently removes directory (and yet returns
an error), which makes it idempotent:
$ mkdir foo
$ ln -sF / foo ; echo $?
ln: foo//: No such file or directory
1
< no foo at this point >
$ ln -sF / foo ; echo $?
0
< now foo -> / >
$ ln -sF / foo ; echo $?
ln: foo//: Is a directory
1
./danfe
More information about the freebsd-hackers
mailing list