ln: Add support for target directories
Also, now that we are using {sym,}linkat, implement the trivial -L and -P options.
This commit is contained in:
parent
cb427d553a
commit
94ef670b27
11
ln.1
11
ln.1
@ -3,12 +3,12 @@
|
|||||||
ln \- make links between files
|
ln \- make links between files
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ln
|
.B ln
|
||||||
.RB [ \-fs ]
|
.RB [ \-LPfs ]
|
||||||
.I file
|
.I file
|
||||||
.RI [ name ]
|
.RI [ name ]
|
||||||
.P
|
.P
|
||||||
.B ln
|
.B ln
|
||||||
.RB [ \-fs ]
|
.RB [ \-LPfs ]
|
||||||
.RI [ file ...]
|
.RI [ file ...]
|
||||||
.RI [ directory ]
|
.RI [ directory ]
|
||||||
.SH DESCRIPTION
|
.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.
|
be linked into the given directory.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.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
|
.B \-f
|
||||||
remove existing destinations.
|
remove existing destinations.
|
||||||
.TP
|
.TP
|
||||||
|
45
ln.c
45
ln.c
@ -1,9 +1,11 @@
|
|||||||
/* See LICENSE file for copyright and license details. */
|
/* See LICENSE file for copyright and license details. */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -11,16 +13,20 @@
|
|||||||
static void
|
static void
|
||||||
usage(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
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int (*flink)(const char *, const char *);
|
|
||||||
char *fname, *to;
|
char *fname, *to;
|
||||||
int sflag = 0;
|
int sflag = 0;
|
||||||
int fflag = 0;
|
int fflag = 0;
|
||||||
|
int hasto = 0;
|
||||||
|
int dirfd = AT_FDCWD;
|
||||||
|
int flags = AT_SYMLINK_FOLLOW;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -29,27 +35,44 @@ main(int argc, char *argv[])
|
|||||||
case 's':
|
case 's':
|
||||||
sflag = 1;
|
sflag = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
flags |= AT_SYMLINK_FOLLOW;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
flags &= ~AT_SYMLINK_FOLLOW;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
|
||||||
if (argc == 0 || argc > 2)
|
if (argc == 0)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
if (sflag) {
|
fname = sflag ? "symlink" : "link";
|
||||||
flink = symlink;
|
|
||||||
fname = "symlink";
|
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 {
|
} else {
|
||||||
flink = link;
|
eprintf("destination is not a directory\n");
|
||||||
fname = "link";
|
}
|
||||||
|
argc--;
|
||||||
}
|
}
|
||||||
|
|
||||||
to = argc < 2 ? basename(argv[0]) : argv[1];
|
for (; argc > 0; argc--, argv++) {
|
||||||
|
if (!hasto)
|
||||||
|
to = basename(argv[0]);
|
||||||
if (fflag)
|
if (fflag)
|
||||||
remove(to);
|
remove(to);
|
||||||
if (flink(argv[0], to) < 0)
|
if ((!sflag ? linkat(AT_FDCWD, argv[0], dirfd, to, flags)
|
||||||
|
: symlinkat(argv[0], dirfd, to)) < 0) {
|
||||||
eprintf("%s %s <- %s:", fname, argv[0], to);
|
eprintf("%s %s <- %s:", fname, argv[0], to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user