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 * 3. 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 * @(#) Copyright (c) 1987, 1993, 1994 The Regents of the University of California. All rights reserved. 30 * @(#)ln.c 8.2 (Berkeley) 3/31/94 31 * $FreeBSD: head/bin/ln/ln.c 251261 2013-06-02 17:55:00Z eadler $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/stat.h> 36 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <libgen.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 static int fflag; /* Unlink existing files. */ 47 static int Fflag; /* Remove empty directories also. */ 48 static int hflag; /* Check new name for symlink first. */ 49 static int iflag; /* Interactive mode. */ 50 static int Pflag; /* Create hard links to symlinks. */ 51 static int sflag; /* Symbolic, not hard, link. */ 52 static int vflag; /* Verbose output. */ 53 static int wflag; /* Warn if symlink target does not 54 * exist, and -f is not enabled. */ 55 static char linkch; 56 57 static int linkit(const char *, const char *, int); 58 static void usage(void) __dead2; 59 60 int 61 main(int argc, char *argv[]) 62 { 63 struct stat sb; 64 char *p, *targetdir; 65 int ch, exitval; 66 67 /* 68 * Test for the special case where the utility is called as 69 * "link", for which the functionality provided is greatly 70 * simplified. 71 */ 72 if ((p = strrchr(argv[0], '/')) == NULL) 73 p = argv[0]; 74 else 75 ++p; 76 if (strcmp(p, "link") == 0) { 77 while (getopt(argc, argv, "") != -1) 78 usage(); 79 argc -= optind; 80 argv += optind; 81 if (argc != 2) 82 usage(); 83 exit(linkit(argv[0], argv[1], 0)); 84 } 85 86 while ((ch = getopt(argc, argv, "FLPfhinsvw")) != -1) 87 switch (ch) { 88 case 'F': 89 Fflag = 1; 90 break; 91 case 'L': 92 Pflag = 0; 93 break; 94 case 'P': 95 Pflag = 1; 96 break; 97 case 'f': 98 fflag = 1; 99 iflag = 0; 100 wflag = 0; 101 break; 102 case 'h': 103 case 'n': 104 hflag = 1; 105 break; 106 case 'i': 107 iflag = 1; 108 fflag = 0; 109 break; 110 case 's': 111 sflag = 1; 112 break; 113 case 'v': 114 vflag = 1; 115 break; 116 case 'w': 117 wflag = 1; 118 break; 119 case '?': 120 default: 121 usage(); 122 } 123 124 argv += optind; 125 argc -= optind; 126 127 linkch = sflag ? '-' : '='; 128 if (sflag == 0) 129 Fflag = 0; 130 if (Fflag == 1 && iflag == 0) { 131 fflag = 1; 132 wflag = 0; /* Implied when fflag != 0 */ 133 } 134 135 switch(argc) { 136 case 0: 137 usage(); 138 /* NOTREACHED */ 139 case 1: /* ln source */ 140 exit(linkit(argv[0], ".", 1)); 141 case 2: /* ln source target */ 142 exit(linkit(argv[0], argv[1], 0)); 143 default: 144 ; 145 } 146 /* ln source1 source2 directory */ 147 targetdir = argv[argc - 1]; 148 if (hflag && lstat(targetdir, &sb) == 0 && S_ISLNK(sb.st_mode)) { 149 /* 150 * We were asked not to follow symlinks, but found one at 151 * the target--simulate "not a directory" error 152 */ 153 errno = ENOTDIR; 154 err(1, "%s", targetdir); 155 } 156 if (stat(targetdir, &sb)) 157 err(1, "%s", targetdir); 158 if (!S_ISDIR(sb.st_mode)) 159 usage(); 160 for (exitval = 0; *argv != targetdir; ++argv) 161 exitval |= linkit(*argv, targetdir, 1); 162 exit(exitval); 163 } 164 165 /* 166 * Two pathnames refer to the same directory entry if the directories match 167 * and the final components' names match. 168 */ 169 static int 170 samedirent(const char *path1, const char *path2) 171 { 172 const char *file1, *file2; 173 char pathbuf[PATH_MAX]; 174 struct stat sb1, sb2; 175 176 if (strcmp(path1, path2) == 0) 177 return 1; 178 file1 = strrchr(path1, '/'); 179 if (file1 != NULL) 180 file1++; 181 else 182 file1 = path1; 183 file2 = strrchr(path2, '/'); 184 if (file2 != NULL) 185 file2++; 186 else 187 file2 = path2; 188 if (strcmp(file1, file2) != 0) 189 return 0; 190 if (file1 - path1 >= PATH_MAX || file2 - path2 >= PATH_MAX) 191 return 0; 192 if (file1 == path1) 193 memcpy(pathbuf, ".", 2); 194 else { 195 memcpy(pathbuf, path1, file1 - path1); 196 pathbuf[file1 - path1] = '\0'; 197 } 198 if (stat(pathbuf, &sb1) != 0) 199 return 0; 200 if (file2 == path2) 201 memcpy(pathbuf, ".", 2); 202 else { 203 memcpy(pathbuf, path2, file2 - path2); 204 pathbuf[file2 - path2] = '\0'; 205 } 206 if (stat(pathbuf, &sb2) != 0) 207 return 0; 208 return sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; 209 } 210 211 static int 212 linkit(const char *source, const char *target, int isdir) 213 { 214 struct stat sb; 215 const char *p; 216 int ch, exists, first; 217 char path[PATH_MAX]; 218 char wbuf[PATH_MAX]; 219 char bbuf[PATH_MAX]; 220 221 if (!sflag) { 222 /* If source doesn't exist, quit now. */ 223 if ((Pflag ? lstat : stat)(source, &sb)) { 224 warn("%s", source); 225 return (1); 226 } 227 /* Only symbolic links to directories. */ 228 if (S_ISDIR(sb.st_mode)) { 229 errno = EISDIR; 230 warn("%s", source); 231 return (1); 232 } 233 } 234 235 /* 236 * If the target is a directory (and not a symlink if hflag), 237 * append the source's name. 238 */ 239 if (isdir || 240 (lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) || 241 (!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) { 242 if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) || 243 (p = basename(bbuf)) == NULL || 244 snprintf(path, sizeof(path), "%s/%s", target, p) >= 245 (ssize_t)sizeof(path)) { 246 errno = ENAMETOOLONG; 247 warn("%s", source); 248 return (1); 249 } 250 target = path; 251 } 252 253 /* 254 * If the link source doesn't exist, and a symbolic link was 255 * requested, and -w was specified, give a warning. 256 */ 257 if (sflag && wflag) { 258 if (*source == '/') { 259 /* Absolute link source. */ 260 if (stat(source, &sb) != 0) 261 warn("warning: %s inaccessible", source); 262 } else { 263 /* 264 * Relative symlink source. Try to construct the 265 * absolute path of the source, by appending `source' 266 * to the parent directory of the target. 267 */ 268 strlcpy(bbuf, target, sizeof(bbuf)); 269 p = dirname(bbuf); 270 if (p != NULL) { 271 snprintf(wbuf, sizeof(wbuf), "%s/%s", 272 p, source); 273 if (stat(wbuf, &sb) != 0) 274 warn("warning: %s", source); 275 } 276 } 277 } 278 279 /* 280 * If the file exists, first check it is not the same directory entry. 281 */ 282 exists = !lstat(target, &sb); 283 if (exists) { 284 if (!sflag && samedirent(source, target)) { 285 warnx("%s and %s are the same directory entry", 286 source, target); 287 return (1); 288 } 289 } 290 /* 291 * Then unlink it forcibly if -f was specified 292 * and interactively if -i was specified. 293 */ 294 if (fflag && exists) { 295 if (Fflag && S_ISDIR(sb.st_mode)) { 296 if (rmdir(target)) { 297 warn("%s", target); 298 return (1); 299 } 300 } else if (unlink(target)) { 301 warn("%s", target); 302 return (1); 303 } 304 } else if (iflag && exists) { 305 fflush(stdout); 306 fprintf(stderr, "replace %s? ", target); 307 308 first = ch = getchar(); 309 while(ch != '\n' && ch != EOF) 310 ch = getchar(); 311 if (first != 'y' && first != 'Y') { 312 fprintf(stderr, "not replaced\n"); 313 return (1); 314 } 315 316 if (Fflag && S_ISDIR(sb.st_mode)) { 317 if (rmdir(target)) { 318 warn("%s", target); 319 return (1); 320 } 321 } else if (unlink(target)) { 322 warn("%s", target); 323 return (1); 324 } 325 } 326 327 /* Attempt the link. */ 328 if (sflag ? symlink(source, target) : 329 linkat(AT_FDCWD, source, AT_FDCWD, target, 330 Pflag ? 0 : AT_SYMLINK_FOLLOW)) { 331 warn("%s", target); 332 return (1); 333 } 334 if (vflag) 335 printf("%s %c> %s\n", target, linkch, source); 336 return (0); 337 } 338 339 static void 340 usage(void) 341 { 342 fprintf(stderr, "%s\n%s\n%s\n", 343 "usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]", 344 " ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir", 345 " link source_file target_file"); 346 exit(1); 347 } 348