xref: /original-bsd/bin/ln/ln.c (revision ad93c43e)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific written prior permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 char copyright[] =
15 "@(#) Copyright (c) 1987 Regents of the University of California.\n\
16  All rights reserved.\n";
17 #endif /* not lint */
18 
19 #ifndef lint
20 static char sccsid[] = "@(#)ln.c	4.10 (Berkeley) 11/30/87";
21 #endif /* not lint */
22 
23 #include <sys/param.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #include <errno.h>
27 
28 static int	fflag,				/* undocumented force flag */
29 		sflag,				/* symbolic, not hard, link */
30 		(*linkf)();			/* system link call */
31 
32 main(argc, argv)
33 	int	argc;
34 	char	**argv;
35 {
36 	extern int	optind;
37 	struct stat	buf;
38 	int	ch, exitval, link(), symlink();
39 	char	*sourcedir;
40 
41 	while ((ch = getopt(argc, argv, "fs")) != EOF)
42 		switch((char)ch) {
43 		case 'f':
44 			fflag = 1;
45 			break;
46 		case 's':
47 			sflag = 1;
48 			break;
49 		case '?':
50 		default:
51 			usage();
52 		}
53 
54 	argv += optind;
55 	argc -= optind;
56 
57 	linkf = sflag ? symlink : link;
58 
59 	switch(argc) {
60 	case 0:
61 		usage();
62 	case 1:				/* ln target */
63 		exit(linkit(argv[0], ".", 1));
64 	case 2:				/* ln target source */
65 		exit(linkit(argv[0], argv[1], 0));
66 	default:			/* ln target1 target2 directory */
67 		sourcedir = argv[argc - 1];
68 		if (stat(sourcedir, &buf)) {
69 			perror(sourcedir);
70 			exit(1);
71 		}
72 		if ((buf.st_mode & S_IFMT) != S_IFDIR)
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 	extern int	errno;
87 	struct stat	buf;
88 	char	path[MAXPATHLEN],
89 		*cp, *rindex(), *strcpy();
90 
91 	if (!sflag) {
92 		/* if target doesn't exist, quit now */
93 		if (stat(target, &buf)) {
94 			perror(target);
95 			return(1);
96 		}
97 		/* only symbolic links to directories, unless -f option used */
98 		if (!fflag && (buf.st_mode & S_IFMT) == S_IFDIR) {
99 			printf("%s is a directory.\n", target);
100 			return(1);
101 		}
102 	}
103 
104 	/* if the source is a directory, append the target's name */
105 	if (isdir || !stat(source, &buf) && (buf.st_mode & S_IFMT) == S_IFDIR) {
106 		if (!(cp = rindex(target, '/')))
107 			cp = target;
108 		else
109 			++cp;
110 		(void)sprintf(path, "%s/%s", source, cp);
111 		source = path;
112 	}
113 
114 	if ((*linkf)(target, source)) {
115 		perror(source);
116 		return(1);
117 	}
118 	return(0);
119 }
120 
121 static
122 usage()
123 {
124 	fputs("usage:\tln [-s] targetname [sourcename]\n\tln [-s] targetname1 targetname2 [... targetnameN] sourcedirectory\n", stderr);
125 	exit(1);
126 }
127