summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2001-08-09 00:03:13 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2001-08-09 00:03:13 +0000
commitcd7ff4d11cc513cd3bf9cc03ae43734fae3e4421 (patch)
tree8dac2fe0ddb52317cd89dd323205b592494b9be3
parent04583b13c583bba9f63564b3473f69d9b76bbb7f (diff)
Add -h flag to prevent following a symlink to a dir as the dest.
Also add -n as an alias for -h for compat with GNU ln. Patch from Phil.Pennock@globnix.org with minor changes by me.
-rw-r--r--bin/ln/ln.130
-rw-r--r--bin/ln/ln.c22
2 files changed, 44 insertions, 8 deletions
diff --git a/bin/ln/ln.1 b/bin/ln/ln.1
index b111ebba87a..8d4510b5002 100644
--- a/bin/ln/ln.1
+++ b/bin/ln/ln.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ln.1,v 1.10 2000/11/09 17:51:55 aaron Exp $
+.\" $OpenBSD: ln.1,v 1.11 2001/08/09 00:03:12 millert Exp $
.\" $NetBSD: ln.1,v 1.10 1995/07/25 19:37:04 jtc Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
@@ -45,7 +45,7 @@
.Nd make hard and symbolic links to files
.Sh SYNOPSIS
.Nm ln
-.Op Fl fs
+.Op Fl fhns
.Ar source_file
.Op Ar target_file
.Nm ln
@@ -70,6 +70,12 @@ The options are as follows:
.Bl -tag -width Ds
.It Fl f
Unlink any already existing file, permitting the link to occur.
+.It Fl h
+If the target is a symlink to a directory, do not descend into it.
+.It Fl n
+An alias for
+.Fn h
+for compatibility with other operating systems.
.It Fl s
Create a symbolic link.
.El
@@ -152,6 +158,26 @@ This hard link exists so
may be invoked from shell scripts, for example, using the
.Cm "if [ ]"
construct.
+.Pp
+.Cm "mkdir bar baz; ln -s bar foo; ln -shf baz foo"
+.Pp
+The second call to
+.Nm
+removes the original
+.Pa foo
+and creates a replacement pointing to
+.Pa baz .
+Without the
+.Ar -h
+option, this would instead leave
+.Pa foo
+pointing to
+.Pa bar
+and inside
+.Pa foo
+create a new symlink
+.Pa baz
+pointing to itself. This results from directory-walking.
.Sh SEE ALSO
.Xr link 2 ,
.Xr lstat 2 ,
diff --git a/bin/ln/ln.c b/bin/ln/ln.c
index 294d9382e5d..715eede32a6 100644
--- a/bin/ln/ln.c
+++ b/bin/ln/ln.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ln.c,v 1.4 1996/12/14 12:18:01 mickey Exp $ */
+/* $OpenBSD: ln.c,v 1.5 2001/08/09 00:03:12 millert Exp $ */
/* $NetBSD: ln.c,v 1.10 1995/03/21 09:06:10 cgd Exp $ */
/*
@@ -35,16 +35,16 @@
*/
#ifndef lint
-static char copyright[] =
+static const char copyright[] =
"@(#) Copyright (c) 1987, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
-static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94";
+static const char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94";
#else
-static char rcsid[] = "$OpenBSD: ln.c,v 1.4 1996/12/14 12:18:01 mickey Exp $";
+static const char rcsid[] = "$OpenBSD: ln.c,v 1.5 2001/08/09 00:03:12 millert Exp $";
#endif
#endif /* not lint */
@@ -60,6 +60,7 @@ static char rcsid[] = "$OpenBSD: ln.c,v 1.4 1996/12/14 12:18:01 mickey Exp $";
int dirflag; /* Undocumented directory flag. */
int fflag; /* Unlink existing files. */
+int hflag; /* Check new name for symlink first. */
int sflag; /* Symbolic, not hard, link. */
/* System link call. */
int (*linkf) __P((const char *, const char *));
@@ -76,7 +77,7 @@ main(argc, argv)
int ch, exitval;
char *sourcedir;
- while ((ch = getopt(argc, argv, "Ffs")) != -1)
+ while ((ch = getopt(argc, argv, "Ffhns")) != -1)
switch (ch) {
case 'F':
dirflag = 1; /* XXX: deliberately undocumented. */
@@ -84,6 +85,10 @@ main(argc, argv)
case 'f':
fflag = 1;
break;
+ case 'h':
+ case 'n':
+ hflag = 1;
+ break;
case 's':
sflag = 1;
break;
@@ -122,6 +127,7 @@ linkit(target, source, isdir)
{
struct stat sb;
char *p, path[MAXPATHLEN];
+ int (*statf) __P((const char *, struct stat *));
if (!sflag) {
/* If target doesn't exist, quit now. */
@@ -136,6 +142,8 @@ linkit(target, source, isdir)
}
}
+ statf = hflag ? lstat : stat;
+
/* If the source is a directory, append the target's name. */
if (isdir || (!stat(source, &sb) && S_ISDIR(sb.st_mode))) {
if ((p = strrchr(target, '/')) == NULL)
@@ -162,8 +170,10 @@ linkit(target, source, isdir)
void
usage()
{
+ extern char *__progname;
(void)fprintf(stderr,
- "usage:\tln [-fs] file1 file2\n\tln [-fs] file ... directory\n");
+ "usage: %s [-fhns] file1 file2\n\tln [-fhns] file ... directory\n",
+ __progname);
exit(1);
}