--- 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 _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; } -- 2.1.3.1.g339ec9cReceived on Sun Nov 23 2014 - 21:25:39 CET
This archive was generated by hypermail 2.3.0 : Sun Nov 23 2014 - 21:36:08 CET