summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-04-21 09:13:00 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-04-21 09:13:00 +0000
commitcb49cb30fe65d4ee317572f232f7017a8c1fe6a2 (patch)
treee6b55eb3a44ee3e9c4a9c22961f46572725a5c13
parent5ba9d6993063e2398e5763736ba50e0f037abe3e (diff)
downloads6-portable-utils-cb49cb30fe65d4ee317572f232f7017a8c1fe6a2.tar.xz
Add -n to s6-ln; document its nonposixness
-rw-r--r--doc/s6-ln.html25
-rw-r--r--src/skaembutils/s6-ln.c8
2 files changed, 27 insertions, 6 deletions
diff --git a/doc/s6-ln.html b/doc/s6-ln.html
index 3ca0245..1417c35 100644
--- a/doc/s6-ln.html
+++ b/doc/s6-ln.html
@@ -25,7 +25,7 @@
<h2> Interface </h2>
<pre>
- s6-ln [ -s ] [ -f ] [ -L ] [ -P ] <em>old</em> <em>new</em>
+ s6-ln [ -n ] [ -s ] [ -f ] [ -L ] [ -P ] <em>source...</em> <em>target</em>
</pre>
<p>
@@ -33,12 +33,31 @@
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html">ln</a> utility.
</p>
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-s</tt>&nbsp;: create a symbolic link instead of a hard link </li>
+ <li> <tt>-f</tt>&nbsp;: force replacement of an existing <em>target</em> </li>
+ <li> <tt>-L</tt>&nbsp;: link targets of symlinks in <em>source...</em> </li>
+ <li> <tt>-P</tt>&nbsp;: link symlinks in <em>source...</em> themselves </li>
+ <li> <tt>-n</tt>&nbsp;: if <em>target</em> is a symlink to a directory, replace
+it instead of adding a link in the directory </li>
+</ul>
+
<h2> Posixness </h2>
<p>
- s6-ln <strong>is</strong> suitable as a Single Unix
+ s6-ln <strong>would be</strong> suitable as a Single Unix
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html">ln</a>
-program.
+program, except that POSIX mandates that a preexisting <em>target</em> must first
+be <tt>unlink()</tt>ed and then (<tt>sym</tt>)<tt>link()</tt>ed, which prevents
+atomic replacements.
+ <tt>s6-ln</tt> aims to be reliable and allow for atomic replacements, so it
+deviates from POSIX on that point: when <em>target</em> exists and needs to
+be replaced, <tt>s6-ln</tt> first creates a (sym)link to a unique temporary
+name, then <tt>rename()</tt>s the temporary name to <em>target</em>. This
+behaviour makes sure that <em>target</em> is atomically replaced - there's
+no point in time where it does not exist.
</p>
</body>
diff --git a/src/skaembutils/s6-ln.c b/src/skaembutils/s6-ln.c
index 59b85a4..65a650f 100644
--- a/src/skaembutils/s6-ln.c
+++ b/src/skaembutils/s6-ln.c
@@ -19,7 +19,7 @@
#include <skalibs/random.h>
#include <skalibs/skamisc.h>
-#define USAGE "s6-ln [ -s ] [ -f ] [ -L ] [ -P ] src... dest"
+#define USAGE "s6-ln [ -n ] [ -s ] [ -f ] [ -L ] [ -P ] src... dest"
typedef int linkfunc_t (char const *, char const *) ;
typedef linkfunc_t *linkfunc_t_ref ;
@@ -78,15 +78,17 @@ int main (int argc, char const *const *argv)
{
linkfunc_t_ref mylink = &link ; /* default to system behaviour */
ln_t_ref f = &noforce ;
+ int nodir = 0 ;
PROG = "s6-ln" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "sfLP", &l) ;
+ int opt = subgetopt_r(argc, argv, "nsfLP", &l) ;
if (opt == -1) break ;
switch (opt)
{
+ case 'n' : nodir = 1 ; break ;
case 's': mylink = &symlink ; break ;
case 'f': f = &force ; break ;
case 'L': if (mylink != &symlink) mylink = &linkderef ; break ;
@@ -120,7 +122,7 @@ int main (int argc, char const *const *argv)
{
struct stat st ;
- if (stat(argv[1], &st) < 0)
+ if (nodir ? lstat(argv[1], &st) : stat(argv[1], &st) < 0)
{
if (errno != ENOENT) strerr_diefu2sys(111, "stat ", argv[1]) ;
(*f)(argv[0], argv[1], mylink) ;