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