1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * 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 35 char copyright[] = 36 "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)ln.c 4.15 (Berkeley) 2/24/91";*/ 42 static char rcsid[] = "$Id: ln.c,v 1.8 1994/02/08 05:09:26 mycroft Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <stdio.h> 48 #include <errno.h> 49 #include <string.h> 50 #include <stdlib.h> 51 #include <unistd.h> 52 #include <err.h> 53 54 static int forceflag, /* force link by removing target */ 55 dirflag, /* allow hard links to directories */ 56 sflag, /* symbolic, not hard, link */ 57 (*linkf)(); /* system link call */ 58 static int linkit(); 59 static void usage(); 60 61 int 62 main(argc, argv) 63 int argc; 64 char **argv; 65 { 66 extern int optind; 67 struct stat buf; 68 int ch, exitval; 69 char *sourcedir; 70 71 while ((ch = getopt(argc, argv, "fFs")) != EOF) 72 switch((char)ch) { 73 case 'f': 74 forceflag = 1; 75 break; 76 case 'F': 77 dirflag = 1; 78 break; 79 case 's': 80 sflag = 1; 81 break; 82 case '?': 83 default: 84 usage(); 85 } 86 87 argv += optind; 88 argc -= optind; 89 90 linkf = sflag ? symlink : link; 91 92 switch(argc) { 93 case 0: 94 usage(); 95 /* NOTREACHED */ 96 case 1: /* ln target */ 97 exit(linkit(argv[0], ".", 1)); 98 /* NOTREACHED */ 99 case 2: /* ln target source */ 100 exit(linkit(argv[0], argv[1], 0)); 101 /* NOTREACHED */ 102 default: /* ln target1 target2 directory */ 103 sourcedir = argv[argc - 1]; 104 if (stat(sourcedir, &buf)) { 105 err(1, "%s", sourcedir); 106 /* NOTREACHED */ 107 } 108 if (!S_ISDIR(buf.st_mode)) 109 usage(); 110 for (exitval = 0; *argv != sourcedir; ++argv) 111 exitval |= linkit(*argv, sourcedir, 1); 112 exit(exitval); 113 } 114 /* NOTREACHED */ 115 } 116 117 static int 118 linkit(source, target, isdir) 119 char *source, *target; 120 int isdir; 121 { 122 struct stat buf; 123 char path[MAXPATHLEN], *cp; 124 125 if (!sflag) { 126 /* if source doesn't exist, quit now */ 127 if (stat(source, &buf)) { 128 warn("%s", source); 129 return(1); 130 } 131 /* only symbolic links to directories, unless -F option used */ 132 if (!dirflag && S_ISDIR(buf.st_mode)) { 133 warnx("%s: %s", source, strerror(EISDIR)); 134 return(1); 135 } 136 } 137 138 /* if the target is a directory, append the source's name */ 139 if (isdir || !stat(target, &buf) && S_ISDIR(buf.st_mode)) { 140 if (!(cp = rindex(source, '/'))) 141 cp = source; 142 else 143 ++cp; 144 (void)sprintf(path, "%s/%s", target, cp); 145 target = path; 146 } 147 148 /* Remove existing file if -f is was specified */ 149 if (forceflag && unlink (target) && errno != ENOENT) { 150 warn("%s", target); 151 return (1); 152 } 153 154 if ((*linkf)(source, target)) { 155 warn("%s", target); 156 return(1); 157 } 158 159 return(0); 160 } 161 162 static void 163 usage() 164 { 165 (void)fprintf(stderr, 166 "usage:\tln [-fs] file1 file2\n\tln [-fs] file ... directory\n"); 167 exit(1); 168 } 169