4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / bin / ln / ln.c
CommitLineData
8fb84ebd 1/*
7a909b83 2 * Copyright (c) 1987 Regents of the University of California.
a754946e
KB
3 * All rights reserved.
4 *
f15db449 5 * %sccs.include.redist.c%
8fb84ebd 6 */
7a909b83 7
a754946e 8#ifndef lint
7a909b83
KB
9char copyright[] =
10"@(#) Copyright (c) 1987 Regents of the University of California.\n\
11 All rights reserved.\n";
a754946e 12#endif /* not lint */
7a909b83 13
a754946e 14#ifndef lint
77011f17 15static char sccsid[] = "@(#)ln.c 5.1 (Berkeley) %G%";
a754946e 16#endif /* not lint */
7a909b83
KB
17
18#include <sys/param.h>
8fb84ebd 19#include <sys/stat.h>
77011f17
KB
20
21#include <err.h>
56abc04a 22#include <errno.h>
77011f17 23#include <stdio.h>
337f474e 24#include <stdlib.h>
77011f17 25#include <string.h>
337f474e 26#include <unistd.h>
8fb84ebd 27
77011f17
KB
28int dirflag, /* Undocumented force flag. */
29 sflag, /* Symbolic, not hard, link. */
30 /* System link call. */
31 (*linkf) __P((const char *, const char *));
8fb84ebd 32
77011f17
KB
33static int linkit __P((char *, char *, int));
34static void usage __P((void));
35
36int
8fb84ebd 37main(argc, argv)
be183d1e 38 int argc;
77011f17 39 char *argv[];
8fb84ebd 40{
fd5596d8 41 extern int optind;
77011f17
KB
42 struct stat sb;
43 int ch, exitval;
fd5596d8 44 char *sourcedir;
8fb84ebd 45
fd5596d8 46 while ((ch = getopt(argc, argv, "Fs")) != EOF)
7a909b83 47 switch((char)ch) {
fd5596d8
KB
48 case 'F':
49 dirflag = 1;
7a909b83
KB
50 break;
51 case 's':
52 sflag = 1;
53 break;
54 case '?':
55 default:
56 usage();
57 }
58
59 argv += optind;
60 argc -= optind;
61
62 linkf = sflag ? symlink : link;
63
64 switch(argc) {
65 case 0:
66 usage();
67 case 1: /* ln target */
68 exit(linkit(argv[0], ".", 1));
69 case 2: /* ln target source */
70 exit(linkit(argv[0], argv[1], 0));
8fb84ebd 71 }
77011f17
KB
72 /* ln target1 target2 directory */
73 sourcedir = argv[argc - 1];
74 if (stat(sourcedir, &sb))
75 err(1, "%s", sourcedir);
76 if (!S_ISDIR(sb.st_mode))
77 usage();
78 for (exitval = 0; *argv != sourcedir; ++argv)
79 exitval |= linkit(*argv, sourcedir, 1);
80 exit(exitval);
8fb84ebd
BJ
81}
82
77011f17 83static int
7a909b83 84linkit(target, source, isdir)
be183d1e
KB
85 char *target, *source;
86 int isdir;
8fb84ebd 87{
77011f17
KB
88 struct stat sb;
89 char path[MAXPATHLEN], *p;
8fb84ebd 90
7a909b83
KB
91 if (!sflag) {
92 /* if target doesn't exist, quit now */
77011f17
KB
93 if (stat(target, &sb)) {
94 warn("%s", target);
95 return (1);
7a909b83 96 }
fd5596d8 97 /* only symbolic links to directories, unless -F option used */
77011f17
KB
98 if (!dirflag && (sb.st_mode & S_IFMT) == S_IFDIR) {
99 warnx("%s: is a directory", target);
100 return (1);
7a909b83 101 }
8fb84ebd 102 }
7a909b83
KB
103
104 /* if the source is a directory, append the target's name */
77011f17
KB
105 if (isdir || !stat(source, &sb) && (sb.st_mode & S_IFMT) == S_IFDIR) {
106 if (!(p = strrchr(target, '/')))
107 p = target;
1bfeaa36 108 else
77011f17
KB
109 ++p;
110 (void)snprintf(path, sizeof(path), "%s/%s", source, p);
7a909b83 111 source = path;
8fb84ebd 112 }
7a909b83
KB
113
114 if ((*linkf)(target, source)) {
77011f17
KB
115 warn("%s", source);
116 return (1);
8fb84ebd 117 }
77011f17 118 return (0);
7a909b83
KB
119}
120
77011f17 121static void
7a909b83
KB
122usage()
123{
be183d1e
KB
124 (void)fprintf(stderr,
125 "usage:\tln [-s] file1 file2\n\tln [-s] file ... directory\n");
7a909b83 126 exit(1);
8fb84ebd 127}