summaryrefslogtreecommitdiffstats
path: root/bin/ln
diff options
context:
space:
mode:
Diffstat (limited to 'bin/ln')
-rw-r--r--bin/ln/ln.115
-rw-r--r--bin/ln/ln.c39
2 files changed, 47 insertions, 7 deletions
diff --git a/bin/ln/ln.1 b/bin/ln/ln.1
index e6ac24a..7ae4ea8 100644
--- a/bin/ln/ln.1
+++ b/bin/ln/ln.1
@@ -32,7 +32,7 @@
.\" @(#)ln.1 8.2 (Berkeley) 12/30/93
.\" $FreeBSD$
.\"
-.Dd February 14, 2006
+.Dd June 6, 2008
.Dt LN 1
.Os
.Sh NAME
@@ -42,13 +42,13 @@
.Sh SYNOPSIS
.Nm
.Op Fl s Op Fl F
-.Op Fl f | i
+.Op Fl f | iw
.Op Fl hnv
.Ar source_file
.Op Ar target_file
.Nm
.Op Fl s Op Fl F
-.Op Fl f | i
+.Op Fl f | iw
.Op Fl hnv
.Ar source_file ...
.Ar target_dir
@@ -79,6 +79,8 @@ then unlink it so that the link may occur.
.Fl f
option overrides any previous
.Fl i
+and
+.Fl w
options.)
.It Fl F
If the target file already exists and is a directory, then remove it
@@ -134,6 +136,8 @@ Create a symbolic link.
Cause
.Nm
to be verbose, showing files as they are processed.
+.It Fl w
+Warn if the source of a symbolic link does not currently exist.
.El
.Pp
By default,
@@ -194,9 +198,10 @@ operation using the two passed arguments.
The
.Fl h ,
.Fl i ,
-.Fl n
-and
+.Fl n ,
.Fl v
+and
+.Fl w
options are non-standard and their use in scripts is not recommended.
They are provided solely for compatibility with other
.Nm
diff --git a/bin/ln/ln.c b/bin/ln/ln.c
index d164c76..45a7cb3 100644
--- a/bin/ln/ln.c
+++ b/bin/ln/ln.c
@@ -58,6 +58,8 @@ int hflag; /* Check new name for symlink first. */
int iflag; /* Interactive mode. */
int sflag; /* Symbolic, not hard, link. */
int vflag; /* Verbose output. */
+int wflag; /* Warn if symlink target does not
+ * exist, and -f is not enabled. */
/* System link call. */
int (*linkf)(const char *, const char *);
char linkch;
@@ -92,7 +94,7 @@ main(int argc, char *argv[])
exit(linkit(argv[0], argv[1], 0));
}
- while ((ch = getopt(argc, argv, "Ffhinsv")) != -1)
+ while ((ch = getopt(argc, argv, "Ffhinsvw")) != -1)
switch (ch) {
case 'F':
Fflag = 1;
@@ -100,6 +102,7 @@ main(int argc, char *argv[])
case 'f':
fflag = 1;
iflag = 0;
+ wflag = 0;
break;
case 'h':
case 'n':
@@ -115,6 +118,9 @@ main(int argc, char *argv[])
case 'v':
vflag = 1;
break;
+ case 'w':
+ wflag = 1;
+ break;
case '?':
default:
usage();
@@ -127,8 +133,10 @@ main(int argc, char *argv[])
linkch = sflag ? '-' : '=';
if (sflag == 0)
Fflag = 0;
- if (Fflag == 1 && iflag == 0)
+ if (Fflag == 1 && iflag == 0) {
fflag = 1;
+ wflag = 0; /* Implied when fflag != 0 */
+ }
switch(argc) {
case 0:
@@ -167,6 +175,7 @@ linkit(const char *source, const char *target, int isdir)
const char *p;
int ch, exists, first;
char path[PATH_MAX];
+ char wbuf[PATH_MAX];
if (!sflag) {
/* If source doesn't exist, quit now. */
@@ -204,6 +213,32 @@ linkit(const char *source, const char *target, int isdir)
exists = !lstat(target, &sb);
/*
+ * If the link source doesn't exist, and a symbolic link was
+ * requested, and -w was specified, give a warning.
+ */
+ if (sflag && wflag) {
+ if (*source == '/') {
+ /* Absolute link source. */
+ if (stat(source, &sb) != 0)
+ warn("warning: %s inaccessible", source);
+ } else {
+ /*
+ * Relative symlink source. Try to construct the
+ * absolute path of the source, by appending `source'
+ * to the parent directory of the target.
+ */
+ p = strrchr(target, '/');
+ if (p != NULL)
+ p++;
+ else
+ p = target;
+ (void)snprintf(wbuf, sizeof(wbuf), "%.*s%s",
+ (p - target), target, source);
+ if (stat(wbuf, &sb) != 0)
+ warn("warning: %s", source);
+ }
+ }
+ /*
* If the file exists, then unlink it forcibly if -f was specified
* and interactively if -i was specified.
*/
OpenPOWER on IntegriCloud