]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/write.c
xfsprogs: minor endian annotation fixes
[thirdparty/xfsprogs-dev.git] / db / write.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a 7#include "libxfs.h"
2bd0ea18
NS
8#include <ctype.h>
9#include <time.h>
10#include "bit.h"
11#include "block.h"
12#include "command.h"
2bd0ea18
NS
13#include "type.h"
14#include "faddr.h"
15#include "fprint.h"
16#include "field.h"
17#include "flist.h"
18#include "io.h"
4ca431fc 19#include "init.h"
2bd0ea18
NS
20#include "output.h"
21#include "print.h"
22#include "write.h"
23#include "malloc.h"
24
25static int write_f(int argc, char **argv);
26static void write_help(void);
27
28static const cmdinfo_t write_cmd =
c9f5e3db 29 { "write", NULL, write_f, 0, -1, 0, N_("[-c] [field or value]..."),
9ee7055c 30 N_("write value to disk"), write_help };
2bd0ea18
NS
31
32void
33write_init(void)
34{
4ca431fc 35 if (!expert_mode)
2bd0ea18
NS
36 return;
37
38 add_command(&write_cmd);
39 srand48(clock());
40}
41
dfc130f3 42static void
2bd0ea18
NS
43write_help(void)
44{
9ee7055c 45 dbprintf(_(
2bd0ea18
NS
46"\n"
47" The 'write' command takes on different personalities depending on the\n"
48" type of object being worked with.\n\n"
49" Write has 3 modes:\n"
50" 'struct mode' - is active anytime you're looking at a filesystem object\n"
51" which contains individual fields (ex: an inode).\n"
52" 'data mode' - is active anytime you set a disk address directly or set\n"
53" the type to 'data'.\n"
54" 'string mode' - only used for writing symlink blocks.\n"
55"\n"
56" Examples:\n"
57" Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n"
58" 'write fname \"hello\\000\"' - write superblock fname.\n"
59" (note: in struct mode strings are not null terminated)\n"
60" 'write fname #6669736800' - write superblock fname with hex.\n"
dfc130f3 61" 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n"
2bd0ea18
NS
62" - write superblock uuid.\n"
63" Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n"
64" 'write lshift 3' - shift the block 3 bytes to the left\n"
65" 'write sequence 1 5' - write a cycle of number [1-5] through\n"
66" the entire block.\n"
67" String mode: 'write \"This_is_a_filename\" - write null terminated string.\n"
68"\n"
69" In data mode type 'write' by itself for a list of specific commands.\n\n"
86769b32
DC
70" Specifying the -c option will allow writes of invalid (corrupt) data with\n"
71" an invalid CRC. Specifying the -d option will allow writes of invalid data,\n"
72" but still recalculate the CRC so we are forced to check and detect the\n"
73" invalid data appropriately.\n\n"
9ee7055c 74));
2bd0ea18
NS
75
76}
77
78static int
79write_f(
80 int argc,
81 char **argv)
82{
83 pfunc_t pf;
84 extern char *progname;
c9f5e3db 85 int c;
86769b32
DC
86 bool corrupt = false; /* Allow write of bad data w/ invalid CRC */
87 bool invalid_data = false; /* Allow write of bad data w/ valid CRC */
88 struct xfs_buf_ops local_ops;
c9f5e3db 89 const struct xfs_buf_ops *stashed_ops = NULL;
2bd0ea18 90
4ca431fc 91 if (x.isreadonly & LIBXFS_ISREADONLY) {
9ee7055c 92 dbprintf(_("%s started in read only mode, writing disabled\n"),
2bd0ea18
NS
93 progname);
94 return 0;
95 }
96
97 if (cur_typ == NULL) {
9ee7055c 98 dbprintf(_("no current type\n"));
2bd0ea18
NS
99 return 0;
100 }
101
102 pf = cur_typ->pfunc;
103 if (pf == NULL) {
9ee7055c 104 dbprintf(_("no handler function for type %s, write unsupported.\n"),
2bd0ea18
NS
105 cur_typ->name);
106 return 0;
107 }
108
86769b32 109 while ((c = getopt(argc, argv, "cd")) != EOF) {
c9f5e3db
ES
110 switch (c) {
111 case 'c':
86769b32
DC
112 corrupt = true;
113 break;
114 case 'd':
115 invalid_data = true;
c9f5e3db
ES
116 break;
117 default:
118 dbprintf(_("bad option for write command\n"));
119 return 0;
120 }
121 }
122
86769b32
DC
123 if (corrupt && invalid_data) {
124 dbprintf(_("Cannot specify both -c and -d options\n"));
125 return 0;
126 }
127
6f7f8928 128 if (invalid_data &&
ef209a96
DW
129 iocur_top->typ->crc_off == TYP_F_NO_CRC_OFF &&
130 xfs_sb_version_hascrc(&mp->m_sb)) {
86769b32
DC
131 dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
132 return 0;
133 }
134
c9f5e3db
ES
135 argc -= optind;
136 argv += optind;
137
86769b32
DC
138 /*
139 * If the buffer has no verifier or we are using standard verifier
140 * paths, then just write it out and return
141 */
142 if (!iocur_top->bp->b_ops ||
143 !(corrupt || invalid_data)) {
144 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
145 return 0;
146 }
147
148
149 /* Temporarily remove write verifier to write bad data */
150 stashed_ops = iocur_top->bp->b_ops;
151 local_ops.verify_read = stashed_ops->verify_read;
152 iocur_top->bp->b_ops = &local_ops;
153
ef209a96
DW
154 if (!xfs_sb_version_hascrc(&mp->m_sb)) {
155 local_ops.verify_write = xfs_dummy_verify;
156 } else if (corrupt) {
86769b32
DC
157 local_ops.verify_write = xfs_dummy_verify;
158 dbprintf(_("Allowing write of corrupted data and bad CRC\n"));
89baf918
DW
159 } else if (iocur_top->typ->crc_off == TYP_F_CRC_FUNC) {
160 local_ops.verify_write = iocur_top->typ->set_crc;
161 dbprintf(_("Allowing write of corrupted data with good CRC\n"));
86769b32
DC
162 } else { /* invalid data */
163 local_ops.verify_write = xfs_verify_recalc_crc;
164 dbprintf(_("Allowing write of corrupted data with good CRC\n"));
c9f5e3db 165 }
2bd0ea18
NS
166
167 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
168
86769b32 169 iocur_top->bp->b_ops = stashed_ops;
c9f5e3db 170
2bd0ea18
NS
171 return 0;
172}
173
174/* compare significant portions of commands */
175
176static int
177sigcmp(
178 char *s1,
179 char *s2,
180 int sig)
181{
182 int sigcnt;
183
184 if (!s1 || !s2)
185 return 0;
186
187 for (sigcnt = 0; *s1 == *s2; s1++, s2++) {
188 sigcnt++;
189 if (*s1 == '\0')
190 return 1;
191 }
192 if (*s1 && *s2)
193 return 0;
194
195 if (sig && (sigcnt >= sig))
196 return 1;
197
198 return 0;
199}
200
201/* ARGSUSED */
202static void
203bwrite_lshift(
204 int start,
205 int len,
206 int shift,
207 int from,
208 int to)
209{
210 char *base;
211
212 if (shift == -1)
213 shift = 1;
214 if (start == -1)
215 start = 0;
216 if (len == -1)
217 len = iocur_top->len - start;
218
219 if (len+start > iocur_top->len) {
9ee7055c 220 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
221 len, iocur_top->len);
222 }
223
224 base = (char *)iocur_top->data + start;
225
226 memcpy(base, base+shift, len-shift);
227 memset(base+(len-shift), 0, shift);
228}
229
230/* ARGSUSED */
231static void
232bwrite_rshift(
233 int start,
234 int len,
235 int shift,
236 int from,
237 int to)
238{
239 char *base;
240
241 if (shift == -1)
242 shift = 1;
243 if (start == -1)
244 start = 0;
245 if (len == -1)
246 len = iocur_top->len - start;
247
248 if (len+start > iocur_top->len) {
9ee7055c 249 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
250 len, iocur_top->len);
251 }
252
253 base = (char *)iocur_top->data + start;
254
255 memcpy(base+shift, base, len-shift);
256 memset(base, 0, shift);
257}
258
259/* ARGSUSED */
260static void
261bwrite_lrot(
262 int start,
263 int len,
264 int shift,
265 int from,
266 int to)
267{
268 char *base;
269 char *hold_region;
270
271 if (shift == -1)
272 shift = 1;
273 if (start == -1)
274 start = 0;
275 if (len == -1)
276 len = iocur_top->len - start;
277
278 if (len+start > iocur_top->len) {
9ee7055c 279 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
280 len, iocur_top->len);
281 }
282
283 base = (char *)iocur_top->data + start;
284
285 hold_region = xmalloc(shift);
286 memcpy(hold_region, base, shift);
287 memcpy(base, base+shift, len-shift);
288 memcpy(base+(len-shift), hold_region, shift);
355ac015 289 free(hold_region);
2bd0ea18
NS
290}
291
292/* ARGSUSED */
293static void
294bwrite_rrot(
295 int start,
296 int len,
297 int shift,
298 int from,
299 int to)
300{
301 char *base;
302 char *hold_region;
303
304 if (shift == -1)
305 shift = 1;
306 if (start == -1)
307 start = 0;
308 if (len == -1)
309 len = iocur_top->len - start;
310
311 if (len+start > iocur_top->len) {
9ee7055c 312 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
313 len, iocur_top->len);
314 }
315
316 base = (char *)iocur_top->data + start;
317
318 hold_region = xmalloc(shift);
319 memcpy(hold_region, base+(len-shift), shift);
0e6b2a43 320 memmove(base+shift, base, len-shift);
2bd0ea18 321 memcpy(base, hold_region, shift);
355ac015 322 free(hold_region);
2bd0ea18
NS
323}
324
325/* ARGSUSED */
326static void
327bwrite_seq(
328 int start,
329 int len,
330 int step,
331 int from,
332 int to)
333{
334 int i;
335 int tmp;
336 int base;
337 int range;
338 int top;
0e6b2a43 339 char *buf;
2bd0ea18
NS
340
341 if (start == -1)
342 start = 0;
343
344 if (len == -1)
345 len = iocur_top->len - start;
346
347 if (len+start > iocur_top->len) {
9ee7055c 348 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
349 len, iocur_top->len);
350 }
351
352 if (from == -1 || from > 255)
353 from = 0;
354 if (to == -1 || to > 255)
355 to = 255;
356 if (step == -1)
357 step = 1;
358
359 base = from;
360 top = to;
361 if (from > to) {
362 base = to;
363 top = from;
364 if (step > 0)
365 step = -step;
366 }
367
368 range = top - base;
0e6b2a43 369 buf = (char *)iocur_top->data + start;
2bd0ea18
NS
370
371 tmp = 0;
372 for (i = start; i < start+len; i++) {
373 *buf++ = tmp + base;
374 tmp = (tmp + step)%(range+1);
375 }
376}
377
378/* ARGSUSED */
379static void
380bwrite_random(
381 int start,
382 int len,
383 int shift,
384 int from,
385 int to)
386{
387 int i;
0e6b2a43 388 char *buf;
2bd0ea18
NS
389
390 if (start == -1)
391 start = 0;
392
393 if (len == -1)
394 len = iocur_top->len - start;
395
396 if (len+start > iocur_top->len) {
9ee7055c 397 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
398 len, iocur_top->len);
399 }
400
0e6b2a43
NS
401 buf = (char *)iocur_top->data + start;
402
2bd0ea18
NS
403 for (i = start; i < start+len; i++)
404 *buf++ = (char)lrand48();
405}
406
407/* ARGSUSED */
408static void
409bwrite_fill(
410 int start,
411 int len,
412 int value,
413 int from,
414 int to)
415{
416 char *base;
417
418 if (value == -1)
419 value = 0;
420 if (start == -1)
421 start = 0;
422 if (len == -1)
423 len = iocur_top->len - start;
424
425 if (len+start > iocur_top->len) {
9ee7055c 426 dbprintf(_("length (%d) too large for data block size (%d)"),
2bd0ea18
NS
427 len, iocur_top->len);
428 }
429
430 base = (char *)iocur_top->data + start;
431
432 memset(base, value, len);
433}
434
435static struct bw_cmd {
436 void (*cmdfunc)(int,int,int,int,int);
437 char *cmdstr;
438 int sig_chars;
439 int argmin;
440 int argmax;
441 int shiftcount_arg;
442 int from_arg;
443 int to_arg;
444 int start_arg;
445 int len_arg;
446 char *usage;
447} bw_cmdtab[] = {
448 /* cmd sig min max sh frm to start len */
449 { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
450 "[shiftcount] [start] [len]", },
451 { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
452 "[shiftcount] [start] [len]", },
453 { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
454 "[shiftcount] [start] [len]", },
455 { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
456 "[shiftcount] [start] [len]", },
457 { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
458 "[from] [to] [start] [len]", },
459 { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2,
460 "[start] [len]", },
461 { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
462 "num [start] [len]" }
463};
464
465#define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
466
467static int
468convert_oct(
469 char *arg,
470 int *ret)
471{
472 int count;
473 int i;
474 int val = 0;
475
476 /* only allow 1 case, '\' and 3 octal digits (or less) */
477
478 for (count = 0; count < 3; count++) {
479 if (arg[count] == '\0')
480 break;
481
482 if ((arg[count] < '0') && (arg[count] > '7'))
483 break;
484 }
485
486 for (i = 0; i < count; i++) {
487 val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3);
488 }
489
490 *ret = val&0xff;
491
492 return(count);
493}
494
495#define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
496
dc151328
MT
497/*
498 * convert_arg allows input in the following forms:
499 *
500 * - A string ("ABTB") whose ASCII value is placed in an array in the order
501 * matching the input.
502 *
503 * - An even number of hex numbers. If the length is greater than 64 bits,
504 * then the output is an array of bytes whose top nibble is the first hex
505 * digit in the input, the lower nibble is the second hex digit in the
506 * input. UUID entries are entered in this manner.
507 *
508 * - A decimal or hexadecimal integer to be used with setbitval().
509 *
510 * Numbers that are passed to setbitval() need to be in big endian format and
511 * are adjusted in the buffer so that the first input bit is to be be written to
512 * the first bit in the output.
513 */
2bd0ea18
NS
514static char *
515convert_arg(
dc151328
MT
516 char *arg,
517 int bit_length)
2bd0ea18 518{
dc151328
MT
519 int i;
520 int alloc_size;
521 int octval;
522 int offset;
523 int ret;
524 static char *buf = NULL;
525 char *endp;
526 char *rbuf;
527 char *ostr;
8e1338fb 528 __be64 *value;
dc151328 529 __u64 val = 0;
2bd0ea18
NS
530
531 if (bit_length <= 64)
532 alloc_size = 8;
533 else
dc151328 534 alloc_size = (bit_length + 7) / 8;
2bd0ea18
NS
535
536 buf = xrealloc(buf, alloc_size);
537 memset(buf, 0, alloc_size);
8e1338fb 538 value = (__be64 *)buf;
2bd0ea18
NS
539 rbuf = buf;
540
541 if (*arg == '\"') {
dc151328 542 /* input a string and output ASCII array of characters */
2bd0ea18
NS
543
544 /* zap closing quote if there is one */
dc151328
MT
545 ostr = strrchr(arg + 1, '\"');
546 if (ostr)
2bd0ea18
NS
547 *ostr = '\0';
548
dc151328 549 ostr = arg + 1;
2bd0ea18
NS
550 for (i = 0; i < alloc_size; i++) {
551 if (!*ostr)
552 break;
553
dc151328 554 /* do octal conversion */
2bd0ea18 555 if (*ostr == '\\') {
dc151328
MT
556 if (*(ostr + 1) >= '0' || *(ostr + 1) <= '7') {
557 ret = convert_oct(ostr + 1, &octval);
2bd0ea18 558 *rbuf++ = octval;
dc151328 559 ostr += ret + 1;
2bd0ea18
NS
560 continue;
561 }
562 }
563 *rbuf++ = *ostr++;
564 }
2bd0ea18 565 return buf;
dc151328
MT
566 }
567
568 if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
dfc130f3
RC
569 /*
570 * handle hex blocks ie
571 * #00112233445566778899aabbccddeeff
572 * and uuids ie
573 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
75efd6ca
ES
574 *
575 * (but if it starts with "-" assume it's just an integer)
dfc130f3 576 */
dc151328
MT
577 int bytes = bit_length / NBBY;
578
579 /* is this an array of hec numbers? */
580 if (bit_length % NBBY)
581 return NULL;
dfc130f3
RC
582
583 /* skip leading hash */
dc151328
MT
584 if (*arg == '#')
585 arg++;
dfc130f3
RC
586
587 while (*arg && bytes--) {
dc151328
MT
588 /* skip hypens */
589 while (*arg == '-')
590 arg++;
591
592 /* get first nybble */
593 if (!isxdigit((int)*arg))
594 return NULL;
595 *rbuf = NYBBLE((int)*arg) << 4;
596 arg++;
597
598 /* skip more hyphens */
599 while (*arg == '-')
600 arg++;
601
602 /* get second nybble */
603 if (!isxdigit((int)*arg))
604 return NULL;
605 *rbuf++ |= NYBBLE((int)*arg);
606 arg++;
dfc130f3 607 }
dc151328
MT
608 if (bytes < 0 && *arg)
609 return NULL;
610
dfc130f3 611 return buf;
2bd0ea18 612 }
dc151328
MT
613
614 /* handle decimal / hexadecimal integers */
615 val = strtoll(arg, &endp, 0);
616 /* return if not a clean number */
617 if (*endp != '\0')
618 return NULL;
619
620 /* Does the value fit into the range of the destination bitfield? */
97ada363 621 if (bit_length < 64 && (val >> bit_length) > 0)
dc151328
MT
622 return NULL;
623 /*
624 * If the length of the field is not a multiple of a byte, push
625 * the bits up in the field, so the most signicant field bit is
626 * the most significant bit in the byte:
627 *
628 * before:
629 * val |----|----|----|----|----|--MM|mmmm|llll|
630 * after
631 * val |----|----|----|----|----|MMmm|mmll|ll00|
632 */
633 offset = bit_length % NBBY;
634 if (offset)
635 val <<= (NBBY - offset);
636
637 /*
638 * convert to big endian and copy into the array
639 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
640 */
641 *value = cpu_to_be64(val);
642
643 /*
644 * Align the array to point to the field in the array.
645 * rbuf = |MMmm|mmll|ll00|
646 */
647 offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64));
648 rbuf += offset;
649 return rbuf;
2bd0ea18
NS
650}
651
652
653/* ARGSUSED */
654void
655write_struct(
656 const field_t *fields,
657 int argc,
658 char **argv)
659{
660 const ftattr_t *fa;
661 flist_t *fl;
dc151328
MT
662 flist_t *sfl;
663 int bit_length;
664 char *buf;
2bd0ea18
NS
665 int parentoffset;
666
667 if (argc != 2) {
9ee7055c 668 dbprintf(_("usage: write fieldname value\n"));
2bd0ea18
NS
669 return;
670 }
671
672 fl = flist_scan(argv[0]);
673 if (!fl) {
9ee7055c 674 dbprintf(_("unable to parse '%s'.\n"), argv[0]);
2bd0ea18
NS
675 return;
676 }
677
678 /* if we're a root field type, go down 1 layer to get field list */
679 if (fields->name[0] == '\0') {
680 fa = &ftattrtab[fields->ftyp];
681 ASSERT(fa->ftyp == fields->ftyp);
682 fields = fa->subfld;
683 }
684
685 /* run down the field list and set offsets into the data */
686 if (!flist_parse(fields, fl, iocur_top->data, 0)) {
687 flist_free(fl);
9ee7055c 688 dbprintf(_("parsing error\n"));
2bd0ea18
NS
689 return;
690 }
691
692 sfl = fl;
693 parentoffset = 0;
694 while (sfl->child) {
695 parentoffset = sfl->offset;
696 sfl = sfl->child;
697 }
698
4222d000
DC
699 /*
700 * For structures, fsize * fcount tells us the size of the region we are
701 * modifying, which is usually a single structure member and is pointed
702 * to by the last child in the list.
703 *
704 * However, if the base structure is an array and we have a direct index
705 * into the array (e.g. write bno[5]) then we are returned a single
706 * flist object with the offset pointing directly at the location we
707 * need to modify. The length of the object we are modifying is then
708 * determined by the size of the individual array entry (fsize) and the
709 * indexes defined in the object, not the overall size of the array
710 * (which is what fcount returns).
711 */
2bd0ea18 712 bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
4222d000
DC
713 if (sfl->fld->flags & FLD_ARRAY)
714 bit_length *= sfl->high - sfl->low + 1;
715 else
716 bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
2bd0ea18
NS
717
718 /* convert this to a generic conversion routine */
719 /* should be able to handle str, num, or even labels */
dfc130f3 720
2bd0ea18
NS
721 buf = convert_arg(argv[1], bit_length);
722 if (!buf) {
9ee7055c 723 dbprintf(_("unable to convert value '%s'.\n"), argv[1]);
9c1c2e32 724 flist_free(fl);
2bd0ea18
NS
725 return;
726 }
727
dfc130f3 728 setbitval(iocur_top->data, sfl->offset, bit_length, buf);
2bd0ea18
NS
729 write_cur();
730
731 flist_print(fl);
dfc130f3 732 print_flist(fl);
2bd0ea18
NS
733 flist_free(fl);
734}
735
736/* ARGSUSED */
737void
738write_string(
739 const field_t *fields,
740 int argc,
741 char **argv)
742{
743 char *buf;
744 int i;
745
746 if (argc != 1) {
9ee7055c 747 dbprintf(_("usage (in string mode): write \"string...\"\n"));
2bd0ea18
NS
748 return;
749 }
750
751 buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8));
752 for (i = 0; i < iocur_top->len; i++) {
753 ((char *)iocur_top->data)[i] = *buf;
754 if (*buf++ == '\0')
755 break;
756 }
757
758 /* write back to disk */
759 write_cur();
760}
761
762/* ARGSUSED */
763void
764write_block(
765 const field_t *fields,
766 int argc,
767 char **argv)
768{
769 int i;
dfc130f3 770 int shiftcount = -1;
2bd0ea18
NS
771 int start = -1;
772 int len = -1;
773 int from = -1;
774 int to = -1;
775 struct bw_cmd *cmd = NULL;
776
777 if (argc <= 1 || argc > 5)
778 goto block_usage;
779
780 for (i = 0; i < BWRITE_CMD_MAX; i++) {
781 if (sigcmp(argv[0], bw_cmdtab[i].cmdstr,
782 bw_cmdtab[i].sig_chars)) {
783 cmd = &bw_cmdtab[i];
784 break;
785 }
786 }
787
788 if (!cmd) {
9ee7055c 789 dbprintf(_("write: invalid subcommand\n"));
2bd0ea18
NS
790 goto block_usage;
791 }
792
793 if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) {
9ee7055c 794 dbprintf(_("write %s: invalid number of arguments\n"),
2bd0ea18
NS
795 cmd->cmdstr);
796 goto block_usage;
797 }
dfc130f3 798
2bd0ea18
NS
799 if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc))
800 shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0);
801 if (cmd->start_arg && (cmd->start_arg < argc))
802 start = (int)strtoul(argv[cmd->start_arg], NULL, 0);
803 if (cmd->len_arg && (cmd->len_arg < argc))
804 len = (int)strtoul(argv[cmd->len_arg], NULL, 0);
805 if (cmd->from_arg && (cmd->len_arg < argc))
806 from = (int)strtoul(argv[cmd->from_arg], NULL, 0);
807 if (cmd->to_arg && (cmd->len_arg < argc))
808 to = (int)strtoul(argv[cmd->to_arg], NULL, 0);
809
810 cmd->cmdfunc(start, len, shiftcount, from, to);
811
812 /* write back to disk */
813 write_cur();
814 return;
815
816 block_usage:
817
9ee7055c 818 dbprintf(_("usage: write (in data mode)\n"));
2bd0ea18
NS
819 for (i = 0; i < BWRITE_CMD_MAX; i++) {
820 dbprintf(" %-9.9s %s\n",
821 bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage);
822 }
823 dbprintf("\n");
824 return;
825}