Subject: ln -i
To: None <tech-userlevel@netbsd.org>
From: None <hiramatu@boreas.dti.ne.jp>
List: tech-userlevel
Date: 09/03/2003 16:26:09
Hello,

How about adding -i(interactive) option to /bin/ln, to be more
consistent with mv, cp and rm?


This code is actually copied from FreeBSD.

diff -bur ln.orig/ln.1 ln/ln.1
--- ln.orig/ln.1	2003-08-24 04:53:37.000000000 +0900
+++ ln/ln.1	2003-08-24 04:50:57.000000000 +0900
@@ -75,6 +75,21 @@
 This is most useful with the
 .Fl f
 option, to replace a symlink which may point to a directory.
+.It Fl i
+Cause
+.Nm
+to write a prompt to standard error if the target file exists.
+If the response from the standard input begins with the character
+.Sq Li y
+or
+.Sq Li Y ,
+then unlink the target file so that the link may occur.
+Otherwise, do not attempt the link.
+(The
+.Fl i
+option overrides any previous
+.Fl f
+options.)
 .It Fl n
 Same as
 .Fl h ,
diff -bur ln.orig/ln.c ln/ln.c
--- ln.orig/ln.c	2003-08-24 04:53:37.000000000 +0900
+++ ln/ln.c	2003-08-24 04:50:57.000000000 +0900
@@ -56,6 +56,7 @@
 
 int	fflag;				/* Unlink existing files. */
 int	hflag;				/* Check new name for symlink first. */
+int	iflag;				/* Interactive mode. */
 int	sflag;				/* Symbolic, not hard, link. */
 int	vflag;                          /* Verbose output */
 int	stdout_ok;			/* stdout connected to a terminal */
@@ -77,15 +78,20 @@
 	char *sourcedir;
 
 	setprogname(argv[0]);
-	while ((ch = getopt(argc, argv, "fhnsv")) != -1)
+	while ((ch = getopt(argc, argv, "fhnisv")) != -1)
 		switch (ch) {
 		case 'f':
 			fflag = 1;
+			iflag = 0;
 			break;
 		case 'h':
 		case 'n':
 			hflag = 1;
 			break;
+		case 'i':
+			iflag = 1;
+			fflag = 0;
+			break;
 		case 's':
 			sflag = 1;
 			break;
@@ -150,6 +156,7 @@
 linkit(char *target, char *source, int isdir)
 {
 	struct stat sb;
+	int ch, exists, first;
 	char *p, path[MAXPATHLEN];
 	char *sn, *tn;
 
@@ -181,12 +188,36 @@
 		source = path;
 	}
 
+	exists = !lstat(source, &sb);
 	/*
-	 * If the file exists, and -f was specified, unlink it.
-	 * Attempt the link.
+	 * If the file exists, then unlink it forcibly if -f was specified
+	 * and interactively if -i was specified.
 	 */
-	if ((fflag && unlink(source) < 0 && errno != ENOENT) ||
-	    (*linkf)(target, source)) {
+	if (fflag & exists) {
+		if (unlink(source)) {
+			warn("%s", source);
+			return (1);
+		}
+	} else if (iflag && exists) {
+		fflush(stdout);
+		fprintf(stderr, "replace %s? ", source);
+
+		first = ch = getchar();
+		while(ch != '\n' && ch != EOF)
+			ch = getchar();
+		if (first != 'y' && first != 'Y') {
+			fprintf(stderr, "not replaced\n");
+			return (1);
+		}
+
+		if (unlink(source)) {
+			warn("%s", source);
+			return (1);
+		}
+	}
+
+	/* Attempt the link. */
+	if ((*linkf)(target, source)) {
 		warn("%s", source);
 		free(sn);
 		free(tn);