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