xref: /csrg-svn/bin/ln/ln.c (revision 66536)
1617Sbill /*
2*66536Sbostic  * Copyright (c) 1987, 1993, 1994
360806Sbostic  *	The Regents of the University of California.  All rights reserved.
432722Sbostic  *
542736Sbostic  * %sccs.include.redist.c%
6617Sbill  */
732596Sbostic 
832722Sbostic #ifndef lint
960806Sbostic static char copyright[] =
10*66536Sbostic "@(#) Copyright (c) 1987, 1993, 1994\n\
1160806Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1232722Sbostic #endif /* not lint */
1332596Sbostic 
1432722Sbostic #ifndef lint
15*66536Sbostic static char sccsid[] = "@(#)ln.c	8.2 (Berkeley) 03/31/94";
1632722Sbostic #endif /* not lint */
1732596Sbostic 
1832596Sbostic #include <sys/param.h>
1932596Sbostic #include <sys/stat.h>
2059497Sbostic 
2159497Sbostic #include <err.h>
2259497Sbostic #include <errno.h>
23617Sbill #include <stdio.h>
2459497Sbostic #include <stdlib.h>
2545341Sbostic #include <string.h>
2646647Sdonn #include <unistd.h>
27617Sbill 
28*66536Sbostic int	dirflag;			/* Undocumented directory flag. */
29*66536Sbostic int	fflag;				/* Unlink existing files. */
30*66536Sbostic int	sflag;				/* Symbolic, not hard, link. */
3159497Sbostic 					/* System link call. */
32*66536Sbostic int (*linkf) __P((const char *, const char *));
33617Sbill 
34*66536Sbostic int	linkit __P((char *, char *, int));
35*66536Sbostic void	usage __P((void));
3659497Sbostic 
3759497Sbostic int
main(argc,argv)38617Sbill main(argc, argv)
3945341Sbostic 	int argc;
4059497Sbostic 	char *argv[];
41617Sbill {
4243268Sbostic 	extern int optind;
4359497Sbostic 	struct stat sb;
4459497Sbostic 	int ch, exitval;
4543268Sbostic 	char *sourcedir;
46617Sbill 
47*66536Sbostic 	while ((ch = getopt(argc, argv, "Ffs")) != EOF)
48*66536Sbostic 		switch (ch) {
4943268Sbostic 		case 'F':
50*66536Sbostic 			dirflag = 1;	/* XXX: deliberately undocumented. */
5132596Sbostic 			break;
52*66536Sbostic 		case 'f':
53*66536Sbostic 			fflag = 1;
54*66536Sbostic 			break;
5532596Sbostic 		case 's':
5632596Sbostic 			sflag = 1;
5732596Sbostic 			break;
5832596Sbostic 		case '?':
5932596Sbostic 		default:
6032596Sbostic 			usage();
6132596Sbostic 		}
6232596Sbostic 
6332596Sbostic 	argv += optind;
6432596Sbostic 	argc -= optind;
6532596Sbostic 
6632596Sbostic 	linkf = sflag ? symlink : link;
6732596Sbostic 
6832596Sbostic 	switch(argc) {
6932596Sbostic 	case 0:
7032596Sbostic 		usage();
7132596Sbostic 	case 1:				/* ln target */
7232596Sbostic 		exit(linkit(argv[0], ".", 1));
7332596Sbostic 	case 2:				/* ln target source */
7432596Sbostic 		exit(linkit(argv[0], argv[1], 0));
75617Sbill 	}
7659497Sbostic 					/* ln target1 target2 directory */
7759497Sbostic 	sourcedir = argv[argc - 1];
7859497Sbostic 	if (stat(sourcedir, &sb))
7959497Sbostic 		err(1, "%s", sourcedir);
8059497Sbostic 	if (!S_ISDIR(sb.st_mode))
8159497Sbostic 		usage();
8259497Sbostic 	for (exitval = 0; *argv != sourcedir; ++argv)
8359497Sbostic 		exitval |= linkit(*argv, sourcedir, 1);
8459497Sbostic 	exit(exitval);
85617Sbill }
86617Sbill 
87*66536Sbostic int
linkit(target,source,isdir)8832596Sbostic linkit(target, source, isdir)
8945341Sbostic 	char *target, *source;
9045341Sbostic 	int isdir;
91617Sbill {
9259497Sbostic 	struct stat sb;
93*66536Sbostic 	int exists;
94*66536Sbostic 	char *p, path[MAXPATHLEN];
95617Sbill 
9632596Sbostic 	if (!sflag) {
97*66536Sbostic 		/* If target doesn't exist, quit now. */
9859497Sbostic 		if (stat(target, &sb)) {
9959497Sbostic 			warn("%s", target);
10059497Sbostic 			return (1);
10132596Sbostic 		}
102*66536Sbostic 		/* Only symbolic links to directories, unless -F option used. */
10359497Sbostic 		if (!dirflag && (sb.st_mode & S_IFMT) == S_IFDIR) {
10459497Sbostic 			warnx("%s: is a directory", target);
10559497Sbostic 			return (1);
10632596Sbostic 		}
107617Sbill 	}
10832596Sbostic 
109*66536Sbostic 	/* If the source is a directory, append the target's name. */
110*66536Sbostic 	if (isdir || (exists = !stat(source, &sb)) && S_ISDIR(sb.st_mode)) {
111*66536Sbostic 		if ((p = strrchr(target, '/')) == NULL)
11259497Sbostic 			p = target;
113716Sbill 		else
11459497Sbostic 			++p;
11559497Sbostic 		(void)snprintf(path, sizeof(path), "%s/%s", source, p);
11632596Sbostic 		source = path;
117*66536Sbostic 		exists = !stat(source, &sb);
118*66536Sbostic 	} else
119*66536Sbostic 		exists = !stat(source, &sb);
12032596Sbostic 
121*66536Sbostic 	/*
122*66536Sbostic 	 * If the file exists, and -f was specified, unlink it.
123*66536Sbostic 	 * Attempt the link.
124*66536Sbostic 	 */
125*66536Sbostic 	if (fflag && exists && unlink(source) || (*linkf)(target, source)) {
12659497Sbostic 		warn("%s", source);
12759497Sbostic 		return (1);
128617Sbill 	}
12959497Sbostic 	return (0);
130617Sbill }
13132596Sbostic 
132*66536Sbostic void
usage()13332596Sbostic usage()
13432596Sbostic {
13545341Sbostic 	(void)fprintf(stderr,
136*66536Sbostic 	    "usage:\tln [-fs] file1 file2\n\tln [-fs] file ... directory\n");
13732596Sbostic 	exit(1);
13832596Sbostic }
139