xref: /netbsd-src/bin/ln/ln.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1987 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)ln.c	4.15 (Berkeley) 2/24/91";*/
42 static char rcsid[] = "$Id: ln.c,v 1.8 1994/02/08 05:09:26 mycroft Exp $";
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <err.h>
53 
54 static int	forceflag,		/* force link by removing target */
55 		dirflag,		/* allow hard links to directories */
56 		sflag,			/* symbolic, not hard, link */
57 		(*linkf)();		/* system link call */
58 static int	linkit();
59 static void	usage();
60 
61 int
62 main(argc, argv)
63 	int argc;
64 	char **argv;
65 {
66 	extern int optind;
67 	struct stat buf;
68 	int ch, exitval;
69 	char *sourcedir;
70 
71 	while ((ch = getopt(argc, argv, "fFs")) != EOF)
72 		switch((char)ch) {
73 		case 'f':
74 			forceflag = 1;
75 			break;
76 		case 'F':
77 			dirflag = 1;
78 			break;
79 		case 's':
80 			sflag = 1;
81 			break;
82 		case '?':
83 		default:
84 			usage();
85 		}
86 
87 	argv += optind;
88 	argc -= optind;
89 
90 	linkf = sflag ? symlink : link;
91 
92 	switch(argc) {
93 	case 0:
94 		usage();
95 		/* NOTREACHED */
96 	case 1:				/* ln target */
97 		exit(linkit(argv[0], ".", 1));
98 		/* NOTREACHED */
99 	case 2:				/* ln target source */
100 		exit(linkit(argv[0], argv[1], 0));
101 		/* NOTREACHED */
102 	default:			/* ln target1 target2 directory */
103 		sourcedir = argv[argc - 1];
104 		if (stat(sourcedir, &buf)) {
105 			err(1, "%s", sourcedir);
106 			/* NOTREACHED */
107 		}
108 		if (!S_ISDIR(buf.st_mode))
109 			usage();
110 		for (exitval = 0; *argv != sourcedir; ++argv)
111 			exitval |= linkit(*argv, sourcedir, 1);
112 		exit(exitval);
113 	}
114 	/* NOTREACHED */
115 }
116 
117 static int
118 linkit(source, target, isdir)
119 	char *source, *target;
120 	int isdir;
121 {
122 	struct stat buf;
123 	char path[MAXPATHLEN], *cp;
124 
125 	if (!sflag) {
126 		/* if source doesn't exist, quit now */
127 		if (stat(source, &buf)) {
128 			warn("%s", source);
129 			return(1);
130 		}
131 		/* only symbolic links to directories, unless -F option used */
132 		if (!dirflag && S_ISDIR(buf.st_mode)) {
133 			warnx("%s: %s", source, strerror(EISDIR));
134 			return(1);
135 		}
136 	}
137 
138 	/* if the target is a directory, append the source's name */
139 	if (isdir || !stat(target, &buf) && S_ISDIR(buf.st_mode)) {
140 		if (!(cp = rindex(source, '/')))
141 			cp = source;
142 		else
143 			++cp;
144 		(void)sprintf(path, "%s/%s", target, cp);
145 		target = path;
146 	}
147 
148 	/* Remove existing file if -f is was specified */
149 	if (forceflag && unlink (target) && errno != ENOENT) {
150 		warn("%s", target);
151 		return (1);
152 	}
153 
154 	if ((*linkf)(source, target)) {
155 		warn("%s", target);
156 		return(1);
157 	}
158 
159 	return(0);
160 }
161 
162 static void
163 usage()
164 {
165 	(void)fprintf(stderr,
166 	    "usage:\tln [-fs] file1 file2\n\tln [-fs] file ... directory\n");
167 	exit(1);
168 }
169