xref: /original-bsd/bin/ln/ln.c (revision 75ddeb8f)
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