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