GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: ln.c,v 1.24 2016/05/10 20:20:43 tim Exp $ */ |
||
2 |
/* $NetBSD: ln.c,v 1.10 1995/03/21 09:06:10 cgd Exp $ */ |
||
3 |
|||
4 |
/* |
||
5 |
* Copyright (c) 1987, 1993, 1994 |
||
6 |
* The Regents of the University of California. All rights reserved. |
||
7 |
* |
||
8 |
* Redistribution and use in source and binary forms, with or without |
||
9 |
* modification, are permitted provided that the following conditions |
||
10 |
* are met: |
||
11 |
* 1. Redistributions of source code must retain the above copyright |
||
12 |
* notice, this list of conditions and the following disclaimer. |
||
13 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
14 |
* notice, this list of conditions and the following disclaimer in the |
||
15 |
* documentation and/or other materials provided with the distribution. |
||
16 |
* 3. Neither the name of the University nor the names of its contributors |
||
17 |
* may be used to endorse or promote products derived from this software |
||
18 |
* without specific prior written permission. |
||
19 |
* |
||
20 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||
21 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
22 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
23 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||
24 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
25 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
26 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
27 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
28 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
29 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
30 |
* SUCH DAMAGE. |
||
31 |
*/ |
||
32 |
|||
33 |
#include <sys/types.h> |
||
34 |
#include <sys/stat.h> |
||
35 |
|||
36 |
#include <err.h> |
||
37 |
#include <errno.h> |
||
38 |
#include <fcntl.h> |
||
39 |
#include <libgen.h> |
||
40 |
#include <stdio.h> |
||
41 |
#include <stdlib.h> |
||
42 |
#include <string.h> |
||
43 |
#include <unistd.h> |
||
44 |
#include <limits.h> |
||
45 |
|||
46 |
int fflag; /* Unlink existing files. */ |
||
47 |
int hflag; /* Check new name for symlink first. */ |
||
48 |
int Pflag; /* Hard link to symlink. */ |
||
49 |
int sflag; /* Symbolic, not hard, link. */ |
||
50 |
|||
51 |
int linkit(char *, char *, int); |
||
52 |
void usage(void) __dead; |
||
53 |
|||
54 |
int |
||
55 |
main(int argc, char *argv[]) |
||
56 |
{ |
||
57 |
1282 |
struct stat sb; |
|
58 |
int ch, exitval; |
||
59 |
char *sourcedir; |
||
60 |
|||
61 |
✗✓ | 641 |
if (pledge("stdio rpath cpath flock wpath", NULL) == -1) |
62 |
err(1, "pledge"); |
||
63 |
|||
64 |
✓✓ | 2424 |
while ((ch = getopt(argc, argv, "fhLnPs")) != -1) |
65 |
✓✗✗✓ ✓✓✗ |
571 |
switch (ch) { |
66 |
case 'f': |
||
67 |
92 |
fflag = 1; |
|
68 |
92 |
break; |
|
69 |
case 'h': |
||
70 |
case 'n': |
||
71 |
hflag = 1; |
||
72 |
break; |
||
73 |
case 'L': |
||
74 |
4 |
Pflag = 0; |
|
75 |
4 |
break; |
|
76 |
case 'P': |
||
77 |
8 |
Pflag = 1; |
|
78 |
8 |
break; |
|
79 |
case 's': |
||
80 |
467 |
sflag = 1; |
|
81 |
467 |
break; |
|
82 |
default: |
||
83 |
usage(); |
||
84 |
} |
||
85 |
|||
86 |
641 |
argv += optind; |
|
87 |
641 |
argc -= optind; |
|
88 |
|||
89 |
✗✓✓✗ |
641 |
switch(argc) { |
90 |
case 0: |
||
91 |
usage(); |
||
92 |
case 1: /* ln target */ |
||
93 |
exit(linkit(argv[0], ".", 1)); |
||
94 |
case 2: /* ln target source */ |
||
95 |
exit(linkit(argv[0], argv[1], 0)); |
||
96 |
} |
||
97 |
/* ln target1 target2 directory */ |
||
98 |
sourcedir = argv[argc - 1]; |
||
99 |
if (stat(sourcedir, &sb)) |
||
100 |
err(1, "%s", sourcedir); |
||
101 |
if (!S_ISDIR(sb.st_mode)) |
||
102 |
usage(); |
||
103 |
for (exitval = 0; *argv != sourcedir; ++argv) |
||
104 |
exitval |= linkit(*argv, sourcedir, 1); |
||
105 |
exit(exitval); |
||
106 |
} |
||
107 |
|||
108 |
/* |
||
109 |
* Nomenclature warning! |
||
110 |
* |
||
111 |
* In this source "target" and "source" are used the opposite way they |
||
112 |
* are used in the ln(1) manual. Here "target" is the existing file and |
||
113 |
* "source" specifies the to-be-created link to "target". |
||
114 |
*/ |
||
115 |
int |
||
116 |
linkit(char *target, char *source, int isdir) |
||
117 |
{ |
||
118 |
1282 |
struct stat sb; |
|
119 |
641 |
char *p, path[PATH_MAX]; |
|
120 |
int (*statf)(const char *, struct stat *); |
||
121 |
int exists, n; |
||
122 |
|||
123 |
✓✓ | 641 |
if (!sflag) { |
124 |
/* If target doesn't exist, quit now. */ |
||
125 |
✗✓ | 174 |
if ((Pflag ? lstat : stat)(target, &sb)) { |
126 |
warn("%s", target); |
||
127 |
return (1); |
||
128 |
} |
||
129 |
/* Only symbolic links to directories. */ |
||
130 |
✗✓ | 174 |
if (S_ISDIR(sb.st_mode)) { |
131 |
warnc(EISDIR, "%s", target); |
||
132 |
return (1); |
||
133 |
} |
||
134 |
} |
||
135 |
|||
136 |
641 |
statf = hflag ? lstat : stat; |
|
137 |
|||
138 |
/* If the source is a directory, append the target's name. */ |
||
139 |
✓✓✓✓ ✓✓ |
1374 |
if (isdir || (!statf(source, &sb) && S_ISDIR(sb.st_mode))) { |
140 |
✗✓ | 33 |
if ((p = basename(target)) == NULL) { |
141 |
warn("%s", target); |
||
142 |
return (1); |
||
143 |
} |
||
144 |
33 |
n = snprintf(path, sizeof(path), "%s/%s", source, p); |
|
145 |
✓✗✗✓ |
66 |
if (n < 0 || n >= sizeof(path)) { |
146 |
warnc(ENAMETOOLONG, "%s/%s", source, p); |
||
147 |
return (1); |
||
148 |
} |
||
149 |
source = path; |
||
150 |
33 |
} |
|
151 |
|||
152 |
641 |
exists = (lstat(source, &sb) == 0); |
|
153 |
/* |
||
154 |
* If doing hard links and the source (destination) exists and it |
||
155 |
* actually is the same file like the target (existing file), we |
||
156 |
* complain that the files are identical. If -f is specified, we |
||
157 |
* accept the job as already done and return with success. |
||
158 |
*/ |
||
159 |
✓✓ | 641 |
if (exists && !sflag) { |
160 |
54 |
struct stat tsb; |
|
161 |
|||
162 |
✗✓ | 54 |
if ((Pflag ? lstat : stat)(target, &tsb)) { |
163 |
warn("%s: disappeared", target); |
||
164 |
return (1); |
||
165 |
} |
||
166 |
|||
167 |
✓✗✓✓ |
108 |
if (tsb.st_dev == sb.st_dev && tsb.st_ino == sb.st_ino) { |
168 |
✗✓ | 6 |
if (fflag) |
169 |
return (0); |
||
170 |
else { |
||
171 |
6 |
warnx("%s and %s are identical (nothing done).", |
|
172 |
target, source); |
||
173 |
6 |
return (1); |
|
174 |
} |
||
175 |
} |
||
176 |
✓✓ | 102 |
} |
177 |
/* |
||
178 |
* If the file exists, and -f was specified, unlink it. |
||
179 |
* Attempt the link. |
||
180 |
*/ |
||
181 |
✓✓✓✓ ✓✗✓✓ ✗✓ |
1560 |
if ((fflag && unlink(source) < 0 && errno != ENOENT) || |
182 |
✗✓ | 1102 |
(sflag ? symlink(target, source) : |
183 |
168 |
linkat(AT_FDCWD, target, AT_FDCWD, source, |
|
184 |
168 |
Pflag ? 0 : AT_SYMLINK_FOLLOW))) { |
|
185 |
warn("%s", source); |
||
186 |
return (1); |
||
187 |
} |
||
188 |
|||
189 |
635 |
return (0); |
|
190 |
641 |
} |
|
191 |
|||
192 |
void |
||
193 |
usage(void) |
||
194 |
{ |
||
195 |
extern char *__progname; |
||
196 |
|||
197 |
(void)fprintf(stderr, |
||
198 |
"usage: %s [-fhLnPs] source [target]\n" |
||
199 |
" %s [-fLPs] source ... [directory]\n", |
||
200 |
__progname, __progname); |
||
201 |
exit(1); |
||
202 |
} |
Generated by: GCOVR (Version 3.3) |