xref: /original-bsd/bin/ln/ln.c (revision 05598ce3)
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	4.15 (Berkeley) 02/24/91";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 
26 static int	dirflag,			/* undocumented force flag */
27 		sflag,				/* symbolic, not hard, link */
28 		(*linkf)();			/* system link call */
29 static linkit(), usage();
30 
31 main(argc, argv)
32 	int argc;
33 	char **argv;
34 {
35 	extern int optind;
36 	struct stat buf;
37 	int ch, exitval, link(), symlink();
38 	char *sourcedir;
39 
40 	while ((ch = getopt(argc, argv, "Fs")) != EOF)
41 		switch((char)ch) {
42 		case 'F':
43 			dirflag = 1;
44 			break;
45 		case 's':
46 			sflag = 1;
47 			break;
48 		case '?':
49 		default:
50 			usage();
51 		}
52 
53 	argv += optind;
54 	argc -= optind;
55 
56 	linkf = sflag ? symlink : link;
57 
58 	switch(argc) {
59 	case 0:
60 		usage();
61 	case 1:				/* ln target */
62 		exit(linkit(argv[0], ".", 1));
63 	case 2:				/* ln target source */
64 		exit(linkit(argv[0], argv[1], 0));
65 	default:			/* ln target1 target2 directory */
66 		sourcedir = argv[argc - 1];
67 		if (stat(sourcedir, &buf)) {
68 			(void)fprintf(stderr,
69 			    "ln: %s: %s\n", sourcedir, strerror(errno));
70 			exit(1);
71 		}
72 		if (!S_ISDIR(buf.st_mode))
73 			usage();
74 		for (exitval = 0; *argv != sourcedir; ++argv)
75 			exitval |= linkit(*argv, sourcedir, 1);
76 		exit(exitval);
77 	}
78 	/* NOTREACHED */
79 }
80 
81 static
82 linkit(target, source, isdir)
83 	char *target, *source;
84 	int isdir;
85 {
86 	struct stat buf;
87 	char path[MAXPATHLEN], *cp;
88 
89 	if (!sflag) {
90 		/* if target doesn't exist, quit now */
91 		if (stat(target, &buf)) {
92 			(void)fprintf(stderr,
93 			    "ln: %s: %s\n", target, strerror(errno));
94 			return(1);
95 		}
96 		/* only symbolic links to directories, unless -F option used */
97 		if (!dirflag && (buf.st_mode & S_IFMT) == S_IFDIR) {
98 			(void)printf("ln: %s is a directory.\n", target);
99 			return(1);
100 		}
101 	}
102 
103 	/* if the source is a directory, append the target's name */
104 	if (isdir || !stat(source, &buf) && (buf.st_mode & S_IFMT) == S_IFDIR) {
105 		if (!(cp = rindex(target, '/')))
106 			cp = target;
107 		else
108 			++cp;
109 		(void)sprintf(path, "%s/%s", source, cp);
110 		source = path;
111 	}
112 
113 	if ((*linkf)(target, source)) {
114 		(void)fprintf(stderr, "ln: %s: %s\n", source, strerror(errno));
115 		return(1);
116 	}
117 	return(0);
118 }
119 
120 static
121 usage()
122 {
123 	(void)fprintf(stderr,
124 	    "usage:\tln [-s] file1 file2\n\tln [-s] file ... directory\n");
125 	exit(1);
126 }
127