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