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