1 /* 2 * Copyright (c) 1987, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1987, 1993, 1994\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 03/31/94"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 21 #include <err.h> 22 #include <errno.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 int dirflag; /* Undocumented directory flag. */ 29 int fflag; /* Unlink existing files. */ 30 int sflag; /* Symbolic, not hard, link. */ 31 /* System link call. */ 32 int (*linkf) __P((const char *, const char *)); 33 34 int linkit __P((char *, char *, int)); 35 void usage __P((void)); 36 37 int 38 main(argc, argv) 39 int argc; 40 char *argv[]; 41 { 42 extern int optind; 43 struct stat sb; 44 int ch, exitval; 45 char *sourcedir; 46 47 while ((ch = getopt(argc, argv, "Ffs")) != EOF) 48 switch (ch) { 49 case 'F': 50 dirflag = 1; /* XXX: deliberately undocumented. */ 51 break; 52 case 'f': 53 fflag = 1; 54 break; 55 case 's': 56 sflag = 1; 57 break; 58 case '?': 59 default: 60 usage(); 61 } 62 63 argv += optind; 64 argc -= optind; 65 66 linkf = sflag ? symlink : link; 67 68 switch(argc) { 69 case 0: 70 usage(); 71 case 1: /* ln target */ 72 exit(linkit(argv[0], ".", 1)); 73 case 2: /* ln target source */ 74 exit(linkit(argv[0], argv[1], 0)); 75 } 76 /* ln target1 target2 directory */ 77 sourcedir = argv[argc - 1]; 78 if (stat(sourcedir, &sb)) 79 err(1, "%s", sourcedir); 80 if (!S_ISDIR(sb.st_mode)) 81 usage(); 82 for (exitval = 0; *argv != sourcedir; ++argv) 83 exitval |= linkit(*argv, sourcedir, 1); 84 exit(exitval); 85 } 86 87 int 88 linkit(target, source, isdir) 89 char *target, *source; 90 int isdir; 91 { 92 struct stat sb; 93 int exists; 94 char *p, path[MAXPATHLEN]; 95 96 if (!sflag) { 97 /* If target doesn't exist, quit now. */ 98 if (stat(target, &sb)) { 99 warn("%s", target); 100 return (1); 101 } 102 /* Only symbolic links to directories, unless -F option used. */ 103 if (!dirflag && (sb.st_mode & S_IFMT) == S_IFDIR) { 104 warnx("%s: is a directory", target); 105 return (1); 106 } 107 } 108 109 /* If the source is a directory, append the target's name. */ 110 if (isdir || (exists = !stat(source, &sb)) && S_ISDIR(sb.st_mode)) { 111 if ((p = strrchr(target, '/')) == NULL) 112 p = target; 113 else 114 ++p; 115 (void)snprintf(path, sizeof(path), "%s/%s", source, p); 116 source = path; 117 exists = !stat(source, &sb); 118 } else 119 exists = !stat(source, &sb); 120 121 /* 122 * If the file exists, and -f was specified, unlink it. 123 * Attempt the link. 124 */ 125 if (fflag && exists && unlink(source) || (*linkf)(target, source)) { 126 warn("%s", source); 127 return (1); 128 } 129 return (0); 130 } 131 132 void 133 usage() 134 { 135 (void)fprintf(stderr, 136 "usage:\tln [-fs] file1 file2\n\tln [-fs] file ... directory\n"); 137 exit(1); 138 } 139