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