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