diff --git a/bin/ln/ln.1 b/bin/ln/ln.1 index e6ac24a9a5e7..7ae4ea8548eb 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 d164c76b3fac..45a7cb3d6e9d 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. */ @@ -203,6 +212,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.