ln.c revision 76877
1139749Simp/* 2117632Sharti * Copyright (c) 1987, 1993, 1994 3117632Sharti * The Regents of the University of California. All rights reserved. 4117632Sharti * 5117632Sharti * Redistribution and use in source and binary forms, with or without 6117632Sharti * modification, are permitted provided that the following conditions 7117632Sharti * are met: 8117632Sharti * 1. Redistributions of source code must retain the above copyright 9117632Sharti * notice, this list of conditions and the following disclaimer. 10117632Sharti * 2. Redistributions in binary form must reproduce the above copyright 11117632Sharti * notice, this list of conditions and the following disclaimer in the 12117632Sharti * documentation and/or other materials provided with the distribution. 13117632Sharti * 3. All advertising materials mentioning features or use of this software 14117632Sharti * must display the following acknowledgement: 15117632Sharti * This product includes software developed by the University of 16117632Sharti * California, Berkeley and its contributors. 17117632Sharti * 4. Neither the name of the University nor the names of its contributors 18117632Sharti * may be used to endorse or promote products derived from this software 19117632Sharti * without specific prior written permission. 20117632Sharti * 21117632Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24117632Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31117632Sharti * SUCH DAMAGE. 32117632Sharti */ 33117632Sharti 34117632Sharti#ifndef lint 35117632Shartistatic char const copyright[] = 36117632Sharti"@(#) Copyright (c) 1987, 1993, 1994\n\ 37117632Sharti The Regents of the University of California. All rights reserved.\n"; 38117632Sharti#endif /* not lint */ 39119418Sobrien 40117632Sharti#ifndef lint 41117632Sharti#if 0 42117632Shartistatic char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; 43117632Sharti#endif 44117632Shartistatic const char rcsid[] = 45117632Sharti "$FreeBSD: head/bin/ln/ln.c 76877 2001-05-20 04:54:15Z kris $"; 46117632Sharti#endif /* not lint */ 47117632Sharti 48117632Sharti#include <sys/param.h> 49117632Sharti#include <sys/stat.h> 50117632Sharti 51117632Sharti#include <err.h> 52117632Sharti#include <errno.h> 53117632Sharti#include <stdio.h> 54117632Sharti#include <stdlib.h> 55117632Sharti#include <string.h> 56117632Sharti#include <unistd.h> 57117632Sharti 58117632Shartiint fflag; /* Unlink existing files. */ 59117632Shartiint hflag; /* Check new name for symlink first. */ 60117632Shartiint iflag; /* Interactive mode. */ 61117632Shartiint sflag; /* Symbolic, not hard, link. */ 62117632Shartiint vflag; /* Verbose output. */ 63117632Sharti /* System link call. */ 64117632Shartiint (*linkf) __P((const char *, const char *)); 65117632Shartichar linkch; 66117632Sharti 67117632Shartiint linkit __P((const char *, const char *, int)); 68117632Shartiint main __P((int, char *[])); 69117632Shartivoid usage __P((void)); 70117632Sharti 71117632Shartiint 72117632Shartimain(argc, argv) 73117632Sharti int argc; 74117632Sharti char *argv[]; 75117632Sharti{ 76117632Sharti struct stat sb; 77117632Sharti char *p, *sourcedir; 78117632Sharti int ch, exitval; 79117632Sharti 80117632Sharti /* 81117632Sharti * Test for the special case where the utility is called as 82117632Sharti * "link", for which the functionality provided is greatly 83117632Sharti * simplified. 84117632Sharti */ 85117632Sharti if ((p = rindex(argv[0], '/')) == NULL) 86117632Sharti p = argv[0]; 87117632Sharti else 88117632Sharti ++p; 89117632Sharti if (strcmp(p, "link") == 0) { 90117632Sharti if (argc == 3) { 91117632Sharti linkf = link; 92117632Sharti exit(linkit(argv[1], argv[2], 0)); 93117632Sharti } else 94117632Sharti usage(); 95117632Sharti } 96117632Sharti 97117632Sharti while ((ch = getopt(argc, argv, "fhinsv")) != -1) 98117632Sharti switch (ch) { 99117632Sharti case 'f': 100117632Sharti fflag = 1; 101117632Sharti iflag = 0; 102117632Sharti break; 103117632Sharti case 'h': 104117632Sharti case 'n': 105117632Sharti hflag = 1; 106117632Sharti break; 107117632Sharti case 'i': 108117632Sharti iflag = 1; 109117632Sharti fflag = 0; 110117632Sharti break; 111117632Sharti case 's': 112117632Sharti sflag = 1; 113117632Sharti break; 114117632Sharti case 'v': 115117632Sharti vflag = 1; 116117632Sharti break; 117117632Sharti case '?': 118117632Sharti default: 119117632Sharti usage(); 120117632Sharti } 121117632Sharti 122147256Sbrooks argv += optind; 123117632Sharti argc -= optind; 124117632Sharti 125117632Sharti linkf = sflag ? symlink : link; 126117632Sharti linkch = sflag ? '-' : '='; 127117632Sharti 128147256Sbrooks switch(argc) { 129117632Sharti case 0: 130117632Sharti usage(); 131117632Sharti /* NOTREACHED */ 132117632Sharti case 1: /* ln target */ 133117632Sharti exit(linkit(argv[0], ".", 1)); 134117632Sharti case 2: /* ln target source */ 135117632Sharti exit(linkit(argv[0], argv[1], 0)); 136117632Sharti } 137117632Sharti /* ln target1 target2 directory */ 138117632Sharti sourcedir = argv[argc - 1]; 139117632Sharti if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { 140117632Sharti /* 141117632Sharti * We were asked not to follow symlinks, but found one at 142117632Sharti * the target--simulate "not a directory" error 143117632Sharti */ 144117632Sharti errno = ENOTDIR; 145117632Sharti err(1, "%s", sourcedir); 146117632Sharti } 147117632Sharti if (stat(sourcedir, &sb)) 148117632Sharti err(1, "%s", sourcedir); 149117632Sharti if (!S_ISDIR(sb.st_mode)) 150117632Sharti usage(); 151117632Sharti for (exitval = 0; *argv != sourcedir; ++argv) 152147256Sbrooks exitval |= linkit(*argv, sourcedir, 1); 153117632Sharti exit(exitval); 154117632Sharti} 155117632Sharti 156117632Shartiint 157117632Shartilinkit(target, source, isdir) 158117632Sharti const char *target, *source; 159117632Sharti int isdir; 160117632Sharti{ 161117632Sharti struct stat sb; 162117632Sharti const char *p; 163117632Sharti char path[MAXPATHLEN]; 164147256Sbrooks int ch, exists, first; 165117632Sharti 166117632Sharti if (!sflag) { 167117632Sharti /* If target doesn't exist, quit now. */ 168117632Sharti if (stat(target, &sb)) { 169117632Sharti warn("%s", target); 170117632Sharti return (1); 171117632Sharti } 172117632Sharti /* Only symbolic links to directories. */ 173117632Sharti if (S_ISDIR(sb.st_mode)) { 174117632Sharti errno = EISDIR; 175117632Sharti warn("%s", target); 176117632Sharti return (1); 177117632Sharti } 178117632Sharti } 179117632Sharti 180117632Sharti /* 181117632Sharti * If the source is a directory (and not a symlink if hflag), 182117632Sharti * append the target's name. 183117632Sharti */ 184117632Sharti if (isdir || 185117632Sharti (lstat(source, &sb) == 0 && S_ISDIR(sb.st_mode)) || 186117632Sharti (!hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) { 187117632Sharti if ((p = strrchr(target, '/')) == NULL) 188117632Sharti p = target; 189117632Sharti else 190117632Sharti ++p; 191117632Sharti (void)snprintf(path, sizeof(path), "%s/%s", source, p); 192117632Sharti source = path; 193117632Sharti } 194117632Sharti 195117632Sharti exists = !lstat(source, &sb); 196117632Sharti /* 197117632Sharti * If the file exists, then unlink it forcibly if -f was specified 198117632Sharti * and interactively if -i was specified. 199117632Sharti */ 200117632Sharti if (fflag && exists) { 201117632Sharti if (unlink(source)) { 202117632Sharti warn("%s", source); 203117632Sharti return (1); 204117632Sharti } 205117632Sharti } else if (iflag && exists) { 206117632Sharti fflush(stdout); 207117632Sharti fprintf(stderr, "replace %s? ", source); 208117632Sharti 209117632Sharti first = ch = getchar(); 210117632Sharti while(ch != '\n' && ch != EOF) 211117632Sharti ch = getchar(); 212117632Sharti if (first != 'y' && first != 'Y') { 213117632Sharti fprintf(stderr, "not replaced\n"); 214117632Sharti return (1); 215117632Sharti } 216117632Sharti 217117632Sharti if (unlink(source)) { 218117632Sharti warn("%s", source); 219117632Sharti return (1); 220117632Sharti } 221117632Sharti } 222117632Sharti 223117632Sharti /* Attempt the link. */ 224117632Sharti if ((*linkf)(target, source)) { 225117632Sharti warn("%s", source); 226117632Sharti return (1); 227117632Sharti } 228117632Sharti if (vflag) 229117632Sharti (void)printf("%s %c> %s\n", source, linkch, target); 230117632Sharti return (0); 231117632Sharti} 232117632Sharti 233117632Shartivoid 234117632Shartiusage() 235117632Sharti{ 236117632Sharti (void)fprintf(stderr, "%s\n%s\n%s\n", 237117632Sharti "usage: ln [-fhinsv] file1 file2", 238117632Sharti " ln [-fhinsv] file ... directory", 239117632Sharti " link file1 file2"); 240117632Sharti exit(1); 241117632Sharti} 242117632Sharti