sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

commit 94ef670b27900c9f2e47181cd79acd55c6cf6e1a
parent cb427d553af31c30c1c1ca0c1490374fee1b6cdb
Author: Michael Forney <mforney@mforney.org>
Date:   Sun, 23 Nov 2014 20:25:39 +0000

ln: Add support for target directories

Also, now that we are using {sym,}linkat, implement the trivial -L and
-P options.

Diffstat:
Mln.1 | 11+++++++++--
Mln.c | 53++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 47 insertions(+), 17 deletions(-)

diff --git 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 @@ -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; }