Also, now that we are using {sym,}linkat, implement the trivial -L and
-P options.
---
 ln.1 | 11 +++++++++--
 ln.c | 53 ++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/ln.1 b/ln.1
index 4205ea7..3b1ac98 100644
--- a/ln.1
+++ b/ln.1
@@ -3,12 +3,12 @@
 ln \- make links between files
 .SH SYNOPSIS
 .B ln
-.RB [ \-fs ]
+.RB [ \-LPfs ]
 .I file
 .RI [ name ]
 .P
 .B ln
-.RB [ \-fs ]
+.RB [ \-LPfs ]
 .RI [ file ...]
 .RI [ directory ]
 .SH DESCRIPTION
@@ -18,6 +18,13 @@ it is linked into the current directory.  If multiple files 
are listed they will
 be linked into the given directory.
 .SH OPTIONS
 .TP
+.B \-L
+create links to the files referenced by symbolic link source files (default
+behavior).
+.TP
+.B \-P
+create links to symbolic link source files themselves.
+.TP
 .B \-f
 remove existing destinations.
 .TP
diff --git a/ln.c b/ln.c
index d8809ce..0a5bf18 100644
--- a/ln.c
+++ b/ln.c
@@ -1,9 +1,11 @@
 /* See LICENSE file for copyright and license details. */
 #include <errno.h>
+#include <fcntl.h>
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "util.h"
@@ -11,16 +13,20 @@
 static void
 usage(void)
 {
-       eprintf("usage: %s [-fs] target [linkname]\n", argv0);
+       eprintf("usage: %1$s [-LPfs] target [linkname]\n"
+               "       %1$s [-LPfs] target... directory\n", argv0);
 }
 
 int
 main(int argc, char *argv[])
 {
-       int (*flink)(const char *, const char *);
        char *fname, *to;
        int sflag = 0;
        int fflag = 0;
+       int hasto = 0;
+       int dirfd = AT_FDCWD;
+       int flags = AT_SYMLINK_FOLLOW;
+       struct stat st;
 
        ARGBEGIN {
        case 'f':
@@ -29,27 +35,44 @@ main(int argc, char *argv[])
        case 's':
                sflag = 1;
                break;
+       case 'L':
+               flags |= AT_SYMLINK_FOLLOW;
+               break;
+       case 'P':
+               flags &= ~AT_SYMLINK_FOLLOW;
+               break;
        default:
                usage();
        } ARGEND;
 
-       if (argc == 0 || argc > 2)
+       if (argc == 0)
                usage();
 
-       if (sflag) {
-               flink = symlink;
-               fname = "symlink";
-       } else {
-               flink = link;
-               fname = "link";
-       }
+       fname = sflag ? "symlink" : "link";
 
-       to = argc < 2 ? basename(argv[0]) : argv[1];
+       if (argc >= 2) {
+               if (stat(argv[argc - 1], &st) == 0 && S_ISDIR(st.st_mode)) {
+                       if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0)
+                               eprintf("open:");
+               } else if (argc == 2) {
+                       to = argv[1];
+                       hasto = 1;
+               } else {
+                       eprintf("destination is not a directory\n");
+               }
+               argc--;
+       }
 
-       if (fflag)
-               remove(to);
-       if (flink(argv[0], to) < 0)
-               eprintf("%s %s <- %s:", fname, argv[0], to);
+       for (; argc > 0; argc--, argv++) {
+               if (!hasto)
+                       to = basename(argv[0]);
+               if (fflag)
+                       remove(to);
+               if ((!sflag ? linkat(AT_FDCWD, argv[0], dirfd, to, flags)
+                           : symlinkat(argv[0], dirfd, to)) < 0) {
+                       eprintf("%s %s <- %s:", fname, argv[0], to);
+               }
+       }
 
        return 0;
 }
-- 
2.1.3.1.g339ec9c


Reply via email to