]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
48c46ee3 | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2004-2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
48c46ee3 NS |
5 | */ |
6 | ||
6b803e5a CH |
7 | #include "command.h" |
8 | #include "input.h" | |
48c46ee3 NS |
9 | #include <sys/mman.h> |
10 | #include <signal.h> | |
48c46ee3 NS |
11 | #include "init.h" |
12 | #include "io.h" | |
13 | ||
14 | static cmdinfo_t mmap_cmd; | |
15 | static cmdinfo_t mread_cmd; | |
16 | static cmdinfo_t msync_cmd; | |
17 | static cmdinfo_t munmap_cmd; | |
18 | static cmdinfo_t mwrite_cmd; | |
a49984b3 | 19 | #ifdef HAVE_MREMAP |
4f20f6a3 | 20 | static cmdinfo_t mremap_cmd; |
a49984b3 | 21 | #endif /* HAVE_MREMAP */ |
48c46ee3 NS |
22 | |
23 | mmap_region_t *maptable; | |
24 | int mapcount; | |
25 | mmap_region_t *mapping; | |
26 | ||
27 | static void | |
28 | print_mapping( | |
29 | mmap_region_t *map, | |
30 | int index, | |
31 | int braces) | |
32 | { | |
dad79683 | 33 | char buffer[8] = { 0 }; |
48c46ee3 NS |
34 | int i; |
35 | ||
36 | static struct { | |
37 | int prot; | |
38 | int mode; | |
39 | } *p, pflags[] = { | |
40 | { PROT_READ, 'r' }, | |
41 | { PROT_WRITE, 'w' }, | |
42 | { PROT_EXEC, 'x' }, | |
43 | { PROT_NONE, 0 } | |
44 | }; | |
45 | ||
46 | for (i = 0, p = pflags; p->prot != PROT_NONE; i++, p++) | |
47 | buffer[i] = (map->prot & p->prot) ? p->mode : '-'; | |
dad79683 | 48 | |
28965957 DW |
49 | #ifdef HAVE_MAP_SYNC |
50 | if ((map->flags & (MAP_SYNC | MAP_SHARED_VALIDATE)) == | |
51 | (MAP_SYNC | MAP_SHARED_VALIDATE)) | |
dad79683 | 52 | sprintf(&buffer[i], " S"); |
28965957 | 53 | #endif |
dad79683 | 54 | |
153563c4 | 55 | printf("%c%03d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n", |
48c46ee3 NS |
56 | braces? '[' : ' ', index, braces? ']' : ' ', |
57 | (unsigned long)map->addr, | |
5ecb3de2 | 58 | (unsigned long)((char *)map->addr + map->length), |
48c46ee3 NS |
59 | buffer, map->name ? map->name : "???", |
60 | (long long)map->offset, (long)map->length); | |
61 | } | |
62 | ||
0bba1a49 | 63 | void * |
48c46ee3 NS |
64 | check_mapping_range( |
65 | mmap_region_t *map, | |
66 | off64_t offset, | |
67 | size_t length, | |
68 | int pagealign) | |
69 | { | |
70 | off64_t relative; | |
71 | ||
72 | if (offset < mapping->offset) { | |
73 | printf(_("offset (%lld) is before start of mapping (%lld)\n"), | |
74 | (long long)offset, (long long)mapping->offset); | |
75 | return NULL; | |
76 | } | |
77 | relative = offset - mapping->offset; | |
78 | if (relative > mapping->length) { | |
79 | printf(_("offset (%lld) is beyond end of mapping (%lld)\n"), | |
80 | (long long)relative, (long long)mapping->offset); | |
81 | return NULL; | |
82 | } | |
83 | if ((relative + length) > (mapping->offset + mapping->length)) { | |
84 | printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"), | |
85 | (long long)offset, (long long)relative, | |
86 | (long long)mapping->offset, (long)mapping->length); | |
87 | return NULL; | |
88 | } | |
5ecb3de2 | 89 | if (pagealign && (long)((char *)mapping->addr + relative) % pagesize) { |
48c46ee3 | 90 | printf(_("offset address (%p) is not page aligned\n"), |
5ecb3de2 | 91 | (char *)mapping->addr + relative); |
48c46ee3 NS |
92 | return NULL; |
93 | } | |
94 | ||
5ecb3de2 | 95 | return (char *)mapping->addr + relative; |
48c46ee3 NS |
96 | } |
97 | ||
98 | int | |
99 | maplist_f(void) | |
100 | { | |
101 | int i; | |
102 | ||
103 | for (i = 0; i < mapcount; i++) | |
104 | print_mapping(&maptable[i], i, &maptable[i] == mapping); | |
105 | return 0; | |
106 | } | |
107 | ||
108 | static int | |
109 | mapset_f( | |
110 | int argc, | |
111 | char **argv) | |
112 | { | |
113 | int i; | |
114 | ||
115 | ASSERT(argc == 2); | |
116 | i = atoi(argv[1]); | |
117 | if (i < 0 || i >= mapcount) { | |
118 | printf("value %d is out of range (0-%d)\n", i, mapcount); | |
9e1595e6 | 119 | exitcode = 1; |
48c46ee3 NS |
120 | } else { |
121 | mapping = &maptable[i]; | |
122 | maplist_f(); | |
123 | } | |
124 | return 0; | |
125 | } | |
126 | ||
127 | static void | |
128 | mmap_help(void) | |
129 | { | |
130 | printf(_( | |
131 | "\n" | |
132 | " maps a range within the current file into memory\n" | |
133 | "\n" | |
134 | " Example:\n" | |
135 | " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n" | |
136 | "\n" | |
137 | " Memory maps a range of a file for subsequent use by other xfs_io commands.\n" | |
138 | " With no arguments, mmap shows the current mappings. The current mapping\n" | |
139 | " can be set by using the single argument form (mapping number or address).\n" | |
140 | " If two arguments are specified (a range), a new mapping is created and the\n" | |
141 | " following options are available:\n" | |
142 | " -r -- map with PROT_READ protection\n" | |
143 | " -w -- map with PROT_WRITE protection\n" | |
144 | " -x -- map with PROT_EXEC protection\n" | |
28965957 | 145 | #ifdef HAVE_MAP_SYNC |
dad79683 | 146 | " -S -- map with MAP_SYNC and MAP_SHARED_VALIDATE flags\n" |
28965957 | 147 | #endif |
e0a88082 | 148 | " -s <size> -- first do mmap(size)/munmap(size), try to reserve some free space\n" |
48c46ee3 NS |
149 | " If no protection mode is specified, all are used by default.\n" |
150 | "\n")); | |
151 | } | |
152 | ||
153 | static int | |
154 | mmap_f( | |
155 | int argc, | |
156 | char **argv) | |
157 | { | |
158 | off64_t offset; | |
e0a88082 ZL |
159 | ssize_t length = 0, length2 = 0; |
160 | void *address = NULL; | |
48c46ee3 | 161 | char *filename; |
2c2f6d79 | 162 | size_t blocksize, sectsize; |
dad79683 | 163 | int c, prot = 0, flags = MAP_SHARED; |
48c46ee3 NS |
164 | |
165 | if (argc == 1) { | |
166 | if (mapping) | |
167 | return maplist_f(); | |
168 | fprintf(stderr, file ? | |
f8149110 | 169 | _("no mapped regions, try 'help mmap'\n") : |
48c46ee3 | 170 | _("no files are open, try 'help open'\n")); |
9e1595e6 | 171 | exitcode = 1; |
48c46ee3 NS |
172 | return 0; |
173 | } else if (argc == 2) { | |
174 | if (mapping) | |
175 | return mapset_f(argc, argv); | |
176 | fprintf(stderr, file ? | |
177 | _("no mapped regions, try 'help mmap'\n") : | |
178 | _("no files are open, try 'help open'\n")); | |
9e1595e6 | 179 | exitcode = 1; |
48c46ee3 NS |
180 | return 0; |
181 | } else if (!file) { | |
182 | fprintf(stderr, _("no files are open, try 'help open'\n")); | |
9e1595e6 | 183 | exitcode = 1; |
48c46ee3 NS |
184 | return 0; |
185 | } | |
186 | ||
e0a88082 ZL |
187 | init_cvtnum(&blocksize, §size); |
188 | ||
dad79683 | 189 | while ((c = getopt(argc, argv, "rwxSs:")) != EOF) { |
48c46ee3 NS |
190 | switch (c) { |
191 | case 'r': | |
192 | prot |= PROT_READ; | |
193 | break; | |
194 | case 'w': | |
195 | prot |= PROT_WRITE; | |
196 | break; | |
197 | case 'x': | |
198 | prot |= PROT_EXEC; | |
199 | break; | |
dad79683 | 200 | case 'S': |
28965957 | 201 | #ifdef HAVE_MAP_SYNC |
dad79683 | 202 | flags = MAP_SYNC | MAP_SHARED_VALIDATE; |
dad79683 | 203 | break; |
28965957 DW |
204 | #else |
205 | printf("MAP_SYNC not supported\n"); | |
206 | exitcode = 1; | |
207 | return command_usage(&mmap_cmd); | |
208 | #endif | |
e0a88082 ZL |
209 | case 's': |
210 | length2 = cvtnum(blocksize, sectsize, optarg); | |
211 | break; | |
48c46ee3 | 212 | default: |
9e1595e6 | 213 | exitcode = 1; |
48c46ee3 NS |
214 | return command_usage(&mmap_cmd); |
215 | } | |
216 | } | |
217 | if (!prot) | |
218 | prot = PROT_READ | PROT_WRITE | PROT_EXEC; | |
219 | ||
9e1595e6 DC |
220 | if (optind != argc - 2) { |
221 | exitcode = 1; | |
48c46ee3 | 222 | return command_usage(&mmap_cmd); |
9e1595e6 | 223 | } |
48c46ee3 | 224 | |
48c46ee3 NS |
225 | offset = cvtnum(blocksize, sectsize, argv[optind]); |
226 | if (offset < 0) { | |
227 | printf(_("non-numeric offset argument -- %s\n"), argv[optind]); | |
9e1595e6 | 228 | exitcode = 1; |
48c46ee3 NS |
229 | return 0; |
230 | } | |
231 | optind++; | |
232 | length = cvtnum(blocksize, sectsize, argv[optind]); | |
233 | if (length < 0) { | |
234 | printf(_("non-numeric length argument -- %s\n"), argv[optind]); | |
9e1595e6 | 235 | exitcode = 1; |
48c46ee3 NS |
236 | return 0; |
237 | } | |
238 | ||
239 | filename = strdup(file->name); | |
240 | if (!filename) { | |
241 | perror("strdup"); | |
9e1595e6 | 242 | exitcode = 1; |
48c46ee3 NS |
243 | return 0; |
244 | } | |
245 | ||
e0a88082 ZL |
246 | /* |
247 | * mmap and munmap memory area of length2 region is helpful to | |
248 | * make a region of extendible free memory. It's generally used | |
249 | * for later mremap operation(no MREMAP_MAYMOVE flag). But there | |
250 | * isn't guarantee that the memory after length (up to length2) | |
251 | * will stay free. | |
252 | */ | |
253 | if (length2 > length) { | |
254 | address = mmap(NULL, length2, prot, | |
255 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
256 | munmap(address, length2); | |
257 | } | |
dad79683 | 258 | address = mmap(address, length, prot, flags, file->fd, offset); |
48c46ee3 NS |
259 | if (address == MAP_FAILED) { |
260 | perror("mmap"); | |
261 | free(filename); | |
9e1595e6 | 262 | exitcode = 1; |
48c46ee3 NS |
263 | return 0; |
264 | } | |
265 | ||
266 | /* Extend the control array of mmap'd regions */ | |
267 | maptable = (mmap_region_t *)realloc(maptable, /* growing */ | |
268 | ++mapcount * sizeof(mmap_region_t)); | |
269 | if (!maptable) { | |
270 | perror("realloc"); | |
271 | mapcount = 0; | |
272 | munmap(address, length); | |
273 | free(filename); | |
9e1595e6 | 274 | exitcode = 1; |
48c46ee3 NS |
275 | return 0; |
276 | } | |
277 | ||
278 | /* Finally, make this the new active mapping */ | |
279 | mapping = &maptable[mapcount - 1]; | |
280 | mapping->addr = address; | |
281 | mapping->length = length; | |
282 | mapping->offset = offset; | |
283 | mapping->name = filename; | |
284 | mapping->prot = prot; | |
28965957 | 285 | mapping->flags = flags; |
48c46ee3 NS |
286 | return 0; |
287 | } | |
288 | ||
289 | static void | |
290 | msync_help(void) | |
291 | { | |
292 | printf(_( | |
293 | "\n" | |
294 | " flushes a range of bytes in the current memory mapping\n" | |
295 | "\n" | |
296 | " Writes all modified copies of pages over the specified range (or entire\n" | |
297 | " mapping if no range specified) to their backing storage locations. Also,\n" | |
298 | " optionally invalidates so that subsequent references to the pages will be\n" | |
299 | " obtained from their backing storage locations (instead of cached copies).\n" | |
300 | " -a -- perform asynchronous writes (MS_ASYNC)\n" | |
301 | " -i -- invalidate mapped pages (MS_INVALIDATE)\n" | |
302 | " -s -- perform synchronous writes (MS_SYNC)\n" | |
303 | "\n")); | |
304 | } | |
305 | ||
00ff2b10 | 306 | static int |
48c46ee3 NS |
307 | msync_f( |
308 | int argc, | |
309 | char **argv) | |
310 | { | |
311 | off64_t offset; | |
5ecb3de2 | 312 | ssize_t length; |
48c46ee3 | 313 | void *start; |
cb7ba2b0 | 314 | int c, flags = 0; |
2c2f6d79 | 315 | size_t blocksize, sectsize; |
48c46ee3 NS |
316 | |
317 | while ((c = getopt(argc, argv, "ais")) != EOF) { | |
318 | switch (c) { | |
319 | case 'a': | |
320 | flags |= MS_ASYNC; | |
321 | break; | |
322 | case 'i': | |
323 | flags |= MS_INVALIDATE; | |
324 | break; | |
325 | case 's': | |
326 | flags |= MS_SYNC; | |
327 | break; | |
328 | default: | |
9e1595e6 | 329 | exitcode = 1; |
48c46ee3 NS |
330 | return command_usage(&msync_cmd); |
331 | } | |
332 | } | |
333 | ||
334 | if (optind == argc) { | |
335 | offset = mapping->offset; | |
336 | length = mapping->length; | |
337 | } else if (optind == argc - 2) { | |
338 | init_cvtnum(&blocksize, §size); | |
339 | offset = cvtnum(blocksize, sectsize, argv[optind]); | |
340 | if (offset < 0) { | |
341 | printf(_("non-numeric offset argument -- %s\n"), | |
342 | argv[optind]); | |
9e1595e6 | 343 | exitcode = 1; |
48c46ee3 NS |
344 | return 0; |
345 | } | |
346 | optind++; | |
347 | length = cvtnum(blocksize, sectsize, argv[optind]); | |
348 | if (length < 0) { | |
349 | printf(_("non-numeric length argument -- %s\n"), | |
350 | argv[optind]); | |
9e1595e6 | 351 | exitcode = 1; |
48c46ee3 NS |
352 | return 0; |
353 | } | |
354 | } else { | |
9e1595e6 | 355 | exitcode = 1; |
48c46ee3 NS |
356 | return command_usage(&msync_cmd); |
357 | } | |
358 | ||
359 | start = check_mapping_range(mapping, offset, length, 1); | |
9e1595e6 DC |
360 | if (!start) { |
361 | exitcode = 1; | |
48c46ee3 | 362 | return 0; |
9e1595e6 | 363 | } |
48c46ee3 | 364 | |
9e1595e6 | 365 | if (msync(start, length, flags) < 0) { |
48c46ee3 | 366 | perror("msync"); |
9e1595e6 DC |
367 | exitcode = 1; |
368 | return 0; | |
369 | } | |
48c46ee3 NS |
370 | |
371 | return 0; | |
372 | } | |
373 | ||
48c46ee3 NS |
374 | static void |
375 | mread_help(void) | |
376 | { | |
377 | printf(_( | |
378 | "\n" | |
379 | " reads a range of bytes in the current memory mapping\n" | |
380 | "\n" | |
381 | " Example:\n" | |
382 | " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n" | |
383 | "\n" | |
384 | " Accesses a range of the current memory mapping, optionally dumping it to\n" | |
385 | " the standard output stream (with -v option) for subsequent inspection.\n" | |
386 | " -f -- verbose mode, dump bytes with offsets relative to start of file.\n" | |
ff1f79a7 | 387 | " -r -- reverse order; start accessing from the end of range, moving backward\n" |
48c46ee3 NS |
388 | " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n" |
389 | " The accesses are performed sequentially from the start offset by default.\n" | |
390 | " Notes:\n" | |
391 | " References to whole pages following the end of the backing file results\n" | |
392 | " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n" | |
393 | " on various filesystem conditions, including quota exceeded errors, and\n" | |
394 | " for physical device errors (such as unreadable disk blocks). No attempt\n" | |
395 | " has been made to catch signals at this stage...\n" | |
396 | "\n")); | |
397 | } | |
398 | ||
00ff2b10 | 399 | static int |
48c46ee3 NS |
400 | mread_f( |
401 | int argc, | |
402 | char **argv) | |
403 | { | |
8e192991 | 404 | off64_t offset, tmp, dumpoffset, printoffset; |
5ecb3de2 | 405 | ssize_t length; |
8e192991 | 406 | size_t dumplen, cnt = 0; |
48c46ee3 NS |
407 | char *bp; |
408 | void *start; | |
cb7ba2b0 | 409 | int dump = 0, rflag = 0, c; |
2c2f6d79 | 410 | size_t blocksize, sectsize; |
48c46ee3 NS |
411 | |
412 | while ((c = getopt(argc, argv, "frv")) != EOF) { | |
413 | switch (c) { | |
414 | case 'f': | |
415 | dump = 2; /* file offset dump */ | |
416 | break; | |
417 | case 'r': | |
418 | rflag = 1; /* read in reverse */ | |
419 | break; | |
420 | case 'v': | |
421 | dump = 1; /* mapping offset dump */ | |
422 | break; | |
423 | default: | |
9e1595e6 | 424 | exitcode = 1; |
48c46ee3 NS |
425 | return command_usage(&mread_cmd); |
426 | } | |
427 | } | |
428 | ||
429 | if (optind == argc) { | |
430 | offset = mapping->offset; | |
431 | length = mapping->length; | |
432 | } else if (optind == argc - 2) { | |
433 | init_cvtnum(&blocksize, §size); | |
434 | offset = cvtnum(blocksize, sectsize, argv[optind]); | |
435 | if (offset < 0) { | |
436 | printf(_("non-numeric offset argument -- %s\n"), | |
437 | argv[optind]); | |
9e1595e6 | 438 | exitcode = 1; |
48c46ee3 NS |
439 | return 0; |
440 | } | |
441 | optind++; | |
442 | length = cvtnum(blocksize, sectsize, argv[optind]); | |
443 | if (length < 0) { | |
444 | printf(_("non-numeric length argument -- %s\n"), | |
445 | argv[optind]); | |
9e1595e6 | 446 | exitcode = 1; |
48c46ee3 NS |
447 | return 0; |
448 | } | |
449 | } else { | |
450 | return command_usage(&mread_cmd); | |
451 | } | |
452 | ||
453 | start = check_mapping_range(mapping, offset, length, 0); | |
9e1595e6 DC |
454 | if (!start) { |
455 | exitcode = 1; | |
48c46ee3 | 456 | return 0; |
9e1595e6 | 457 | } |
8e192991 BN |
458 | dumpoffset = offset - mapping->offset; |
459 | if (dump == 2) | |
460 | printoffset = offset; | |
461 | else | |
462 | printoffset = dumpoffset; | |
48c46ee3 | 463 | |
9e1595e6 DC |
464 | if (alloc_buffer(pagesize, 0, 0) < 0) { |
465 | exitcode = 1; | |
48c46ee3 | 466 | return 0; |
9e1595e6 | 467 | } |
86715ccb | 468 | bp = (char *)io_buffer; |
48c46ee3 NS |
469 | |
470 | dumplen = length % pagesize; | |
471 | if (!dumplen) | |
472 | dumplen = pagesize; | |
473 | ||
474 | if (rflag) { | |
8e192991 BN |
475 | for (tmp = length - 1, c = 0; tmp >= 0; tmp--, c = 1) { |
476 | *bp = *(((char *)mapping->addr) + dumpoffset + tmp); | |
477 | cnt++; | |
478 | if (c && cnt == dumplen) { | |
479 | if (dump) { | |
480 | dump_buffer(printoffset, dumplen); | |
481 | printoffset += dumplen; | |
482 | } | |
86715ccb | 483 | bp = (char *)io_buffer; |
48c46ee3 | 484 | dumplen = pagesize; |
8e192991 BN |
485 | cnt = 0; |
486 | } else { | |
487 | bp++; | |
48c46ee3 | 488 | } |
8e192991 | 489 | } |
48c46ee3 | 490 | } else { |
8e192991 BN |
491 | for (tmp = 0, c = 0; tmp < length; tmp++, c = 1) { |
492 | *bp = *(((char *)mapping->addr) + dumpoffset + tmp); | |
493 | cnt++; | |
494 | if (c && cnt == dumplen) { | |
495 | if (dump) | |
496 | dump_buffer(printoffset + tmp - | |
497 | (dumplen - 1), dumplen); | |
86715ccb | 498 | bp = (char *)io_buffer; |
48c46ee3 | 499 | dumplen = pagesize; |
8e192991 BN |
500 | cnt = 0; |
501 | } else { | |
502 | bp++; | |
48c46ee3 | 503 | } |
48c46ee3 NS |
504 | } |
505 | } | |
506 | return 0; | |
507 | } | |
508 | ||
00ff2b10 | 509 | static int |
48c46ee3 NS |
510 | munmap_f( |
511 | int argc, | |
512 | char **argv) | |
513 | { | |
5ecb3de2 | 514 | ssize_t length; |
48c46ee3 NS |
515 | unsigned int offset; |
516 | ||
517 | if (munmap(mapping->addr, mapping->length) < 0) { | |
518 | perror("munmap"); | |
9e1595e6 | 519 | exitcode = 1; |
48c46ee3 NS |
520 | return 0; |
521 | } | |
522 | free(mapping->name); | |
523 | ||
524 | /* Shuffle the mapping table entries down over the removed entry */ | |
525 | offset = mapping - &maptable[0]; | |
526 | length = mapcount * sizeof(mmap_region_t); | |
527 | length -= (offset + 1) * sizeof(mmap_region_t); | |
528 | if (length) | |
529 | memmove(mapping, mapping + 1, length); | |
530 | ||
531 | /* Resize the memory allocated for the table, possibly freeing */ | |
532 | if (--mapcount) { | |
533 | maptable = (mmap_region_t *)realloc(maptable, /* shrinking */ | |
534 | mapcount * sizeof(mmap_region_t)); | |
535 | if (offset == mapcount) | |
536 | offset--; | |
537 | mapping = maptable + offset; | |
538 | } else { | |
539 | free(maptable); | |
540 | mapping = maptable = NULL; | |
541 | } | |
542 | maplist_f(); | |
543 | return 0; | |
544 | } | |
545 | ||
546 | static void | |
547 | mwrite_help(void) | |
548 | { | |
549 | printf(_( | |
550 | "\n" | |
551 | " dirties a range of bytes in the current memory mapping\n" | |
552 | "\n" | |
553 | " Example:\n" | |
554 | " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n" | |
555 | "\n" | |
556 | " Stores a byte into memory for a range within a mapping.\n" | |
557 | " The default stored value is 'X', repeated to fill the range specified.\n" | |
558 | " -S -- use an alternate seed character\n" | |
ff1f79a7 | 559 | " -r -- reverse order; start storing from the end of range, moving backward\n" |
48c46ee3 NS |
560 | " The stores are performed sequentially from the start offset by default.\n" |
561 | "\n")); | |
562 | } | |
563 | ||
00ff2b10 | 564 | static int |
48c46ee3 NS |
565 | mwrite_f( |
566 | int argc, | |
567 | char **argv) | |
568 | { | |
569 | off64_t offset, tmp; | |
5ecb3de2 | 570 | ssize_t length; |
48c46ee3 NS |
571 | void *start; |
572 | char *sp; | |
573 | int seed = 'X'; | |
574 | int rflag = 0; | |
cb7ba2b0 | 575 | int c; |
2c2f6d79 | 576 | size_t blocksize, sectsize; |
48c46ee3 NS |
577 | |
578 | while ((c = getopt(argc, argv, "rS:")) != EOF) { | |
579 | switch (c) { | |
580 | case 'r': | |
581 | rflag = 1; | |
582 | break; | |
583 | case 'S': | |
584 | seed = (int)strtol(optarg, &sp, 0); | |
585 | if (!sp || sp == optarg) { | |
586 | printf(_("non-numeric seed -- %s\n"), optarg); | |
587 | return 0; | |
588 | } | |
589 | break; | |
590 | default: | |
9e1595e6 | 591 | exitcode = 1; |
48c46ee3 NS |
592 | return command_usage(&mwrite_cmd); |
593 | } | |
594 | } | |
595 | ||
596 | if (optind == argc) { | |
597 | offset = mapping->offset; | |
598 | length = mapping->length; | |
599 | } else if (optind == argc - 2) { | |
600 | init_cvtnum(&blocksize, §size); | |
601 | offset = cvtnum(blocksize, sectsize, argv[optind]); | |
602 | if (offset < 0) { | |
603 | printf(_("non-numeric offset argument -- %s\n"), | |
604 | argv[optind]); | |
9e1595e6 | 605 | exitcode = 1; |
48c46ee3 NS |
606 | return 0; |
607 | } | |
608 | optind++; | |
609 | length = cvtnum(blocksize, sectsize, argv[optind]); | |
610 | if (length < 0) { | |
611 | printf(_("non-numeric length argument -- %s\n"), | |
612 | argv[optind]); | |
9e1595e6 | 613 | exitcode = 1; |
48c46ee3 NS |
614 | return 0; |
615 | } | |
616 | } else { | |
9e1595e6 | 617 | exitcode = 1; |
48c46ee3 NS |
618 | return command_usage(&mwrite_cmd); |
619 | } | |
620 | ||
621 | start = check_mapping_range(mapping, offset, length, 0); | |
9e1595e6 DC |
622 | if (!start) { |
623 | exitcode = 1; | |
48c46ee3 | 624 | return 0; |
9e1595e6 | 625 | } |
48c46ee3 | 626 | |
f0911c29 | 627 | offset -= mapping->offset; |
48c46ee3 | 628 | if (rflag) { |
8e192991 | 629 | for (tmp = offset + length -1; tmp >= offset; tmp--) |
48c46ee3 NS |
630 | ((char *)mapping->addr)[tmp] = seed; |
631 | } else { | |
632 | for (tmp = offset; tmp < offset + length; tmp++) | |
633 | ((char *)mapping->addr)[tmp] = seed; | |
634 | } | |
635 | ||
636 | return 0; | |
637 | } | |
638 | ||
a49984b3 | 639 | #ifdef HAVE_MREMAP |
4f20f6a3 ES |
640 | static void |
641 | mremap_help(void) | |
642 | { | |
643 | printf(_( | |
644 | "\n" | |
645 | " resizes the current memory mapping\n" | |
646 | "\n" | |
647 | " Examples:\n" | |
648 | " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n" | |
649 | "\n" | |
9ae168bb | 650 | " Resizes the mapping, growing or shrinking from the current size.\n" |
4f20f6a3 | 651 | " The default stored value is 'X', repeated to fill the range specified.\n" |
6f224a2c | 652 | " -f <new_address> -- use MREMAP_FIXED flag to mremap on new_address\n" |
4f20f6a3 ES |
653 | " -m -- use the MREMAP_MAYMOVE flag\n" |
654 | "\n")); | |
655 | } | |
656 | ||
00ff2b10 | 657 | static int |
4f20f6a3 ES |
658 | mremap_f( |
659 | int argc, | |
660 | char **argv) | |
661 | { | |
662 | ssize_t new_length; | |
6f224a2c | 663 | void *new_addr = NULL; |
4f20f6a3 ES |
664 | int flags = 0; |
665 | int c; | |
666 | size_t blocksize, sectsize; | |
667 | ||
6f224a2c ZL |
668 | init_cvtnum(&blocksize, §size); |
669 | ||
670 | while ((c = getopt(argc, argv, "f:m")) != EOF) { | |
4f20f6a3 ES |
671 | switch (c) { |
672 | case 'f': | |
673 | flags = MREMAP_FIXED|MREMAP_MAYMOVE; | |
5e303e25 ES |
674 | new_addr = (void *)(unsigned long)cvtnum(blocksize, |
675 | sectsize, optarg); | |
4f20f6a3 ES |
676 | break; |
677 | case 'm': | |
678 | flags = MREMAP_MAYMOVE; | |
679 | break; | |
680 | default: | |
9e1595e6 | 681 | exitcode = 1; |
4f20f6a3 ES |
682 | return command_usage(&mremap_cmd); |
683 | } | |
684 | } | |
685 | ||
9e1595e6 DC |
686 | if (optind != argc - 1) { |
687 | exitcode = 1; | |
6f224a2c | 688 | return command_usage(&mremap_cmd); |
9e1595e6 | 689 | } |
6f224a2c | 690 | |
4f20f6a3 ES |
691 | new_length = cvtnum(blocksize, sectsize, argv[optind]); |
692 | if (new_length < 0) { | |
693 | printf(_("non-numeric offset argument -- %s\n"), | |
694 | argv[optind]); | |
9e1595e6 | 695 | exitcode = 1; |
4f20f6a3 ES |
696 | return 0; |
697 | } | |
698 | ||
6f224a2c ZL |
699 | if (!new_addr) |
700 | new_addr = mremap(mapping->addr, mapping->length, | |
701 | new_length, flags); | |
702 | else | |
703 | new_addr = mremap(mapping->addr, mapping->length, | |
704 | new_length, flags, new_addr); | |
9e1595e6 | 705 | if (new_addr == MAP_FAILED) { |
4f20f6a3 | 706 | perror("mremap"); |
9e1595e6 DC |
707 | exitcode = 1; |
708 | return 0; | |
4f20f6a3 ES |
709 | } |
710 | ||
9e1595e6 DC |
711 | mapping->addr = new_addr; |
712 | mapping->length = new_length; | |
4f20f6a3 ES |
713 | return 0; |
714 | } | |
a49984b3 | 715 | #endif /* HAVE_MREMAP */ |
4f20f6a3 | 716 | |
48c46ee3 NS |
717 | void |
718 | mmap_init(void) | |
719 | { | |
ad765595 AM |
720 | mmap_cmd.name = "mmap"; |
721 | mmap_cmd.altname = "mm"; | |
48c46ee3 NS |
722 | mmap_cmd.cfunc = mmap_f; |
723 | mmap_cmd.argmin = 0; | |
724 | mmap_cmd.argmax = -1; | |
16bf0464 DC |
725 | mmap_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | |
726 | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT; | |
dad79683 | 727 | mmap_cmd.args = _("[N] | [-rwxS] [-s size] [off len]"); |
48c46ee3 NS |
728 | mmap_cmd.oneline = |
729 | _("mmap a range in the current file, show mappings"); | |
730 | mmap_cmd.help = mmap_help; | |
731 | ||
ad765595 AM |
732 | mread_cmd.name = "mread"; |
733 | mread_cmd.altname = "mr"; | |
48c46ee3 NS |
734 | mread_cmd.cfunc = mread_f; |
735 | mread_cmd.argmin = 0; | |
736 | mread_cmd.argmax = -1; | |
737 | mread_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; | |
738 | mread_cmd.args = _("[-r] [off len]"); | |
739 | mread_cmd.oneline = | |
740 | _("reads data from a region in the current memory mapping"); | |
741 | mread_cmd.help = mread_help; | |
742 | ||
ad765595 AM |
743 | msync_cmd.name = "msync"; |
744 | msync_cmd.altname = "ms"; | |
48c46ee3 NS |
745 | msync_cmd.cfunc = msync_f; |
746 | msync_cmd.argmin = 0; | |
747 | msync_cmd.argmax = -1; | |
748 | msync_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; | |
749 | msync_cmd.args = _("[-ais] [off len]"); | |
750 | msync_cmd.oneline = _("flush a region in the current memory mapping"); | |
751 | msync_cmd.help = msync_help; | |
752 | ||
ad765595 AM |
753 | munmap_cmd.name = "munmap"; |
754 | munmap_cmd.altname = "mu"; | |
48c46ee3 NS |
755 | munmap_cmd.cfunc = munmap_f; |
756 | munmap_cmd.argmin = 0; | |
757 | munmap_cmd.argmax = 0; | |
758 | munmap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; | |
759 | munmap_cmd.oneline = _("unmaps the current memory mapping"); | |
760 | ||
ad765595 AM |
761 | mwrite_cmd.name = "mwrite"; |
762 | mwrite_cmd.altname = "mw"; | |
48c46ee3 NS |
763 | mwrite_cmd.cfunc = mwrite_f; |
764 | mwrite_cmd.argmin = 0; | |
765 | mwrite_cmd.argmax = -1; | |
766 | mwrite_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; | |
767 | mwrite_cmd.args = _("[-r] [-S seed] [off len]"); | |
768 | mwrite_cmd.oneline = | |
769 | _("writes data into a region in the current memory mapping"); | |
770 | mwrite_cmd.help = mwrite_help; | |
771 | ||
a49984b3 | 772 | #ifdef HAVE_MREMAP |
4f20f6a3 ES |
773 | mremap_cmd.name = "mremap"; |
774 | mremap_cmd.altname = "mrm"; | |
775 | mremap_cmd.cfunc = mremap_f; | |
776 | mremap_cmd.argmin = 1; | |
6f224a2c | 777 | mremap_cmd.argmax = 3; |
4f20f6a3 | 778 | mremap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK; |
6f224a2c | 779 | mremap_cmd.args = _("[-m|-f <new_address>] newsize"); |
4f20f6a3 ES |
780 | mremap_cmd.oneline = |
781 | _("alters the size of the current memory mapping"); | |
782 | mremap_cmd.help = mremap_help; | |
a49984b3 | 783 | #endif /* HAVE_MREMAP */ |
4f20f6a3 | 784 | |
48c46ee3 NS |
785 | add_command(&mmap_cmd); |
786 | add_command(&mread_cmd); | |
787 | add_command(&msync_cmd); | |
788 | add_command(&munmap_cmd); | |
789 | add_command(&mwrite_cmd); | |
a49984b3 | 790 | #ifdef HAVE_MREMAP |
4f20f6a3 | 791 | add_command(&mremap_cmd); |
a49984b3 | 792 | #endif /* HAVE_MREMAP */ |
48c46ee3 | 793 | } |