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