[hackers] [sbase] ln: Add support for target directories || Michael Forney

From: <git_AT_suckless.org>
Date: Sun, 23 Nov 2014 21:58:20 +0100

commit 94ef670b27900c9f2e47181cd79acd55c6cf6e1a
Author: Michael Forney <mforney_AT_mforney.org>
Date: Sun Nov 23 20:25:39 2014 +0000

    ln: Add support for target directories
    
    Also, now that we are using {sym,}linkat, implement the trivial -L and
    -P options.

diff --git a/ln.1 b/ln.1
index 4205ea7..3b1ac98 100644
--- a/ln.1
+++ b/ln.1
_AT_@ -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
_AT_@ -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
_AT_@ -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"
_AT_@ -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':
_AT_@ -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;
 }
Received on Sun Nov 23 2014 - 21:58:20 CET

This archive was generated by hypermail 2.3.0 : Sun Nov 23 2014 - 22:00:16 CET