Please somebody take a look at attached patch that adds ``-h'' option
to the ln(1) command (obtained from NetBSD, which has it since 1997).
In addition, I've tried to minimise diffs between our code and
NetBSD's one, so  there are several changes that at a first glance
look superfluous.

-Maxim
Index: ln.1
===================================================================
RCS file: /home/ncvs/src/bin/ln/ln.1,v
retrieving revision 1.14
diff -d -u -r1.14 ln.1
--- ln.1        2000/11/20 11:39:37     1.14
+++ ln.1        2001/04/20 14:36:37
@@ -44,11 +44,11 @@
 .Nd make links
 .Sh SYNOPSIS
 .Nm
-.Op Fl fisv
+.Op Fl fhinsv
 .Ar source_file
 .Op target_file
 .Nm
-.Op Fl fisv
+.Op Fl fhinsv
 .Ar source_file ...
 .Op target_dir
 .Nm link
@@ -79,6 +79,14 @@
 option overrides any previous
 .Fl i
 options.)
+.It Fl h
+If the
+.Ar target_file
+or
+.Ar target_dir
+is a symbolic link, do not follow it.  This is most useful with the
+.Fl f
+option, to replace a symlink which may point to a directory.
 .It Fl i
 Cause
 .Nm
@@ -94,6 +102,12 @@
 option overrides any previous
 .Fl f
 options.)
+.It Fl n
+Same as
+.Fl h ,
+for compatibility with other
+.Nm
+implementations.
 .It Fl s
 Create a symbolic link.
 .It Fl v
@@ -168,12 +182,18 @@
 and
 .Fl v
 options are non-standard and their use in scripts is not recommended.
-.Sh HISTORY
-An
+.Sh STANDARDS
+The
 .Nm
-command appeared in
-.At v1 .
+utility conforms to
+.St -p1003.2-92 .
+.Pp
 The simplified
 .Nm link
 command conforms to
 .St -susv2 .
+.Sh HISTORY
+An
+.Nm
+command appeared in
+.At v1 .
Index: ln.c
===================================================================
RCS file: /home/ncvs/src/bin/ln/ln.c,v
retrieving revision 1.18
diff -d -u -r1.18 ln.c
--- ln.c        2000/08/17 16:08:06     1.18
+++ ln.c        2001/04/20 14:36:37
@@ -57,6 +57,7 @@
 
 int    fflag;                          /* Unlink existing files. */
 int    iflag;                          /* Interactive mode. */
+int    hflag;                          /* Check new name for symlink first. */
 int    sflag;                          /* Symbolic, not hard, link. */
 int    vflag;                          /* Verbose output. */
                                        /* System link call. */
@@ -65,6 +66,7 @@
 
 int    linkit __P((char *, char *, int));
 void   usage __P((void));
+int    main __P((int, char *[]));
 
 int
 main(argc, argv)
@@ -73,7 +75,8 @@
 {
        struct stat sb;
        int ch, exitval;
-       char *p, *sourcedir;
+       char *p;
+       char *sourcedir;
 
        /*
         * Test for the special case where the utility is called as
@@ -92,12 +95,16 @@
                        usage();
        }
 
-       while ((ch = getopt(argc, argv, "fisv")) != -1)
+       while ((ch = getopt(argc, argv, "fhinsv")) != -1)
                switch (ch) {
                case 'f':
                        fflag = 1;
                        iflag = 0;
                        break;
+               case 'h':
+               case 'n':
+                       hflag = 1;
+                       break;
                case 'i':
                        iflag = 1;
                        fflag = 0;
@@ -122,13 +129,22 @@
        switch(argc) {
        case 0:
                usage();
+               /* NOTREACHED */
        case 1:                         /* ln target */
                exit(linkit(argv[0], ".", 1));
+               /* NOTREACHED */
        case 2:                         /* ln target source */
                exit(linkit(argv[0], argv[1], 0));
+               /* NOTREACHED */
        }
                                        /* ln target1 target2 directory */
        sourcedir = argv[argc - 1];
+       if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+               /* we were asked not to follow symlinks, but found one at
+                  the target--simulate "not a directory" error */
+               errno = ENOTDIR;
+               err(1, "%s", sourcedir);
+       }
        if (stat(sourcedir, &sb))
                err(1, "%s", sourcedir);
        if (!S_ISDIR(sb.st_mode))
@@ -136,6 +152,7 @@
        for (exitval = 0; *argv != sourcedir; ++argv)
                exitval |= linkit(*argv, sourcedir, 1);
        exit(exitval);
+       /* NOTREACHED */
 }
 
 int
@@ -161,18 +178,20 @@
                }
        }
 
-       /* If the source is a directory, append the target's name. */
-       if (isdir || ((exists = !stat(source, &sb)) && S_ISDIR(sb.st_mode))) {
+       /* If the source is a directory (and not a symlink if hflag),
+          append the target's name. */
+       if (isdir ||
+           (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
+           (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
                if ((p = strrchr(target, '/')) == NULL)
                        p = target;
                else
                        ++p;
                (void)snprintf(path, sizeof(path), "%s/%s", source, p);
                source = path;
-               exists = !lstat(source, &sb);
-       } else
-               exists = !lstat(source, &sb);
+       }
 
+       exists = !lstat(source, &sb);
        /*
         * If the file exists, then unlink it forcibly if -f was specified
         * and interactively if -i was specified.
@@ -214,8 +233,9 @@
 usage()
 {
        (void)fprintf(stderr, "%s\n%s\n%s\n",
-           "usage: ln [-fisv] file1 file2",
-           "       ln [-fisv] file ... directory",
+           "usage: ln [-fhinsv] file1 file2",
+           "       ln [-fhinsv] file ... directory",
            "       link file1 file2");
        exit(1);
+       /* NOTREACHED */
 }

Reply via email to