From afad68b5dc9dd7ac9e87c87a272c5dad1a689597 Mon Sep 17 00:00:00 2001 From: jilles Date: Sun, 19 Jul 2009 17:35:23 +0000 Subject: 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) --- bin/ln/ln.1 | 39 ++++++++++++++++++++++++++------------- bin/ln/ln.c | 24 +++++++++++++++--------- 2 files changed, 41 insertions(+), 22 deletions(-) (limited to 'bin/ln') diff --git a/bin/ln/ln.1 b/bin/ln/ln.1 index 2cb2639..6f554c8 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 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 between a hard and symbolic link. .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 diff --git a/bin/ln/ln.c b/bin/ln/ln.c index 1908c16..e946646 100644 --- a/bin/ln/ln.c +++ b/bin/ln/ln.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -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 *target, int isdir) 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 *target, int isdir) } /* 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); } -- cgit v1.1