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