new vm
[unix-history] / usr / src / bin / ln / ln.c
index b72eb23..038599f 100644 (file)
-static char sccsid[] = "@(#)ln.c 4.8 %G%";
 /*
 /*
- * ln
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
  */
-#include <stdio.h>
-#include <sys/types.h>
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1987 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ln.c       4.15 (Berkeley) %G%";
+#endif /* not lint */
+
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <stdio.h>
 #include <errno.h>
 #include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 
-struct stat stb;
-int    fflag;          /* force flag set? */
-int    sflag;
-char   name[BUFSIZ];
-char   *rindex();
-extern int errno;
+static int     dirflag,                        /* undocumented force flag */
+               sflag,                          /* symbolic, not hard, link */
+               (*linkf)();                     /* system link call */
+static linkit(), usage();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
-       register char **argv;
+       char **argv;
 {
 {
-       register int i, r;
+       extern int optind;
+       struct stat buf;
+       int ch, exitval, link(), symlink();
+       char *sourcedir;
 
 
-       argc--, argv++;
-again:
-       if (argc && strcmp(argv[0], "-f") == 0) {
-               fflag++;
-               argv++;
-               argc--;
-       }
-       if (argc && strcmp(argv[0], "-s") == 0) {
-               sflag++;
-               argv++;
-               argc--;
-       }
-       if (argc == 0) 
-               goto usage;
-       else if (argc == 1) {
-               argv[argc] = ".";
-               argc++;
-       }
-       if (sflag == 0 && argc > 2) {
-               if (stat(argv[argc-1], &stb) < 0)
-                       goto usage;
-               if ((stb.st_mode&S_IFMT) != S_IFDIR) 
-                       goto usage;
+       while ((ch = getopt(argc, argv, "Fs")) != EOF)
+               switch((char)ch) {
+               case 'F':
+                       dirflag = 1;
+                       break;
+               case 's':
+                       sflag = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+
+       argv += optind;
+       argc -= optind;
+
+       linkf = sflag ? symlink : link;
+
+       switch(argc) {
+       case 0:
+               usage();
+       case 1:                         /* ln target */
+               exit(linkit(argv[0], ".", 1));
+       case 2:                         /* ln target source */
+               exit(linkit(argv[0], argv[1], 0));
+       default:                        /* ln target1 target2 directory */
+               sourcedir = argv[argc - 1];
+               if (stat(sourcedir, &buf)) {
+                       (void)fprintf(stderr,
+                           "ln: %s: %s\n", sourcedir, strerror(errno));
+                       exit(1);
+               }
+               if (!S_ISDIR(buf.st_mode))
+                       usage();
+               for (exitval = 0; *argv != sourcedir; ++argv)
+                       exitval |= linkit(*argv, sourcedir, 1);
+               exit(exitval);
        }
        }
-       r = 0;
-       for(i = 0; i < argc-1; i++)
-               r |= linkit(argv[i], argv[argc-1]);
-       exit(r);
-usage:
-       fprintf(stderr, "Usage: ln [ -s ] f1\nor: ln [ -s ] f1 f2\nln [ -s ] f1 ... fn d2\n");
-       exit(1);
+       /* NOTREACHED */
 }
 
 }
 
-int    link(), symlink();
-
-linkit(from, to)
-       char *from, *to;
+static
+linkit(target, source, isdir)
+       char *target, *source;
+       int isdir;
 {
 {
-       char *tail;
-       int (*linkf)() = sflag ? symlink : link;
+       struct stat buf;
+       char path[MAXPATHLEN], *cp;
 
 
-       /* is target a directory? */
-       if (sflag == 0 && fflag == 0 && stat(from, &stb) >= 0
-           && (stb.st_mode&S_IFMT) == S_IFDIR) {
-               printf("%s is a directory\n", from);
-               return (1);
+       if (!sflag) {
+               /* if target doesn't exist, quit now */
+               if (stat(target, &buf)) {
+                       (void)fprintf(stderr,
+                           "ln: %s: %s\n", target, strerror(errno));
+                       return(1);
+               }
+               /* only symbolic links to directories, unless -F option used */
+               if (!dirflag && (buf.st_mode & S_IFMT) == S_IFDIR) {
+                       (void)printf("ln: %s is a directory.\n", target);
+                       return(1);
+               }
        }
        }
-       if (stat(to, &stb) >= 0 && (stb.st_mode&S_IFMT) == S_IFDIR) {
-               tail = rindex(from, '/');
-               if (tail == 0)
-                       tail = from;
+
+       /* if the source is a directory, append the target's name */
+       if (isdir || !stat(source, &buf) && (buf.st_mode & S_IFMT) == S_IFDIR) {
+               if (!(cp = rindex(target, '/')))
+                       cp = target;
                else
                else
-                       tail++;
-               (void)sprintf(name, "%s/%s", to, tail);
-               to = name;
+                       ++cp;
+               (void)sprintf(path, "%s/%s", source, cp);
+               source = path;
        }
        }
-       if ((*linkf)(from, to) < 0) {
-               if (errno == EEXIST || sflag)
-                       perror(to);
-               else if (access(from, 0) < 0)
-                       perror(from);
-               else
-                       perror(to);
-               return (1);
+
+       if ((*linkf)(target, source)) {
+               (void)fprintf(stderr, "ln: %s: %s\n", source, strerror(errno));
+               return(1);
        }
        }
-       return (0);
+       return(0);
+}
+
+static
+usage()
+{
+       (void)fprintf(stderr,
+           "usage:\tln [-s] file1 file2\n\tln [-s] file ... directory\n");
+       exit(1);
 }
 }