ln.c revision 97531
11556Srgrimes/* 21556Srgrimes * Copyright (c) 1987, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 3. All advertising materials mentioning features or use of this software 141556Srgrimes * must display the following acknowledgement: 151556Srgrimes * This product includes software developed by the University of 161556Srgrimes * California, Berkeley and its contributors. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3520420Sstevestatic char const copyright[] = 361556Srgrimes"@(#) Copyright (c) 1987, 1993, 1994\n\ 371556Srgrimes The Regents of the University of California. All rights reserved.\n"; 381556Srgrimes#endif /* not lint */ 391556Srgrimes 401556Srgrimes#ifndef lint 4136046Scharnier#if 0 4236046Scharnierstatic char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; 4336046Scharnier#endif 4436046Scharnierstatic const char rcsid[] = 4550471Speter "$FreeBSD: head/bin/ln/ln.c 97531 2002-05-30 00:57:38Z tjr $"; 461556Srgrimes#endif /* not lint */ 471556Srgrimes 481556Srgrimes#include <sys/param.h> 491556Srgrimes#include <sys/stat.h> 501556Srgrimes 511556Srgrimes#include <err.h> 521556Srgrimes#include <errno.h> 5377404Simp#include <limits.h> 541556Srgrimes#include <stdio.h> 551556Srgrimes#include <stdlib.h> 561556Srgrimes#include <string.h> 571556Srgrimes#include <unistd.h> 581556Srgrimes 591556Srgrimesint fflag; /* Unlink existing files. */ 6076039Ssobomaxint hflag; /* Check new name for symlink first. */ 6164638Ssheldonhint iflag; /* Interactive mode. */ 621556Srgrimesint sflag; /* Symbolic, not hard, link. */ 6351148Sobrienint vflag; /* Verbose output. */ 641556Srgrimes /* System link call. */ 6590110Simpint (*linkf)(const char *, const char *); 6651148Sobrienchar linkch; 671556Srgrimes 6890110Simpint linkit(const char *, const char *, int); 6990110Simpvoid usage(void); 701556Srgrimes 711556Srgrimesint 7290110Simpmain(int argc, char *argv[]) 731556Srgrimes{ 741556Srgrimes struct stat sb; 7576877Skris char *p, *sourcedir; 761556Srgrimes int ch, exitval; 771556Srgrimes 7854895Ssheldonh /* 7954895Ssheldonh * Test for the special case where the utility is called as 8054895Ssheldonh * "link", for which the functionality provided is greatly 8154895Ssheldonh * simplified. 8254895Ssheldonh */ 8354895Ssheldonh if ((p = rindex(argv[0], '/')) == NULL) 8454895Ssheldonh p = argv[0]; 8554895Ssheldonh else 8654895Ssheldonh ++p; 8754895Ssheldonh if (strcmp(p, "link") == 0) { 8897531Stjr while (getopt(argc, argv, "") != -1) 8954895Ssheldonh usage(); 9097531Stjr argc -= optind; 9197531Stjr argv += optind; 9297531Stjr if (argc != 2) 9397531Stjr usage(); 9497531Stjr linkf = link; 9597531Stjr exit(linkit(argv[0], argv[1], 0)); 9654895Ssheldonh } 9754895Ssheldonh 9876039Ssobomax while ((ch = getopt(argc, argv, "fhinsv")) != -1) 991556Srgrimes switch (ch) { 1001556Srgrimes case 'f': 1011556Srgrimes fflag = 1; 10264787Ssheldonh iflag = 0; 1031556Srgrimes break; 10476039Ssobomax case 'h': 10576039Ssobomax case 'n': 10676039Ssobomax hflag = 1; 10776039Ssobomax break; 10864638Ssheldonh case 'i': 10964638Ssheldonh iflag = 1; 11064787Ssheldonh fflag = 0; 11164638Ssheldonh break; 1121556Srgrimes case 's': 1131556Srgrimes sflag = 1; 1141556Srgrimes break; 11551148Sobrien case 'v': 11651148Sobrien vflag = 1; 11751148Sobrien break; 1181556Srgrimes case '?': 1191556Srgrimes default: 1201556Srgrimes usage(); 1211556Srgrimes } 1221556Srgrimes 1231556Srgrimes argv += optind; 1241556Srgrimes argc -= optind; 1251556Srgrimes 1261556Srgrimes linkf = sflag ? symlink : link; 12751148Sobrien linkch = sflag ? '-' : '='; 1281556Srgrimes 1291556Srgrimes switch(argc) { 1301556Srgrimes case 0: 1311556Srgrimes usage(); 13276039Ssobomax /* NOTREACHED */ 1331556Srgrimes case 1: /* ln target */ 1341556Srgrimes exit(linkit(argv[0], ".", 1)); 1351556Srgrimes case 2: /* ln target source */ 1361556Srgrimes exit(linkit(argv[0], argv[1], 0)); 13791084Smarkm default: 13896373Sjedgar ; 1391556Srgrimes } 1401556Srgrimes /* ln target1 target2 directory */ 1411556Srgrimes sourcedir = argv[argc - 1]; 14276039Ssobomax if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { 14376039Ssobomax /* 14476039Ssobomax * We were asked not to follow symlinks, but found one at 14576039Ssobomax * the target--simulate "not a directory" error 14676039Ssobomax */ 14776039Ssobomax errno = ENOTDIR; 14876039Ssobomax err(1, "%s", sourcedir); 14976039Ssobomax } 1501556Srgrimes if (stat(sourcedir, &sb)) 1511556Srgrimes err(1, "%s", sourcedir); 1521556Srgrimes if (!S_ISDIR(sb.st_mode)) 1531556Srgrimes usage(); 1541556Srgrimes for (exitval = 0; *argv != sourcedir; ++argv) 1551556Srgrimes exitval |= linkit(*argv, sourcedir, 1); 1561556Srgrimes exit(exitval); 1571556Srgrimes} 1581556Srgrimes 1591556Srgrimesint 16090110Simplinkit(const char *target, const char *source, int isdir) 1611556Srgrimes{ 1621556Srgrimes struct stat sb; 16376877Skris const char *p; 16464787Ssheldonh int ch, exists, first; 16577404Simp char path[PATH_MAX]; 1661556Srgrimes 1671556Srgrimes if (!sflag) { 1681556Srgrimes /* If target doesn't exist, quit now. */ 1691556Srgrimes if (stat(target, &sb)) { 1701556Srgrimes warn("%s", target); 1711556Srgrimes return (1); 1721556Srgrimes } 17315900Speter /* Only symbolic links to directories. */ 17415900Speter if (S_ISDIR(sb.st_mode)) { 17515900Speter errno = EISDIR; 17615900Speter warn("%s", target); 1771556Srgrimes return (1); 1781556Srgrimes } 1791556Srgrimes } 1801556Srgrimes 18176039Ssobomax /* 18276039Ssobomax * If the source is a directory (and not a symlink if hflag), 18376039Ssobomax * append the target's name. 18476039Ssobomax */ 18576039Ssobomax if (isdir || 18676039Ssobomax (lstat(source, &sb) == 0 && S_ISDIR(sb.st_mode)) || 18776039Ssobomax (!hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) { 1881556Srgrimes if ((p = strrchr(target, '/')) == NULL) 1891556Srgrimes p = target; 1901556Srgrimes else 1911556Srgrimes ++p; 1921556Srgrimes (void)snprintf(path, sizeof(path), "%s/%s", source, p); 1931556Srgrimes source = path; 19476039Ssobomax } 1951556Srgrimes 19676039Ssobomax exists = !lstat(source, &sb); 1971556Srgrimes /* 19864787Ssheldonh * If the file exists, then unlink it forcibly if -f was specified 19964787Ssheldonh * and interactively if -i was specified. 2001556Srgrimes */ 20164787Ssheldonh if (fflag && exists) { 20264787Ssheldonh if (unlink(source)) { 20364787Ssheldonh warn("%s", source); 20464787Ssheldonh return (1); 20564787Ssheldonh } 20664638Ssheldonh } else if (iflag && exists) { 20764787Ssheldonh fflush(stdout); 20864638Ssheldonh fprintf(stderr, "replace %s? ", source); 20964638Ssheldonh 21064638Ssheldonh first = ch = getchar(); 21164638Ssheldonh while(ch != '\n' && ch != EOF) 21264638Ssheldonh ch = getchar(); 21364787Ssheldonh if (first != 'y' && first != 'Y') { 21464787Ssheldonh fprintf(stderr, "not replaced\n"); 21564787Ssheldonh return (1); 21664787Ssheldonh } 21764638Ssheldonh 21864787Ssheldonh if (unlink(source)) { 21964638Ssheldonh warn("%s", source); 22064638Ssheldonh return (1); 22164638Ssheldonh } 2221556Srgrimes } 22364787Ssheldonh 22464787Ssheldonh /* Attempt the link. */ 22564638Ssheldonh if ((*linkf)(target, source)) { 22664638Ssheldonh warn("%s", source); 22764638Ssheldonh return (1); 22864638Ssheldonh } 22951148Sobrien if (vflag) 23051148Sobrien (void)printf("%s %c> %s\n", source, linkch, target); 2311556Srgrimes return (0); 2321556Srgrimes} 2331556Srgrimes 2341556Srgrimesvoid 23590110Simpusage(void) 2361556Srgrimes{ 23754895Ssheldonh (void)fprintf(stderr, "%s\n%s\n%s\n", 23876039Ssobomax "usage: ln [-fhinsv] file1 file2", 23976039Ssobomax " ln [-fhinsv] file ... directory", 24054895Ssheldonh " link file1 file2"); 2411556Srgrimes exit(1); 2421556Srgrimes} 243