1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2012 Jilin Xpd <jilinxpd@gmail.com>
14 * Copyright 2018 Nexenta Systems, Inc.
15 */
16
17 /*
18 * use mmap to copy data from src file to des file,
19 * with given flags and modes.
20 * the src & des file should exist and have the same size.
21 */
22
23 #include <sys/mman.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32
33 void
usage(void)34 usage(void)
35 {
36 fprintf(stderr,
37 "usage: "
38 "prot_mmap -o <r|w> <r|w>"
39 " -m <r|w|s|p> <r|w|s|p>"
40 " -f <srcfile> <desfile>\n");
41 exit(1);
42 }
43
44 int
main(int argc,char ** argv)45 main(int argc, char **argv)
46 {
47 struct stat sb;
48 char *src_addr, *des_addr;
49 char *src_file = NULL, *des_file = NULL;
50 off_t offset;
51 size_t filesize;
52 size_t blksize;
53 size_t numblks;
54 size_t i, j;
55 int src_fid, des_fid;
56 int mret = 0;
57 int flags0 = 0, mflags0 = 0, prot0 = 0; /* flags for src file */
58 int flags1 = 0, mflags1 = 0, prot1 = 0; /* flags for des file */
59
60 /*
61 * parse arguments
62 * Not getopt because -o -m -f all have 2 optargs each.
63 */
64 if (argc != 10) {
65 usage();
66 }
67 for (i = 1; i < argc; ) {
68 switch (argv[i][1]) {
69 case 'o': /* options for open() */
70 i++;
71 for (j = 0; argv[i][j]; j++) {
72 if (argv[i][j] == 'r')
73 flags0 |= O_RDONLY;
74 else if (argv[i][j] == 'w')
75 flags0 |= O_WRONLY;
76 }
77 if ((flags0 & (O_RDONLY | O_WRONLY)) ==
78 (O_RDONLY | O_WRONLY))
79 flags0 = O_RDWR;
80 i++;
81 for (j = 0; argv[i][j]; j++) {
82 if (argv[i][j] == 'r')
83 flags1 |= O_RDONLY;
84 else if (argv[i][j] == 'w')
85 flags1 |= O_WRONLY;
86 }
87 if ((flags1 & (O_RDONLY | O_WRONLY)) ==
88 (O_RDONLY | O_WRONLY))
89 flags1 = O_RDWR;
90 i++;
91 break;
92 case 'm': /* options for mmap() */
93 i++;
94 for (j = 0; argv[i][j]; j++) {
95 if (argv[i][j] == 'r')
96 prot0 |= PROT_READ;
97 else if (argv[i][j] == 'w')
98 prot0 |= PROT_WRITE;
99 else if (argv[i][j] == 's')
100 mflags0 |= MAP_SHARED;
101 else if (argv[i][j] == 'p')
102 mflags0 |= MAP_PRIVATE;
103 }
104 i++;
105 for (j = 0; argv[i][j]; j++) {
106 if (argv[i][j] == 'r')
107 prot1 |= PROT_READ;
108 else if (argv[i][j] == 'w')
109 prot1 |= PROT_WRITE;
110 else if (argv[i][j] == 's')
111 mflags1 |= MAP_SHARED;
112 else if (argv[i][j] == 'p')
113 mflags1 |= MAP_PRIVATE;
114 }
115 i++;
116 break;
117 case 'f': /* src file and des file */
118 i++;
119 src_file = argv[i];
120 i++;
121 des_file = argv[i];
122 i++;
123 }
124 }
125
126 /* source file */
127 src_fid = open(src_file, flags0);
128 if (src_fid == -1) {
129 fprintf(stderr, "open %s error=%d\n", src_file, errno);
130 return (1);
131 }
132 /* destination file */
133 des_fid = open(des_file, flags1);
134 if (des_fid == -1) {
135 fprintf(stderr, "open %s error=%d\n", des_file, errno);
136 mret = 1;
137 goto exit3;
138 }
139
140 /* get file size */
141 if (fstat(src_fid, &sb) == -1) {
142 fprintf(stderr, "fstat %s error=%d\n", src_file, errno);
143 mret = 1;
144 goto exit2;
145 }
146 filesize = sb.st_size;
147 if (filesize < 4096) {
148 fprintf(stderr, "file too small\n");
149 mret = 1;
150 goto exit2;
151 }
152
153 if (fstat(des_fid, &sb) == -1) {
154 fprintf(stderr, "fstat %s error=%d\n", des_file, errno);
155 mret = 1;
156 goto exit2;
157 }
158 if (filesize != sb.st_size) {
159 fprintf(stderr, "file sizes differ\n");
160 mret = 1;
161 goto exit2;
162 }
163
164 /* copy data */
165 blksize = 64 * 1024 * 1024;
166 numblks = (filesize + blksize - 1) / blksize;
167 for (i = 0; i < numblks && mret == 0; i++) {
168
169 offset = (i % numblks) * blksize;
170 if (offset + blksize > filesize)
171 blksize = filesize - offset;
172
173 /* map file */
174 src_addr = mmap(NULL, blksize, prot0, mflags0, src_fid, offset);
175 if (src_addr == MAP_FAILED) {
176 fprintf(stderr, "mmap %s error=%d\n", src_file, errno);
177 mret = 1;
178 break;
179 }
180 des_addr = mmap(NULL, blksize, prot1, mflags1, des_fid, offset);
181 if (des_addr == MAP_FAILED) {
182 fprintf(stderr, "mmap %s error=%d\n", des_file, errno);
183 mret = 1;
184 goto exit1;
185 }
186
187 /* cp data from src addr to des addr */
188 memcpy(des_addr, src_addr, blksize);
189 /* sync mapped pages to file */
190 if (msync(des_addr, blksize, MS_SYNC) == -1) {
191 fprintf(stderr, "msync %s error=%d\n", des_file, errno);
192 mret = 1;
193 }
194
195 /* unmap file */
196 if (munmap(des_addr, blksize) == -1) {
197 fprintf(stderr, "munmap %s error=%d\n",
198 des_file, errno);
199 mret = 1;
200 }
201 exit1:
202 if (munmap(src_addr, blksize) == -1) {
203 fprintf(stderr, "munmap %s error=%d\n",
204 src_file, errno);
205 mret = 1;
206 }
207 }
208
209 /* close file */
210 exit2:
211 close(des_fid);
212 exit3:
213 close(src_fid);
214
215 return (mret);
216 }
217