summaryrefslogtreecommitdiff
path: root/bin/ln
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2013-03-12 06:00:06 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2013-03-12 06:00:06 +0000
commit22d6176c7a5b0d9982db2ad3b4a2e6befb249d3b (patch)
treea21b7f3ff4ae40407fc29238268b11a7ae5ffdfc /bin/ln
parent7832dd65734e7616e36f99c1a4281e4d293cfe03 (diff)
Add support for the -L and -P options.
Based on a patch from Kent R. Spillner (kspillner (at) acm.org) ok jmc@ millert@
Diffstat (limited to 'bin/ln')
-rw-r--r--bin/ln/ln.123
-rw-r--r--bin/ln/ln.c28
2 files changed, 35 insertions, 16 deletions
diff --git a/bin/ln/ln.1 b/bin/ln/ln.1
index 89a2be0f00a..8e72ac88dff 100644
--- a/bin/ln/ln.1
+++ b/bin/ln/ln.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ln.1,v 1.29 2011/03/02 07:47:21 jmc Exp $
+.\" $OpenBSD: ln.1,v 1.30 2013/03/12 06:00:05 guenther Exp $
.\" $NetBSD: ln.1,v 1.10 1995/07/25 19:37:04 jtc Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
@@ -33,7 +33,7 @@
.\"
.\" @(#)ln.1 8.2 (Berkeley) 12/30/93
.\"
-.Dd $Mdocdate: March 2 2011 $
+.Dd $Mdocdate: March 12 2013 $
.Dt LN 1
.Os
.Sh NAME
@@ -41,11 +41,11 @@
.Nd make hard and symbolic links to files
.Sh SYNOPSIS
.Nm ln
-.Op Fl fhns
+.Op Fl fhLnPs
.Ar source
.Op Ar target
.Nm ln
-.Op Fl fs
+.Op Fl fLPs
.Ar source ...\&
.Op Ar directory
.Sh DESCRIPTION
@@ -68,10 +68,23 @@ The options are as follows:
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 L
+When creating a hard link and the source is a symbolic link,
+link to the fully resolved target of the symbolic link.
+This is the default.
+This option cancels the
+.Fl P
+option.
.It Fl n
An alias for
.Fl h
for compatibility with other operating systems.
+.It Fl P
+When creating a hard link and the source is a symbolic link,
+link to the symbolic link itself.
+This option cancels the
+.Fl L
+option.
.It Fl s
Create a symbolic link.
.El
@@ -183,7 +196,7 @@ create a new symlink
pointing to itself.
This results from directory-walking.
.Sh SEE ALSO
-.Xr link 2 ,
+.Xr linkat 2 ,
.Xr lstat 2 ,
.Xr readlink 2 ,
.Xr stat 2 ,
diff --git a/bin/ln/ln.c b/bin/ln/ln.c
index 0b0be08f7a4..c5c40e7c409 100644
--- a/bin/ln/ln.c
+++ b/bin/ln/ln.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ln.c,v 1.18 2009/10/27 23:59:21 deraadt Exp $ */
+/* $OpenBSD: ln.c,v 1.19 2013/03/12 06:00:05 guenther Exp $ */
/* $NetBSD: ln.c,v 1.10 1995/03/21 09:06:10 cgd Exp $ */
/*
@@ -35,6 +35,7 @@
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
@@ -44,9 +45,8 @@
int dirflag; /* Undocumented directory flag. */
int fflag; /* Unlink existing files. */
int hflag; /* Check new name for symlink first. */
+int Pflag; /* Hard link to symlink. */
int sflag; /* Symbolic, not hard, link. */
- /* System link call. */
-int (*linkf)(const char *, const char *);
int linkit(char *, char *, int);
void usage(void) __dead;
@@ -58,7 +58,7 @@ main(int argc, char *argv[])
int ch, exitval;
char *sourcedir;
- while ((ch = getopt(argc, argv, "Ffhns")) != -1)
+ while ((ch = getopt(argc, argv, "FfhLnPs")) != -1)
switch (ch) {
case 'F':
dirflag = 1; /* XXX: deliberately undocumented. */
@@ -70,6 +70,12 @@ main(int argc, char *argv[])
case 'n':
hflag = 1;
break;
+ case 'L':
+ Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
case 's':
sflag = 1;
break;
@@ -80,8 +86,6 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
- linkf = sflag ? symlink : link;
-
switch(argc) {
case 0:
usage();
@@ -118,7 +122,7 @@ linkit(char *target, char *source, int isdir)
if (!sflag) {
/* If target doesn't exist, quit now. */
- if (stat(target, &sb)) {
+ if ((Pflag ? lstat : stat)(target, &sb)) {
warn("%s", target);
return (1);
}
@@ -157,7 +161,7 @@ linkit(char *target, char *source, int isdir)
if (exists && !sflag) {
struct stat tsb;
- if (stat(target, &tsb) != 0) {
+ if ((Pflag ? lstat : stat)(target, &tsb)) {
warn("%s: disappeared", target);
return (1);
}
@@ -177,7 +181,9 @@ linkit(char *target, char *source, int isdir)
* Attempt the link.
*/
if ((fflag && unlink(source) < 0 && errno != ENOENT) ||
- (*linkf)(target, source)) {
+ sflag ? symlink(target, source) :
+ linkat(AT_FDCWD, target, AT_FDCWD, source,
+ Pflag ? 0 : AT_SYMLINK_FOLLOW)) {
warn("%s", source);
return (1);
}
@@ -191,8 +197,8 @@ usage(void)
extern char *__progname;
(void)fprintf(stderr,
- "usage: %s [-fhns] source [target]\n"
- " %s [-fs] source ... [directory]\n",
+ "usage: %s [-fhLnPs] source [target]\n"
+ " %s [-fLPs] source ... [directory]\n",
__progname, __progname);
exit(1);
}