1/*- 2 * Copyright (c) 1987, 1993, 1994 3 * The Regents of the University of California. 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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#if 0 31#ifndef lint 32static char const copyright[] = 33"@(#) Copyright (c) 1987, 1993, 1994\n\ 34 The Regents of the University of California. All rights reserved.\n"; 35#endif /* not lint */ 36 37#ifndef lint 38static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; 39#endif /* not lint */ 40#endif 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: src/bin/ln/ln.c,v 1.34 2006/02/14 11:08:05 glebius Exp $"); 43 44#include <sys/param.h> 45#include <sys/stat.h> 46 47#include <err.h> 48#include <errno.h> 49#include <libgen.h> 50#include <limits.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <unistd.h> 55 56int fflag; /* Unlink existing files. */ 57int Fflag; /* Remove empty directories also. */ 58int hflag; /* Check new name for symlink first. */ 59int iflag; /* Interactive mode. */ 60int sflag; /* Symbolic, not hard, link. */ 61int vflag; /* Verbose output. */ 62 /* System link call. */ 63int (*linkf)(const char *, const char *); 64char linkch; 65 66int linkit(const char *, const char *, int); 67void usage(void); 68 69int 70main(int argc, char *argv[]) 71{ 72 struct stat sb; 73 char *p, *sourcedir; 74 int ch, exitval; 75 76 if (argc < 1) 77 usage(); 78 /* 79 * Test for the special case where the utility is called as 80 * "link", for which the functionality provided is greatly 81 * simplified. 82 */ 83 if ((p = rindex(argv[0], '/')) == NULL) 84 p = argv[0]; 85 else 86 ++p; 87 if (strcmp(p, "link") == 0) { 88 while (getopt(argc, argv, "") != -1) 89 usage(); 90 argc -= optind; 91 argv += optind; 92 if (argc != 2) 93 usage(); 94 linkf = link; 95 exit(linkit(argv[0], argv[1], 0)); 96 } 97 98 while ((ch = getopt(argc, argv, "Ffhinsv")) != -1) 99 switch (ch) { 100 case 'F': 101 Fflag = 1; 102 break; 103 case 'f': 104 fflag = 1; 105 iflag = 0; 106 break; 107 case 'h': 108 case 'n': 109 hflag = 1; 110 break; 111 case 'i': 112 iflag = 1; 113 fflag = 0; 114 break; 115 case 's': 116 sflag = 1; 117 break; 118 case 'v': 119 vflag = 1; 120 break; 121 case '?': 122 default: 123 usage(); 124 } 125 126 argv += optind; 127 argc -= optind; 128 129 linkf = sflag ? symlink : link; 130 linkch = sflag ? '-' : '='; 131 if (sflag == 0) 132 Fflag = 0; 133 if (Fflag == 1 && iflag == 0) 134 fflag = 1; 135 136 switch(argc) { 137 case 0: 138 usage(); 139 /* NOTREACHED */ 140 case 1: /* ln target */ 141 exit(linkit(argv[0], ".", 1)); 142 case 2: /* ln target source */ 143 exit(linkit(argv[0], argv[1], 0)); 144 default: 145 ; 146 } 147 /* ln target1 target2 directory */ 148 sourcedir = argv[argc - 1]; 149 if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { 150 /* 151 * We were asked not to follow symlinks, but found one at 152 * the target--simulate "not a directory" error 153 */ 154 errno = ENOTDIR; 155 err(1, "%s", sourcedir); 156 } 157 if (stat(sourcedir, &sb)) 158 err(1, "%s", sourcedir); 159 if (!S_ISDIR(sb.st_mode)) 160 usage(); 161 for (exitval = 0; *argv != sourcedir; ++argv) 162 exitval |= linkit(*argv, sourcedir, 1); 163 exit(exitval); 164} 165 166int 167linkit(const char *target, const char *source, int isdir) 168{ 169 struct stat sb; 170 const char *p; 171 int ch, exists, first; 172 char path[PATH_MAX]; 173 char bbuf[PATH_MAX]; 174 175 if (!sflag) { 176 /* If target doesn't exist, quit now. */ 177 if (stat(target, &sb)) { 178 warn("%s", target); 179 return (1); 180 } 181 /* Only symbolic links to directories. */ 182 if (S_ISDIR(sb.st_mode)) { 183 errno = EISDIR; 184 warn("%s", target); 185 return (1); 186 } 187 } 188 189 /* 190 * If the source is a directory (and not a symlink if hflag), 191 * append the target's name. 192 */ 193 if (isdir || 194 (lstat(source, &sb) == 0 && S_ISDIR(sb.st_mode)) || 195 (!hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) { 196 if (strlcpy(bbuf, target, sizeof(bbuf)) >= sizeof(bbuf) || 197 (p = basename(bbuf)) == NULL || 198 snprintf(path, sizeof(path), "%s/%s", source, p) >= 199 (ssize_t)sizeof(path)) { 200 errno = ENAMETOOLONG; 201 warn("%s", target); 202 return (1); 203 } 204 source = path; 205 } 206 207 exists = !lstat(source, &sb); 208 /* 209 * If the file exists, then unlink it forcibly if -f was specified 210 * and interactively if -i was specified. 211 */ 212 if (fflag && exists) { 213 if (Fflag && S_ISDIR(sb.st_mode)) { 214 if (rmdir(source)) { 215 warn("%s", source); 216 return (1); 217 } 218 } else if (unlink(source)) { 219 warn("%s", source); 220 return (1); 221 } 222 } else if (iflag && exists) { 223 fflush(stdout); 224 fprintf(stderr, "replace %s? ", source); 225 226 first = ch = getchar(); 227 while(ch != '\n' && ch != EOF) 228 ch = getchar(); 229 if (first != 'y' && first != 'Y') { 230 fprintf(stderr, "not replaced\n"); 231 return (1); 232 } 233 234 if (Fflag && S_ISDIR(sb.st_mode)) { 235 if (rmdir(source)) { 236 warn("%s", source); 237 return (1); 238 } 239 } else if (unlink(source)) { 240 warn("%s", source); 241 return (1); 242 } 243 } 244 245 /* Attempt the link. */ 246 if ((*linkf)(target, source)) { 247 warn("%s", source); 248 return (1); 249 } 250 if (vflag) 251 (void)printf("%s %c> %s\n", source, linkch, target); 252 return (0); 253} 254 255void 256usage(void) 257{ 258 (void)fprintf(stderr, "%s\n%s\n%s\n", 259 "usage: ln [-Ffhinsv] source_file [target_file]", 260 " ln [-Ffhinsv] source_file ... target_dir", 261 " link source_file target_file"); 262 exit(1); 263} 264