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