1*78ae60b4SMartin Matuska /*
2*78ae60b4SMartin Matuska * CDDL HEADER START
3*78ae60b4SMartin Matuska *
4*78ae60b4SMartin Matuska * The contents of this file are subject to the terms of the
5*78ae60b4SMartin Matuska * Common Development and Distribution License (the "License").
6*78ae60b4SMartin Matuska * You may not use this file except in compliance with the License.
7*78ae60b4SMartin Matuska *
8*78ae60b4SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*78ae60b4SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10*78ae60b4SMartin Matuska * See the License for the specific language governing permissions
11*78ae60b4SMartin Matuska * and limitations under the License.
12*78ae60b4SMartin Matuska *
13*78ae60b4SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
14*78ae60b4SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*78ae60b4SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
16*78ae60b4SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
17*78ae60b4SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
18*78ae60b4SMartin Matuska *
19*78ae60b4SMartin Matuska * CDDL HEADER END
20*78ae60b4SMartin Matuska */
21*78ae60b4SMartin Matuska
22*78ae60b4SMartin Matuska /*
23*78ae60b4SMartin Matuska * Copyright (c) 2024 by Pawel Jakub Dawidek
24*78ae60b4SMartin Matuska */
25*78ae60b4SMartin Matuska
26*78ae60b4SMartin Matuska #include <sys/mman.h>
27*78ae60b4SMartin Matuska #include <sys/stat.h>
28*78ae60b4SMartin Matuska
29*78ae60b4SMartin Matuska #include <assert.h>
30*78ae60b4SMartin Matuska #include <errno.h>
31*78ae60b4SMartin Matuska #include <fcntl.h>
32*78ae60b4SMartin Matuska #include <stdbool.h>
33*78ae60b4SMartin Matuska #include <stdio.h>
34*78ae60b4SMartin Matuska #include <stdlib.h>
35*78ae60b4SMartin Matuska #include <string.h>
36*78ae60b4SMartin Matuska #include <unistd.h>
37*78ae60b4SMartin Matuska
38*78ae60b4SMartin Matuska #ifdef __FreeBSD__
39*78ae60b4SMartin Matuska #define loff_t off_t
40*78ae60b4SMartin Matuska #endif
41*78ae60b4SMartin Matuska
42*78ae60b4SMartin Matuska ssize_t
43*78ae60b4SMartin Matuska copy_file_range(int, loff_t *, int, loff_t *, size_t, unsigned int)
44*78ae60b4SMartin Matuska __attribute__((weak));
45*78ae60b4SMartin Matuska
46*78ae60b4SMartin Matuska static void *
mmap_file(int fd,size_t size)47*78ae60b4SMartin Matuska mmap_file(int fd, size_t size)
48*78ae60b4SMartin Matuska {
49*78ae60b4SMartin Matuska void *p;
50*78ae60b4SMartin Matuska
51*78ae60b4SMartin Matuska p = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
52*78ae60b4SMartin Matuska if (p == MAP_FAILED) {
53*78ae60b4SMartin Matuska (void) fprintf(stderr, "mmap failed: %s\n", strerror(errno));
54*78ae60b4SMartin Matuska exit(2);
55*78ae60b4SMartin Matuska }
56*78ae60b4SMartin Matuska
57*78ae60b4SMartin Matuska return (p);
58*78ae60b4SMartin Matuska }
59*78ae60b4SMartin Matuska
60*78ae60b4SMartin Matuska static void
usage(const char * progname)61*78ae60b4SMartin Matuska usage(const char *progname)
62*78ae60b4SMartin Matuska {
63*78ae60b4SMartin Matuska
64*78ae60b4SMartin Matuska /*
65*78ae60b4SMartin Matuska * -i cache input before copy_file_range(2).
66*78ae60b4SMartin Matuska * -o cache input before copy_file_range(2).
67*78ae60b4SMartin Matuska */
68*78ae60b4SMartin Matuska (void) fprintf(stderr, "usage: %s [-io] <input> <output>\n", progname);
69*78ae60b4SMartin Matuska exit(3);
70*78ae60b4SMartin Matuska }
71*78ae60b4SMartin Matuska
72*78ae60b4SMartin Matuska int
main(int argc,char * argv[])73*78ae60b4SMartin Matuska main(int argc, char *argv[])
74*78ae60b4SMartin Matuska {
75*78ae60b4SMartin Matuska int dfd, sfd;
76*78ae60b4SMartin Matuska size_t dsize, ssize;
77*78ae60b4SMartin Matuska void *dmem, *smem, *ptr;
78*78ae60b4SMartin Matuska off_t doff, soff;
79*78ae60b4SMartin Matuska struct stat sb;
80*78ae60b4SMartin Matuska bool cache_input, cache_output;
81*78ae60b4SMartin Matuska const char *progname;
82*78ae60b4SMartin Matuska int c;
83*78ae60b4SMartin Matuska
84*78ae60b4SMartin Matuska progname = argv[0];
85*78ae60b4SMartin Matuska cache_input = cache_output = false;
86*78ae60b4SMartin Matuska
87*78ae60b4SMartin Matuska while ((c = getopt(argc, argv, "io")) != -1) {
88*78ae60b4SMartin Matuska switch (c) {
89*78ae60b4SMartin Matuska case 'i':
90*78ae60b4SMartin Matuska cache_input = true;
91*78ae60b4SMartin Matuska break;
92*78ae60b4SMartin Matuska case 'o':
93*78ae60b4SMartin Matuska cache_output = true;
94*78ae60b4SMartin Matuska break;
95*78ae60b4SMartin Matuska default:
96*78ae60b4SMartin Matuska usage(progname);
97*78ae60b4SMartin Matuska }
98*78ae60b4SMartin Matuska }
99*78ae60b4SMartin Matuska argc -= optind;
100*78ae60b4SMartin Matuska argv += optind;
101*78ae60b4SMartin Matuska
102*78ae60b4SMartin Matuska if (argc != 2) {
103*78ae60b4SMartin Matuska usage(progname);
104*78ae60b4SMartin Matuska }
105*78ae60b4SMartin Matuska
106*78ae60b4SMartin Matuska sfd = open(argv[0], O_RDONLY);
107*78ae60b4SMartin Matuska if (fstat(sfd, &sb) == -1) {
108*78ae60b4SMartin Matuska (void) fprintf(stderr, "fstat failed: %s\n", strerror(errno));
109*78ae60b4SMartin Matuska exit(2);
110*78ae60b4SMartin Matuska }
111*78ae60b4SMartin Matuska ssize = sb.st_size;
112*78ae60b4SMartin Matuska smem = mmap_file(sfd, ssize);
113*78ae60b4SMartin Matuska
114*78ae60b4SMartin Matuska dfd = open(argv[1], O_RDWR);
115*78ae60b4SMartin Matuska if (fstat(dfd, &sb) == -1) {
116*78ae60b4SMartin Matuska (void) fprintf(stderr, "fstat failed: %s\n", strerror(errno));
117*78ae60b4SMartin Matuska exit(2);
118*78ae60b4SMartin Matuska }
119*78ae60b4SMartin Matuska dsize = sb.st_size;
120*78ae60b4SMartin Matuska dmem = mmap_file(dfd, dsize);
121*78ae60b4SMartin Matuska
122*78ae60b4SMartin Matuska /*
123*78ae60b4SMartin Matuska * Hopefully it won't be compiled out.
124*78ae60b4SMartin Matuska */
125*78ae60b4SMartin Matuska if (cache_input) {
126*78ae60b4SMartin Matuska ptr = malloc(ssize);
127*78ae60b4SMartin Matuska assert(ptr != NULL);
128*78ae60b4SMartin Matuska memcpy(ptr, smem, ssize);
129*78ae60b4SMartin Matuska free(ptr);
130*78ae60b4SMartin Matuska }
131*78ae60b4SMartin Matuska if (cache_output) {
132*78ae60b4SMartin Matuska ptr = malloc(ssize);
133*78ae60b4SMartin Matuska assert(ptr != NULL);
134*78ae60b4SMartin Matuska memcpy(ptr, dmem, dsize);
135*78ae60b4SMartin Matuska free(ptr);
136*78ae60b4SMartin Matuska }
137*78ae60b4SMartin Matuska
138*78ae60b4SMartin Matuska soff = doff = 0;
139*78ae60b4SMartin Matuska if (copy_file_range(sfd, &soff, dfd, &doff, ssize, 0) < 0) {
140*78ae60b4SMartin Matuska (void) fprintf(stderr, "copy_file_range failed: %s\n",
141*78ae60b4SMartin Matuska strerror(errno));
142*78ae60b4SMartin Matuska exit(2);
143*78ae60b4SMartin Matuska }
144*78ae60b4SMartin Matuska
145*78ae60b4SMartin Matuska exit(memcmp(smem, dmem, ssize) == 0 ? 0 : 1);
146*78ae60b4SMartin Matuska }
147