date and time created 91/03/07 20:28:05 by bostic
[unix-history] / usr / src / bin / ln / ln.c
CommitLineData
8fb84ebd 1/*
7a909b83 2 * Copyright (c) 1987 Regents of the University of California.
a754946e
KB
3 * All rights reserved.
4 *
f15db449 5 * %sccs.include.redist.c%
8fb84ebd 6 */
7a909b83 7
a754946e 8#ifndef lint
7a909b83
KB
9char copyright[] =
10"@(#) Copyright (c) 1987 Regents of the University of California.\n\
11 All rights reserved.\n";
a754946e 12#endif /* not lint */
7a909b83 13
a754946e 14#ifndef lint
337f474e 15static char sccsid[] = "@(#)ln.c 4.15 (Berkeley) %G%";
a754946e 16#endif /* not lint */
7a909b83
KB
17
18#include <sys/param.h>
8fb84ebd 19#include <sys/stat.h>
7a909b83 20#include <stdio.h>
56abc04a 21#include <errno.h>
be183d1e 22#include <string.h>
337f474e
DS
23#include <stdlib.h>
24#include <unistd.h>
8fb84ebd 25
fd5596d8 26static int dirflag, /* undocumented force flag */
7a909b83
KB
27 sflag, /* symbolic, not hard, link */
28 (*linkf)(); /* system link call */
337f474e 29static linkit(), usage();
8fb84ebd
BJ
30
31main(argc, argv)
be183d1e
KB
32 int argc;
33 char **argv;
8fb84ebd 34{
fd5596d8
KB
35 extern int optind;
36 struct stat buf;
37 int ch, exitval, link(), symlink();
38 char *sourcedir;
8fb84ebd 39
fd5596d8 40 while ((ch = getopt(argc, argv, "Fs")) != EOF)
7a909b83 41 switch((char)ch) {
fd5596d8
KB
42 case 'F':
43 dirflag = 1;
7a909b83
KB
44 break;
45 case 's':
46 sflag = 1;
47 break;
48 case '?':
49 default:
50 usage();
51 }
52
53 argv += optind;
54 argc -= optind;
55
56 linkf = sflag ? symlink : link;
57
58 switch(argc) {
59 case 0:
60 usage();
61 case 1: /* ln target */
62 exit(linkit(argv[0], ".", 1));
63 case 2: /* ln target source */
64 exit(linkit(argv[0], argv[1], 0));
65 default: /* ln target1 target2 directory */
66 sourcedir = argv[argc - 1];
67 if (stat(sourcedir, &buf)) {
be183d1e
KB
68 (void)fprintf(stderr,
69 "ln: %s: %s\n", sourcedir, strerror(errno));
7a909b83
KB
70 exit(1);
71 }
be183d1e 72 if (!S_ISDIR(buf.st_mode))
7a909b83
KB
73 usage();
74 for (exitval = 0; *argv != sourcedir; ++argv)
75 exitval |= linkit(*argv, sourcedir, 1);
76 exit(exitval);
8fb84ebd 77 }
be183d1e 78 /* NOTREACHED */
8fb84ebd
BJ
79}
80
7a909b83
KB
81static
82linkit(target, source, isdir)
be183d1e
KB
83 char *target, *source;
84 int isdir;
8fb84ebd 85{
be183d1e
KB
86 struct stat buf;
87 char path[MAXPATHLEN], *cp;
8fb84ebd 88
7a909b83
KB
89 if (!sflag) {
90 /* if target doesn't exist, quit now */
91 if (stat(target, &buf)) {
be183d1e
KB
92 (void)fprintf(stderr,
93 "ln: %s: %s\n", target, strerror(errno));
7a909b83
KB
94 return(1);
95 }
fd5596d8
KB
96 /* only symbolic links to directories, unless -F option used */
97 if (!dirflag && (buf.st_mode & S_IFMT) == S_IFDIR) {
be183d1e 98 (void)printf("ln: %s is a directory.\n", target);
7a909b83
KB
99 return(1);
100 }
8fb84ebd 101 }
7a909b83
KB
102
103 /* if the source is a directory, append the target's name */
104 if (isdir || !stat(source, &buf) && (buf.st_mode & S_IFMT) == S_IFDIR) {
105 if (!(cp = rindex(target, '/')))
106 cp = target;
1bfeaa36 107 else
7a909b83
KB
108 ++cp;
109 (void)sprintf(path, "%s/%s", source, cp);
110 source = path;
8fb84ebd 111 }
7a909b83
KB
112
113 if ((*linkf)(target, source)) {
be183d1e 114 (void)fprintf(stderr, "ln: %s: %s\n", source, strerror(errno));
7a909b83 115 return(1);
8fb84ebd 116 }
7a909b83
KB
117 return(0);
118}
119
120static
121usage()
122{
be183d1e
KB
123 (void)fprintf(stderr,
124 "usage:\tln [-s] file1 file2\n\tln [-s] file ... directory\n");
7a909b83 125 exit(1);
8fb84ebd 126}