2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
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
7 * published by the Free Software Foundation.
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.
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
37 static int write_f(int argc
, char **argv
);
38 static void write_help(void);
40 static const cmdinfo_t write_cmd
=
41 { "write", NULL
, write_f
, 0, -1, 0, N_("[-c] [field or value]..."),
42 N_("write value to disk"), write_help
};
50 add_command(&write_cmd
);
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"
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"
73 " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n"
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"
81 " In data mode type 'write' by itself for a list of specific commands.\n\n"
82 " Specifying the -c option will allow writes of invalid (corrupt) data with\n"
83 " an invalid CRC. Specifying the -d option will allow writes of invalid data,\n"
84 " but still recalculate the CRC so we are forced to check and detect the\n"
85 " invalid data appropriately.\n\n"
96 extern char *progname
;
98 bool corrupt
= false; /* Allow write of bad data w/ invalid CRC */
99 bool invalid_data
= false; /* Allow write of bad data w/ valid CRC */
100 struct xfs_buf_ops local_ops
;
101 const struct xfs_buf_ops
*stashed_ops
= NULL
;
103 if (x
.isreadonly
& LIBXFS_ISREADONLY
) {
104 dbprintf(_("%s started in read only mode, writing disabled\n"),
109 if (cur_typ
== NULL
) {
110 dbprintf(_("no current type\n"));
116 dbprintf(_("no handler function for type %s, write unsupported.\n"),
121 while ((c
= getopt(argc
, argv
, "cd")) != EOF
) {
130 dbprintf(_("bad option for write command\n"));
135 if (corrupt
&& invalid_data
) {
136 dbprintf(_("Cannot specify both -c and -d options\n"));
141 iocur_top
->typ
->crc_off
== TYP_F_NO_CRC_OFF
&&
142 !iocur_top
->ino_buf
&&
143 !iocur_top
->dquot_buf
) {
144 dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
152 * If the buffer has no verifier or we are using standard verifier
153 * paths, then just write it out and return
155 if (!iocur_top
->bp
->b_ops
||
156 !(corrupt
|| invalid_data
)) {
157 (*pf
)(DB_WRITE
, cur_typ
->fields
, argc
, argv
);
162 /* Temporarily remove write verifier to write bad data */
163 stashed_ops
= iocur_top
->bp
->b_ops
;
164 local_ops
.verify_read
= stashed_ops
->verify_read
;
165 iocur_top
->bp
->b_ops
= &local_ops
;
168 local_ops
.verify_write
= xfs_dummy_verify
;
169 dbprintf(_("Allowing write of corrupted data and bad CRC\n"));
170 } else if (iocur_top
->ino_buf
) {
171 local_ops
.verify_write
= xfs_verify_recalc_inode_crc
;
172 dbprintf(_("Allowing write of corrupted inode with good CRC\n"));
173 } else if (iocur_top
->dquot_buf
) {
174 local_ops
.verify_write
= xfs_verify_recalc_dquot_crc
;
175 dbprintf(_("Allowing write of corrupted dquot with good CRC\n"));
176 } else if (iocur_top
->typ
->crc_off
== TYP_F_CRC_FUNC
) {
177 local_ops
.verify_write
= iocur_top
->typ
->set_crc
;
178 dbprintf(_("Allowing write of corrupted data with good CRC\n"));
179 } else { /* invalid data */
180 local_ops
.verify_write
= xfs_verify_recalc_crc
;
181 dbprintf(_("Allowing write of corrupted data with good CRC\n"));
184 (*pf
)(DB_WRITE
, cur_typ
->fields
, argc
, argv
);
186 iocur_top
->bp
->b_ops
= stashed_ops
;
191 /* compare significant portions of commands */
204 for (sigcnt
= 0; *s1
== *s2
; s1
++, s2
++) {
212 if (sig
&& (sigcnt
>= sig
))
234 len
= iocur_top
->len
- start
;
236 if (len
+start
> iocur_top
->len
) {
237 dbprintf(_("length (%d) too large for data block size (%d)"),
238 len
, iocur_top
->len
);
241 base
= (char *)iocur_top
->data
+ start
;
243 memcpy(base
, base
+shift
, len
-shift
);
244 memset(base
+(len
-shift
), 0, shift
);
263 len
= iocur_top
->len
- start
;
265 if (len
+start
> iocur_top
->len
) {
266 dbprintf(_("length (%d) too large for data block size (%d)"),
267 len
, iocur_top
->len
);
270 base
= (char *)iocur_top
->data
+ start
;
272 memcpy(base
+shift
, base
, len
-shift
);
273 memset(base
, 0, shift
);
293 len
= iocur_top
->len
- start
;
295 if (len
+start
> iocur_top
->len
) {
296 dbprintf(_("length (%d) too large for data block size (%d)"),
297 len
, iocur_top
->len
);
300 base
= (char *)iocur_top
->data
+ start
;
302 hold_region
= xmalloc(shift
);
303 memcpy(hold_region
, base
, shift
);
304 memcpy(base
, base
+shift
, len
-shift
);
305 memcpy(base
+(len
-shift
), hold_region
, shift
);
326 len
= iocur_top
->len
- start
;
328 if (len
+start
> iocur_top
->len
) {
329 dbprintf(_("length (%d) too large for data block size (%d)"),
330 len
, iocur_top
->len
);
333 base
= (char *)iocur_top
->data
+ start
;
335 hold_region
= xmalloc(shift
);
336 memcpy(hold_region
, base
+(len
-shift
), shift
);
337 memmove(base
+shift
, base
, len
-shift
);
338 memcpy(base
, hold_region
, shift
);
362 len
= iocur_top
->len
- start
;
364 if (len
+start
> iocur_top
->len
) {
365 dbprintf(_("length (%d) too large for data block size (%d)"),
366 len
, iocur_top
->len
);
369 if (from
== -1 || from
> 255)
371 if (to
== -1 || to
> 255)
386 buf
= (char *)iocur_top
->data
+ start
;
389 for (i
= start
; i
< start
+len
; i
++) {
391 tmp
= (tmp
+ step
)%(range
+1);
411 len
= iocur_top
->len
- start
;
413 if (len
+start
> iocur_top
->len
) {
414 dbprintf(_("length (%d) too large for data block size (%d)"),
415 len
, iocur_top
->len
);
418 buf
= (char *)iocur_top
->data
+ start
;
420 for (i
= start
; i
< start
+len
; i
++)
421 *buf
++ = (char)lrand48();
440 len
= iocur_top
->len
- start
;
442 if (len
+start
> iocur_top
->len
) {
443 dbprintf(_("length (%d) too large for data block size (%d)"),
444 len
, iocur_top
->len
);
447 base
= (char *)iocur_top
->data
+ start
;
449 memset(base
, value
, len
);
452 static struct bw_cmd
{
453 void (*cmdfunc
)(int,int,int,int,int);
465 /* cmd sig min max sh frm to start len */
466 { bwrite_lshift
, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
467 "[shiftcount] [start] [len]", },
468 { bwrite_rshift
, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
469 "[shiftcount] [start] [len]", },
470 { bwrite_lrot
, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
471 "[shiftcount] [start] [len]", },
472 { bwrite_rrot
, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
473 "[shiftcount] [start] [len]", },
474 { bwrite_seq
, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
475 "[from] [to] [start] [len]", },
476 { bwrite_random
, "random", 3, 0, 2, 0, 0, 0, 1, 2,
478 { bwrite_fill
, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
479 "num [start] [len]" }
482 #define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
493 /* only allow 1 case, '\' and 3 octal digits (or less) */
495 for (count
= 0; count
< 3; count
++) {
496 if (arg
[count
] == '\0')
499 if ((arg
[count
] < '0') && (arg
[count
] > '7'))
503 for (i
= 0; i
< count
; i
++) {
504 val
|= ((arg
[(count
-1)-i
]-'0')&0x07)<<(i
*3);
512 #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
515 * convert_arg allows input in the following forms:
517 * - A string ("ABTB") whose ASCII value is placed in an array in the order
518 * matching the input.
520 * - An even number of hex numbers. If the length is greater than 64 bits,
521 * then the output is an array of bytes whose top nibble is the first hex
522 * digit in the input, the lower nibble is the second hex digit in the
523 * input. UUID entries are entered in this manner.
525 * - A decimal or hexadecimal integer to be used with setbitval().
527 * Numbers that are passed to setbitval() need to be in big endian format and
528 * are adjusted in the buffer so that the first input bit is to be be written to
529 * the first bit in the output.
541 static char *buf
= NULL
;
548 if (bit_length
<= 64)
551 alloc_size
= (bit_length
+ 7) / 8;
553 buf
= xrealloc(buf
, alloc_size
);
554 memset(buf
, 0, alloc_size
);
555 value
= (__u64
*)buf
;
559 /* input a string and output ASCII array of characters */
561 /* zap closing quote if there is one */
562 ostr
= strrchr(arg
+ 1, '\"');
567 for (i
= 0; i
< alloc_size
; i
++) {
571 /* do octal conversion */
573 if (*(ostr
+ 1) >= '0' || *(ostr
+ 1) <= '7') {
574 ret
= convert_oct(ostr
+ 1, &octval
);
585 if (arg
[0] == '#' || ((arg
[0] != '-') && strchr(arg
,'-'))) {
587 * handle hex blocks ie
588 * #00112233445566778899aabbccddeeff
590 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
592 * (but if it starts with "-" assume it's just an integer)
594 int bytes
= bit_length
/ NBBY
;
596 /* is this an array of hec numbers? */
597 if (bit_length
% NBBY
)
600 /* skip leading hash */
604 while (*arg
&& bytes
--) {
609 /* get first nybble */
610 if (!isxdigit((int)*arg
))
612 *rbuf
= NYBBLE((int)*arg
) << 4;
615 /* skip more hyphens */
619 /* get second nybble */
620 if (!isxdigit((int)*arg
))
622 *rbuf
++ |= NYBBLE((int)*arg
);
625 if (bytes
< 0 && *arg
)
631 /* handle decimal / hexadecimal integers */
632 val
= strtoll(arg
, &endp
, 0);
633 /* return if not a clean number */
637 /* Does the value fit into the range of the destination bitfield? */
638 if (bit_length
< 64 && (val
>> bit_length
) > 0)
641 * If the length of the field is not a multiple of a byte, push
642 * the bits up in the field, so the most signicant field bit is
643 * the most significant bit in the byte:
646 * val |----|----|----|----|----|--MM|mmmm|llll|
648 * val |----|----|----|----|----|MMmm|mmll|ll00|
650 offset
= bit_length
% NBBY
;
652 val
<<= (NBBY
- offset
);
655 * convert to big endian and copy into the array
656 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
658 *value
= cpu_to_be64(val
);
661 * Align the array to point to the field in the array.
662 * rbuf = |MMmm|mmll|ll00|
664 offset
= sizeof(__be64
) - 1 - ((bit_length
- 1) / sizeof(__be64
));
673 const field_t
*fields
,
685 dbprintf(_("usage: write fieldname value\n"));
689 fl
= flist_scan(argv
[0]);
691 dbprintf(_("unable to parse '%s'.\n"), argv
[0]);
695 /* if we're a root field type, go down 1 layer to get field list */
696 if (fields
->name
[0] == '\0') {
697 fa
= &ftattrtab
[fields
->ftyp
];
698 ASSERT(fa
->ftyp
== fields
->ftyp
);
702 /* run down the field list and set offsets into the data */
703 if (!flist_parse(fields
, fl
, iocur_top
->data
, 0)) {
705 dbprintf(_("parsing error\n"));
712 parentoffset
= sfl
->offset
;
717 * For structures, fsize * fcount tells us the size of the region we are
718 * modifying, which is usually a single structure member and is pointed
719 * to by the last child in the list.
721 * However, if the base structure is an array and we have a direct index
722 * into the array (e.g. write bno[5]) then we are returned a single
723 * flist object with the offset pointing directly at the location we
724 * need to modify. The length of the object we are modifying is then
725 * determined by the size of the individual array entry (fsize) and the
726 * indexes defined in the object, not the overall size of the array
727 * (which is what fcount returns).
729 bit_length
= fsize(sfl
->fld
, iocur_top
->data
, parentoffset
, 0);
730 if (sfl
->fld
->flags
& FLD_ARRAY
)
731 bit_length
*= sfl
->high
- sfl
->low
+ 1;
733 bit_length
*= fcount(sfl
->fld
, iocur_top
->data
, parentoffset
);
735 /* convert this to a generic conversion routine */
736 /* should be able to handle str, num, or even labels */
738 buf
= convert_arg(argv
[1], bit_length
);
740 dbprintf(_("unable to convert value '%s'.\n"), argv
[1]);
745 setbitval(iocur_top
->data
, sfl
->offset
, bit_length
, buf
);
756 const field_t
*fields
,
764 dbprintf(_("usage (in string mode): write \"string...\"\n"));
768 buf
= convert_arg(argv
[0], (int)((strlen(argv
[0])+1)*8));
769 for (i
= 0; i
< iocur_top
->len
; i
++) {
770 ((char *)iocur_top
->data
)[i
] = *buf
;
775 /* write back to disk */
782 const field_t
*fields
,
792 struct bw_cmd
*cmd
= NULL
;
794 if (argc
<= 1 || argc
> 5)
797 for (i
= 0; i
< BWRITE_CMD_MAX
; i
++) {
798 if (sigcmp(argv
[0], bw_cmdtab
[i
].cmdstr
,
799 bw_cmdtab
[i
].sig_chars
)) {
806 dbprintf(_("write: invalid subcommand\n"));
810 if ((argc
< cmd
->argmin
+ 1) || (argc
> cmd
->argmax
+ 1)) {
811 dbprintf(_("write %s: invalid number of arguments\n"),
816 if (cmd
->shiftcount_arg
&& (cmd
->shiftcount_arg
< argc
))
817 shiftcount
= (int)strtoul(argv
[cmd
->shiftcount_arg
], NULL
, 0);
818 if (cmd
->start_arg
&& (cmd
->start_arg
< argc
))
819 start
= (int)strtoul(argv
[cmd
->start_arg
], NULL
, 0);
820 if (cmd
->len_arg
&& (cmd
->len_arg
< argc
))
821 len
= (int)strtoul(argv
[cmd
->len_arg
], NULL
, 0);
822 if (cmd
->from_arg
&& (cmd
->len_arg
< argc
))
823 from
= (int)strtoul(argv
[cmd
->from_arg
], NULL
, 0);
824 if (cmd
->to_arg
&& (cmd
->len_arg
< argc
))
825 to
= (int)strtoul(argv
[cmd
->to_arg
], NULL
, 0);
827 cmd
->cmdfunc(start
, len
, shiftcount
, from
, to
);
829 /* write back to disk */
835 dbprintf(_("usage: write (in data mode)\n"));
836 for (i
= 0; i
< BWRITE_CMD_MAX
; i
++) {
837 dbprintf(" %-9.9s %s\n",
838 bw_cmdtab
[i
].cmdstr
, bw_cmdtab
[i
].usage
);