Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.bin/cmp/cmp.c
34677 views
1
/*
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1987, 1990, 1993, 1994
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/types.h>
33
#include <sys/stat.h>
34
35
#include <capsicum_helpers.h>
36
#include <err.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <getopt.h>
40
#include <nl_types.h>
41
#include <stdbool.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46
47
#include <libutil.h>
48
49
#include "extern.h"
50
51
bool bflag, lflag, sflag, xflag, zflag;
52
53
static const struct option long_opts[] =
54
{
55
{"print-bytes", no_argument, NULL, 'b'},
56
{"ignore-initial", required_argument, NULL, 'i'},
57
{"verbose", no_argument, NULL, 'l'},
58
{"bytes", required_argument, NULL, 'n'},
59
{"silent", no_argument, NULL, 's'},
60
{"quiet", no_argument, NULL, 's'},
61
{NULL, no_argument, NULL, 0}
62
};
63
64
#ifdef SIGINFO
65
volatile sig_atomic_t info;
66
67
static void
68
siginfo(int signo)
69
{
70
info = signo;
71
}
72
#endif
73
74
static void usage(void) __dead2;
75
76
static bool
77
parse_iskipspec(char *spec, off_t *skip1, off_t *skip2)
78
{
79
char *colon;
80
81
colon = strchr(spec, ':');
82
if (colon != NULL)
83
*colon++ = '\0';
84
85
if (expand_number(spec, skip1) < 0)
86
return (false);
87
88
if (colon != NULL)
89
return (expand_number(colon, skip2) == 0);
90
91
*skip2 = *skip1;
92
return (true);
93
}
94
95
int
96
main(int argc, char *argv[])
97
{
98
struct stat sb1, sb2;
99
off_t skip1, skip2, limit;
100
int ch, fd1, fd2, oflag;
101
bool special;
102
const char *file1, *file2;
103
int ret;
104
105
limit = skip1 = skip2 = ret = 0;
106
oflag = O_RDONLY;
107
while ((ch = getopt_long(argc, argv, "+bhi:ln:sxz", long_opts, NULL)) != -1)
108
switch (ch) {
109
case 'b': /* Print bytes */
110
bflag = true;
111
break;
112
case 'h': /* Don't follow symlinks */
113
oflag |= O_NOFOLLOW;
114
break;
115
case 'i':
116
if (!parse_iskipspec(optarg, &skip1, &skip2)) {
117
fprintf(stderr,
118
"Invalid --ignore-initial: %s\n",
119
optarg);
120
usage();
121
}
122
break;
123
case 'l': /* print all differences */
124
lflag = true;
125
break;
126
case 'n': /* Limit */
127
if (expand_number(optarg, &limit) < 0 || limit < 0) {
128
fprintf(stderr, "Invalid --bytes: %s\n",
129
optarg);
130
usage();
131
}
132
break;
133
case 's': /* silent run */
134
sflag = true;
135
break;
136
case 'x': /* hex output */
137
lflag = true;
138
xflag = true;
139
break;
140
case 'z': /* compare size first */
141
zflag = true;
142
break;
143
case '?':
144
default:
145
usage();
146
}
147
argv += optind;
148
argc -= optind;
149
150
if (lflag && sflag)
151
errx(ERR_EXIT, "specifying -s with -l or -x is not permitted");
152
153
if (argc < 2 || argc > 4)
154
usage();
155
156
/* Don't limit rights on stdin since it may be one of the inputs. */
157
if (caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | CAPH_IGNORE_EBADF))
158
err(ERR_EXIT, "unable to limit rights on stdout");
159
if (caph_limit_stream(STDERR_FILENO, CAPH_WRITE | CAPH_IGNORE_EBADF))
160
err(ERR_EXIT, "unable to limit rights on stderr");
161
162
/* Backward compatibility -- handle "-" meaning stdin. */
163
special = false;
164
if (strcmp(file1 = argv[0], "-") == 0) {
165
special = true;
166
fd1 = STDIN_FILENO;
167
file1 = "stdin";
168
} else if ((fd1 = open(file1, oflag, 0)) < 0 && errno != EMLINK) {
169
if (!sflag)
170
err(ERR_EXIT, "%s", file1);
171
else
172
exit(ERR_EXIT);
173
}
174
if (strcmp(file2 = argv[1], "-") == 0) {
175
if (special)
176
errx(ERR_EXIT,
177
"standard input may only be specified once");
178
special = true;
179
fd2 = STDIN_FILENO;
180
file2 = "stdin";
181
} else if ((fd2 = open(file2, oflag, 0)) < 0 && errno != EMLINK) {
182
if (!sflag)
183
err(ERR_EXIT, "%s", file2);
184
else
185
exit(ERR_EXIT);
186
}
187
188
if (argc > 2 && expand_number(argv[2], &skip1) < 0) {
189
fprintf(stderr, "Invalid skip1: %s\n", argv[2]);
190
usage();
191
}
192
193
if (argc == 4 && expand_number(argv[3], &skip2) < 0) {
194
fprintf(stderr, "Invalid skip2: %s\n", argv[3]);
195
usage();
196
}
197
198
if (sflag && skip1 == 0 && skip2 == 0)
199
zflag = true;
200
201
if (fd1 == -1) {
202
if (fd2 == -1) {
203
ret = c_link(file1, skip1, file2, skip2, limit);
204
goto end;
205
} else if (!sflag)
206
errx(ERR_EXIT, "%s: Not a symbolic link", file2);
207
else
208
exit(ERR_EXIT);
209
} else if (fd2 == -1) {
210
if (!sflag)
211
errx(ERR_EXIT, "%s: Not a symbolic link", file1);
212
else
213
exit(ERR_EXIT);
214
}
215
216
/* FD rights are limited in c_special() and c_regular(). */
217
caph_cache_catpages();
218
219
if (!special) {
220
if (fstat(fd1, &sb1)) {
221
if (!sflag)
222
err(ERR_EXIT, "%s", file1);
223
else
224
exit(ERR_EXIT);
225
}
226
if (!S_ISREG(sb1.st_mode))
227
special = true;
228
else {
229
if (fstat(fd2, &sb2)) {
230
if (!sflag)
231
err(ERR_EXIT, "%s", file2);
232
else
233
exit(ERR_EXIT);
234
}
235
if (!S_ISREG(sb2.st_mode))
236
special = true;
237
}
238
}
239
240
#ifdef SIGINFO
241
(void)signal(SIGINFO, siginfo);
242
#endif
243
if (special) {
244
ret = c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
245
} else {
246
if (zflag && sb1.st_size != sb2.st_size) {
247
if (!sflag)
248
(void)printf("%s %s differ: size\n",
249
file1, file2);
250
ret = DIFF_EXIT;
251
} else {
252
ret = c_regular(fd1, file1, skip1, sb1.st_size,
253
fd2, file2, skip2, sb2.st_size, limit);
254
}
255
}
256
end:
257
if (!sflag && fflush(stdout) != 0)
258
err(ERR_EXIT, "stdout");
259
exit(ret);
260
}
261
262
static void
263
usage(void)
264
{
265
266
(void)fprintf(stderr,
267
"usage: cmp [-l | -s | -x] [-hz] file1 file2 [skip1 [skip2]]\n");
268
exit(ERR_EXIT);
269
}
270
271