1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ln.c 5.1 (Berkeley) 04/29/93"; 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 force flag. */ 29 sflag, /* Symbolic, not hard, link. */ 30 /* System link call. */ 31 (*linkf) __P((const char *, const char *)); 32 33 static int linkit __P((char *, char *, int)); 34 static void usage __P((void)); 35 36 int 37 main(argc, argv) 38 int argc; 39 char *argv[]; 40 { 41 extern int optind; 42 struct stat sb; 43 int ch, exitval; 44 char *sourcedir; 45 46 while ((ch = getopt(argc, argv, "Fs")) != EOF) 47 switch((char)ch) { 48 case 'F': 49 dirflag = 1; 50 break; 51 case 's': 52 sflag = 1; 53 break; 54 case '?': 55 default: 56 usage(); 57 } 58 59 argv += optind; 60 argc -= optind; 61 62 linkf = sflag ? symlink : link; 63 64 switch(argc) { 65 case 0: 66 usage(); 67 case 1: /* ln target */ 68 exit(linkit(argv[0], ".", 1)); 69 case 2: /* ln target source */ 70 exit(linkit(argv[0], argv[1], 0)); 71 } 72 /* ln target1 target2 directory */ 73 sourcedir = argv[argc - 1]; 74 if (stat(sourcedir, &sb)) 75 err(1, "%s", sourcedir); 76 if (!S_ISDIR(sb.st_mode)) 77 usage(); 78 for (exitval = 0; *argv != sourcedir; ++argv) 79 exitval |= linkit(*argv, sourcedir, 1); 80 exit(exitval); 81 } 82 83 static int 84 linkit(target, source, isdir) 85 char *target, *source; 86 int isdir; 87 { 88 struct stat sb; 89 char path[MAXPATHLEN], *p; 90 91 if (!sflag) { 92 /* if target doesn't exist, quit now */ 93 if (stat(target, &sb)) { 94 warn("%s", target); 95 return (1); 96 } 97 /* only symbolic links to directories, unless -F option used */ 98 if (!dirflag && (sb.st_mode & S_IFMT) == S_IFDIR) { 99 warnx("%s: is a directory", target); 100 return (1); 101 } 102 } 103 104 /* if the source is a directory, append the target's name */ 105 if (isdir || !stat(source, &sb) && (sb.st_mode & S_IFMT) == S_IFDIR) { 106 if (!(p = strrchr(target, '/'))) 107 p = target; 108 else 109 ++p; 110 (void)snprintf(path, sizeof(path), "%s/%s", source, p); 111 source = path; 112 } 113 114 if ((*linkf)(target, source)) { 115 warn("%s", source); 116 return (1); 117 } 118 return (0); 119 } 120 121 static void 122 usage() 123 { 124 (void)fprintf(stderr, 125 "usage:\tln [-s] file1 file2\n\tln [-s] file ... directory\n"); 126 exit(1); 127 } 128