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:
		
							
								
								
									
										11
									
								
								ln.1
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								ln.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								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";
 | 
			
		||||
 | 
			
		||||
	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--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	to = argc < 2 ? basename(argv[0]) : argv[1];
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user