Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jul 2009 17:35:23 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r195768 - head/bin/ln
Message-ID:  <200907191735.n6JHZNgm049664@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jilles
Date: Sun Jul 19 17:35:23 2009
New Revision: 195768
URL: http://svn.freebsd.org/changeset/base/195768

Log:
  Allow creating hard links to symlinks using ln(1).
  
  This implements the POSIX.1-2008 -L and -P flags.
  
  The default remains to create hard links to the target of symlinks.
  
  Approved by:	re (kib), ed (mentor)

Modified:
  head/bin/ln/ln.1
  head/bin/ln/ln.c

Modified: head/bin/ln/ln.1
==============================================================================
--- head/bin/ln/ln.1	Sun Jul 19 17:25:24 2009	(r195767)
+++ head/bin/ln/ln.1	Sun Jul 19 17:35:23 2009	(r195768)
@@ -32,7 +32,7 @@
 .\"	@(#)ln.1	8.2 (Berkeley) 12/30/93
 .\" $FreeBSD$
 .\"
-.Dd June 6, 2008
+.Dd July 17, 2009
 .Dt LN 1
 .Os
 .Sh NAME
@@ -41,13 +41,13 @@
 .Nd link files
 .Sh SYNOPSIS
 .Nm
-.Op Fl s Op Fl F
+.Op Fl L | Fl P | Fl s Op Fl F
 .Op Fl f | iw
 .Op Fl hnv
 .Ar source_file
 .Op Ar target_file
 .Nm
-.Op Fl s Op Fl F
+.Op Fl L | Fl P | Fl s Op Fl F
 .Op Fl f | iw
 .Op Fl hnv
 .Ar source_file ...
@@ -77,16 +77,6 @@ to a file is one of the differences betw
 .Pp
 The options are as follows:
 .Bl -tag -width flag
-.It Fl f
-If the target file already exists,
-then unlink it so that the link may occur.
-(The
-.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
 so that the link may occur.
@@ -105,6 +95,29 @@ The
 option is a no-op unless
 .Fl s
 option is specified.
+.It Fl L
+When creating a hard link to a symbolic link,
+create a hard link to the target of the symbolic link.
+This is the default.
+This option cancels the
+.Fl P
+option.
+.It Fl P
+When creating a hard link to a symbolic link,
+create a hard link to the symbolic link itself.
+This option cancels the
+.Fl L
+option.
+.It Fl f
+If the target file already exists,
+then unlink it so that the link may occur.
+(The
+.Fl f
+option overrides any previous
+.Fl i
+and
+.Fl w
+options.)
 .It Fl h
 If the
 .Ar target_file

Modified: head/bin/ln/ln.c
==============================================================================
--- head/bin/ln/ln.c	Sun Jul 19 17:25:24 2009	(r195767)
+++ head/bin/ln/ln.c	Sun Jul 19 17:35:23 2009	(r195768)
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -56,12 +57,11 @@ int	fflag;				/* Unlink existing files. 
 int	Fflag;				/* Remove empty directories also. */
 int	hflag;				/* Check new name for symlink first. */
 int	iflag;				/* Interactive mode. */
+int	Pflag;				/* Create hard links to symlinks. */
 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;
 
 int	linkit(const char *, const char *, int);
@@ -90,15 +90,20 @@ main(int argc, char *argv[])
 		argv += optind;
 		if (argc != 2)
 			usage();
-		linkf = link;
 		exit(linkit(argv[0], argv[1], 0));
 	}
 
-	while ((ch = getopt(argc, argv, "Ffhinsvw")) != -1)
+	while ((ch = getopt(argc, argv, "FLPfhinsvw")) != -1)
 		switch (ch) {
 		case 'F':
 			Fflag = 1;
 			break;
+		case 'L':
+			Pflag = 0;
+			break;
+		case 'P':
+			Pflag = 1;
+			break;
 		case 'f':
 			fflag = 1;
 			iflag = 0;
@@ -129,7 +134,6 @@ main(int argc, char *argv[])
 	argv += optind;
 	argc -= optind;
 
-	linkf = sflag ? symlink : link;
 	linkch = sflag ? '-' : '=';
 	if (sflag == 0)
 		Fflag = 0;
@@ -179,7 +183,7 @@ linkit(const char *source, const char *t
 
 	if (!sflag) {
 		/* If source doesn't exist, quit now. */
-		if (stat(source, &sb)) {
+		if ((Pflag ? lstat : stat)(source, &sb)) {
 			warn("%s", source);
 			return (1);
 		}
@@ -276,7 +280,9 @@ linkit(const char *source, const char *t
 	}
 
 	/* Attempt the link. */
-	if ((*linkf)(source, target)) {
+	if (sflag ? symlink(source, target) :
+	    linkat(AT_FDCWD, source, AT_FDCWD, target,
+	    Pflag ? 0 : AT_SYMLINK_FOLLOW)) {
 		warn("%s", target);
 		return (1);
 	}
@@ -289,8 +295,8 @@ void
 usage(void)
 {
 	(void)fprintf(stderr, "%s\n%s\n%s\n",
-	    "usage: ln [-s [-F]] [-f | -i] [-hnv] source_file [target_file]",
-	    "       ln [-s [-F]] [-f | -i] [-hnv] source_file ... target_dir",
+	    "usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]",
+	    "       ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir",
 	    "       link source_file target_file");
 	exit(1);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907191735.n6JHZNgm049664>