]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/write.c
Merge whitespace changes over
[thirdparty/xfsprogs-dev.git] / db / write.c
CommitLineData
2bd0ea18 1/*
0d3e0b37 2 * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
dfc130f3 3 *
2bd0ea18
NS
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
dfc130f3 7 *
2bd0ea18
NS
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dfc130f3 11 *
2bd0ea18
NS
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
dfc130f3 18 *
2bd0ea18
NS
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
dfc130f3 22 *
2bd0ea18
NS
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
dfc130f3
RC
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
2bd0ea18
NS
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <libxfs.h>
34#include <ctype.h>
35#include <time.h>
36#include "bit.h"
37#include "block.h"
38#include "command.h"
2bd0ea18
NS
39#include "type.h"
40#include "faddr.h"
41#include "fprint.h"
42#include "field.h"
43#include "flist.h"
44#include "io.h"
4ca431fc 45#include "init.h"
2bd0ea18
NS
46#include "output.h"
47#include "print.h"
48#include "write.h"
49#include "malloc.h"
50
51static int write_f(int argc, char **argv);
52static void write_help(void);
53
54static const cmdinfo_t write_cmd =
55 { "write", NULL, write_f, 0, -1, 0, "[field or value]...",
56 "write value to disk", write_help };
57
58void
59write_init(void)
60{
4ca431fc 61 if (!expert_mode)
2bd0ea18
NS
62 return;
63
64 add_command(&write_cmd);
65 srand48(clock());
66}
67
dfc130f3 68static void
2bd0ea18
NS
69write_help(void)
70{
71 dbprintf(
72"\n"
73" The 'write' command takes on different personalities depending on the\n"
74" type of object being worked with.\n\n"
75" Write has 3 modes:\n"
76" 'struct mode' - is active anytime you're looking at a filesystem object\n"
77" which contains individual fields (ex: an inode).\n"
78" 'data mode' - is active anytime you set a disk address directly or set\n"
79" the type to 'data'.\n"
80" 'string mode' - only used for writing symlink blocks.\n"
81"\n"
82" Examples:\n"
83" Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n"
84" 'write fname \"hello\\000\"' - write superblock fname.\n"
85" (note: in struct mode strings are not null terminated)\n"
86" 'write fname #6669736800' - write superblock fname with hex.\n"
dfc130f3 87" 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n"
2bd0ea18
NS
88" - write superblock uuid.\n"
89" Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n"
90" 'write lshift 3' - shift the block 3 bytes to the left\n"
91" 'write sequence 1 5' - write a cycle of number [1-5] through\n"
92" the entire block.\n"
93" String mode: 'write \"This_is_a_filename\" - write null terminated string.\n"
94"\n"
95" In data mode type 'write' by itself for a list of specific commands.\n\n"
96);
97
98}
99
100static int
101write_f(
102 int argc,
103 char **argv)
104{
105 pfunc_t pf;
106 extern char *progname;
107
4ca431fc 108 if (x.isreadonly & LIBXFS_ISREADONLY) {
2bd0ea18
NS
109 dbprintf("%s started in read only mode, writing disabled\n",
110 progname);
111 return 0;
112 }
113
114 if (cur_typ == NULL) {
115 dbprintf("no current type\n");
116 return 0;
117 }
118
119 pf = cur_typ->pfunc;
120 if (pf == NULL) {
121 dbprintf("no handler function for type %s, write unsupported.\n",
122 cur_typ->name);
123 return 0;
124 }
125
126 /* move past the "write" command */
127 argc--;
128 argv++;
129
130 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
131
132 return 0;
133}
134
135/* compare significant portions of commands */
136
137static int
138sigcmp(
139 char *s1,
140 char *s2,
141 int sig)
142{
143 int sigcnt;
144
145 if (!s1 || !s2)
146 return 0;
147
148 for (sigcnt = 0; *s1 == *s2; s1++, s2++) {
149 sigcnt++;
150 if (*s1 == '\0')
151 return 1;
152 }
153 if (*s1 && *s2)
154 return 0;
155
156 if (sig && (sigcnt >= sig))
157 return 1;
158
159 return 0;
160}
161
162/* ARGSUSED */
163static void
164bwrite_lshift(
165 int start,
166 int len,
167 int shift,
168 int from,
169 int to)
170{
171 char *base;
172
173 if (shift == -1)
174 shift = 1;
175 if (start == -1)
176 start = 0;
177 if (len == -1)
178 len = iocur_top->len - start;
179
180 if (len+start > iocur_top->len) {
181 dbprintf("length (%d) too large for data block size (%d)",
182 len, iocur_top->len);
183 }
184
185 base = (char *)iocur_top->data + start;
186
187 memcpy(base, base+shift, len-shift);
188 memset(base+(len-shift), 0, shift);
189}
190
191/* ARGSUSED */
192static void
193bwrite_rshift(
194 int start,
195 int len,
196 int shift,
197 int from,
198 int to)
199{
200 char *base;
201
202 if (shift == -1)
203 shift = 1;
204 if (start == -1)
205 start = 0;
206 if (len == -1)
207 len = iocur_top->len - start;
208
209 if (len+start > iocur_top->len) {
210 dbprintf("length (%d) too large for data block size (%d)",
211 len, iocur_top->len);
212 }
213
214 base = (char *)iocur_top->data + start;
215
216 memcpy(base+shift, base, len-shift);
217 memset(base, 0, shift);
218}
219
220/* ARGSUSED */
221static void
222bwrite_lrot(
223 int start,
224 int len,
225 int shift,
226 int from,
227 int to)
228{
229 char *base;
230 char *hold_region;
231
232 if (shift == -1)
233 shift = 1;
234 if (start == -1)
235 start = 0;
236 if (len == -1)
237 len = iocur_top->len - start;
238
239 if (len+start > iocur_top->len) {
240 dbprintf("length (%d) too large for data block size (%d)",
241 len, iocur_top->len);
242 }
243
244 base = (char *)iocur_top->data + start;
245
246 hold_region = xmalloc(shift);
247 memcpy(hold_region, base, shift);
248 memcpy(base, base+shift, len-shift);
249 memcpy(base+(len-shift), hold_region, shift);
250}
251
252/* ARGSUSED */
253static void
254bwrite_rrot(
255 int start,
256 int len,
257 int shift,
258 int from,
259 int to)
260{
261 char *base;
262 char *hold_region;
263
264 if (shift == -1)
265 shift = 1;
266 if (start == -1)
267 start = 0;
268 if (len == -1)
269 len = iocur_top->len - start;
270
271 if (len+start > iocur_top->len) {
272 dbprintf("length (%d) too large for data block size (%d)",
273 len, iocur_top->len);
274 }
275
276 base = (char *)iocur_top->data + start;
277
278 hold_region = xmalloc(shift);
279 memcpy(hold_region, base+(len-shift), shift);
0e6b2a43 280 memmove(base+shift, base, len-shift);
2bd0ea18
NS
281 memcpy(base, hold_region, shift);
282}
283
284/* ARGSUSED */
285static void
286bwrite_seq(
287 int start,
288 int len,
289 int step,
290 int from,
291 int to)
292{
293 int i;
294 int tmp;
295 int base;
296 int range;
297 int top;
0e6b2a43 298 char *buf;
2bd0ea18
NS
299
300 if (start == -1)
301 start = 0;
302
303 if (len == -1)
304 len = iocur_top->len - start;
305
306 if (len+start > iocur_top->len) {
307 dbprintf("length (%d) too large for data block size (%d)",
308 len, iocur_top->len);
309 }
310
311 if (from == -1 || from > 255)
312 from = 0;
313 if (to == -1 || to > 255)
314 to = 255;
315 if (step == -1)
316 step = 1;
317
318 base = from;
319 top = to;
320 if (from > to) {
321 base = to;
322 top = from;
323 if (step > 0)
324 step = -step;
325 }
326
327 range = top - base;
0e6b2a43 328 buf = (char *)iocur_top->data + start;
2bd0ea18
NS
329
330 tmp = 0;
331 for (i = start; i < start+len; i++) {
332 *buf++ = tmp + base;
333 tmp = (tmp + step)%(range+1);
334 }
335}
336
337/* ARGSUSED */
338static void
339bwrite_random(
340 int start,
341 int len,
342 int shift,
343 int from,
344 int to)
345{
346 int i;
0e6b2a43 347 char *buf;
2bd0ea18
NS
348
349 if (start == -1)
350 start = 0;
351
352 if (len == -1)
353 len = iocur_top->len - start;
354
355 if (len+start > iocur_top->len) {
356 dbprintf("length (%d) too large for data block size (%d)",
357 len, iocur_top->len);
358 }
359
0e6b2a43
NS
360 buf = (char *)iocur_top->data + start;
361
2bd0ea18
NS
362 for (i = start; i < start+len; i++)
363 *buf++ = (char)lrand48();
364}
365
366/* ARGSUSED */
367static void
368bwrite_fill(
369 int start,
370 int len,
371 int value,
372 int from,
373 int to)
374{
375 char *base;
376
377 if (value == -1)
378 value = 0;
379 if (start == -1)
380 start = 0;
381 if (len == -1)
382 len = iocur_top->len - start;
383
384 if (len+start > iocur_top->len) {
385 dbprintf("length (%d) too large for data block size (%d)",
386 len, iocur_top->len);
387 }
388
389 base = (char *)iocur_top->data + start;
390
391 memset(base, value, len);
392}
393
394static struct bw_cmd {
395 void (*cmdfunc)(int,int,int,int,int);
396 char *cmdstr;
397 int sig_chars;
398 int argmin;
399 int argmax;
400 int shiftcount_arg;
401 int from_arg;
402 int to_arg;
403 int start_arg;
404 int len_arg;
405 char *usage;
406} bw_cmdtab[] = {
407 /* cmd sig min max sh frm to start len */
408 { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
409 "[shiftcount] [start] [len]", },
410 { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
411 "[shiftcount] [start] [len]", },
412 { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
413 "[shiftcount] [start] [len]", },
414 { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
415 "[shiftcount] [start] [len]", },
416 { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
417 "[from] [to] [start] [len]", },
418 { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2,
419 "[start] [len]", },
420 { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
421 "num [start] [len]" }
422};
423
424#define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
425
426static int
427convert_oct(
428 char *arg,
429 int *ret)
430{
431 int count;
432 int i;
433 int val = 0;
434
435 /* only allow 1 case, '\' and 3 octal digits (or less) */
436
437 for (count = 0; count < 3; count++) {
438 if (arg[count] == '\0')
439 break;
440
441 if ((arg[count] < '0') && (arg[count] > '7'))
442 break;
443 }
444
445 for (i = 0; i < count; i++) {
446 val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3);
447 }
448
449 *ret = val&0xff;
450
451 return(count);
452}
453
454#define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
455
456static char *
457convert_arg(
458 char *arg,
459 int bit_length)
460{
461 int i;
462 static char *buf = NULL;
463 char *rbuf;
464 long long *value;
465 int alloc_size;
466 char *ostr;
467 int octval, ret;
468
469 if (bit_length <= 64)
470 alloc_size = 8;
471 else
472 alloc_size = (bit_length+7)/8;
473
474 buf = xrealloc(buf, alloc_size);
475 memset(buf, 0, alloc_size);
476 value = (long long *)buf;
477 rbuf = buf;
478
479 if (*arg == '\"') {
dfc130f3 480 /* handle strings */
2bd0ea18
NS
481
482 /* zap closing quote if there is one */
483 if ((ostr = strrchr(arg+1, '\"')) != NULL)
484 *ostr = '\0';
485
486 ostr = arg+1;
487 for (i = 0; i < alloc_size; i++) {
488 if (!*ostr)
489 break;
490
491 /* do octal */
492 if (*ostr == '\\') {
493 if (*(ostr+1) >= '0' || *(ostr+1) <= '7') {
494 ret = convert_oct(ostr+1, &octval);
495 *rbuf++ = octval;
496 ostr += ret+1;
497 continue;
498 }
499 }
500 *rbuf++ = *ostr++;
501 }
502
503 return buf;
dfc130f3
RC
504 } else if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
505 /*
506 * handle hex blocks ie
507 * #00112233445566778899aabbccddeeff
508 * and uuids ie
509 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
75efd6ca
ES
510 *
511 * (but if it starts with "-" assume it's just an integer)
dfc130f3
RC
512 */
513 int bytes=bit_length/8;
514
515 /* skip leading hash */
516 if (*arg=='#') arg++;
517
518 while (*arg && bytes--) {
519 /* skip hypens */
520 while (*arg=='-') arg++;
521
522 /* get first nybble */
523 if (!isxdigit((int)*arg)) return NULL;
524 *rbuf=NYBBLE((int)*arg)<<4;
525 arg++;
526
527 /* skip more hyphens */
528 while (*arg=='-') arg++;
529
530 /* get second nybble */
531 if (!isxdigit((int)*arg)) return NULL;
532 *rbuf++|=NYBBLE((int)*arg);
533 arg++;
534 }
535 if (bytes<0&&*arg) return NULL;
536 return buf;
2bd0ea18 537 } else {
dfc130f3
RC
538 /*
539 * handle integers
540 */
2bd0ea18 541 *value = strtoll(arg, NULL, 0);
dfc130f3 542
2bd0ea18
NS
543#if __BYTE_ORDER == BIG_ENDIAN
544 /* hackery for big endian */
545 if (bit_length <= 8) {
546 rbuf += 7;
547 } else if (bit_length <= 16) {
548 rbuf += 6;
549 } else if (bit_length <= 32) {
550 rbuf += 4;
551 }
552#endif
553 return rbuf;
554 }
555}
556
557
558/* ARGSUSED */
559void
560write_struct(
561 const field_t *fields,
562 int argc,
563 char **argv)
564{
565 const ftattr_t *fa;
566 flist_t *fl;
567 flist_t *sfl;
568 int bit_length;
569 char *buf;
570 int parentoffset;
571
572 if (argc != 2) {
573 dbprintf("usage: write fieldname value\n");
574 return;
575 }
576
577 fl = flist_scan(argv[0]);
578 if (!fl) {
579 dbprintf("unable to parse '%s'.\n", argv[0]);
580 return;
581 }
582
583 /* if we're a root field type, go down 1 layer to get field list */
584 if (fields->name[0] == '\0') {
585 fa = &ftattrtab[fields->ftyp];
586 ASSERT(fa->ftyp == fields->ftyp);
587 fields = fa->subfld;
588 }
589
590 /* run down the field list and set offsets into the data */
591 if (!flist_parse(fields, fl, iocur_top->data, 0)) {
592 flist_free(fl);
593 dbprintf("parsing error\n");
594 return;
595 }
596
597 sfl = fl;
598 parentoffset = 0;
599 while (sfl->child) {
600 parentoffset = sfl->offset;
601 sfl = sfl->child;
602 }
603
604 bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
605 bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
606
607 /* convert this to a generic conversion routine */
608 /* should be able to handle str, num, or even labels */
dfc130f3 609
2bd0ea18
NS
610 buf = convert_arg(argv[1], bit_length);
611 if (!buf) {
612 dbprintf("unable to convert value '%s'.\n", argv[1]);
613 return;
614 }
615
dfc130f3 616 setbitval(iocur_top->data, sfl->offset, bit_length, buf);
2bd0ea18
NS
617 write_cur();
618
619 flist_print(fl);
dfc130f3 620 print_flist(fl);
2bd0ea18
NS
621 flist_free(fl);
622}
623
624/* ARGSUSED */
625void
626write_string(
627 const field_t *fields,
628 int argc,
629 char **argv)
630{
631 char *buf;
632 int i;
633
634 if (argc != 1) {
635 dbprintf("usage (in string mode): write \"string...\"\n");
636 return;
637 }
638
639 buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8));
640 for (i = 0; i < iocur_top->len; i++) {
641 ((char *)iocur_top->data)[i] = *buf;
642 if (*buf++ == '\0')
643 break;
644 }
645
646 /* write back to disk */
647 write_cur();
648}
649
650/* ARGSUSED */
651void
652write_block(
653 const field_t *fields,
654 int argc,
655 char **argv)
656{
657 int i;
dfc130f3 658 int shiftcount = -1;
2bd0ea18
NS
659 int start = -1;
660 int len = -1;
661 int from = -1;
662 int to = -1;
663 struct bw_cmd *cmd = NULL;
664
665 if (argc <= 1 || argc > 5)
666 goto block_usage;
667
668 for (i = 0; i < BWRITE_CMD_MAX; i++) {
669 if (sigcmp(argv[0], bw_cmdtab[i].cmdstr,
670 bw_cmdtab[i].sig_chars)) {
671 cmd = &bw_cmdtab[i];
672 break;
673 }
674 }
675
676 if (!cmd) {
677 dbprintf("write: invalid subcommand\n");
678 goto block_usage;
679 }
680
681 if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) {
682 dbprintf("write %s: invalid number of arguments\n",
683 cmd->cmdstr);
684 goto block_usage;
685 }
dfc130f3 686
2bd0ea18
NS
687 if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc))
688 shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0);
689 if (cmd->start_arg && (cmd->start_arg < argc))
690 start = (int)strtoul(argv[cmd->start_arg], NULL, 0);
691 if (cmd->len_arg && (cmd->len_arg < argc))
692 len = (int)strtoul(argv[cmd->len_arg], NULL, 0);
693 if (cmd->from_arg && (cmd->len_arg < argc))
694 from = (int)strtoul(argv[cmd->from_arg], NULL, 0);
695 if (cmd->to_arg && (cmd->len_arg < argc))
696 to = (int)strtoul(argv[cmd->to_arg], NULL, 0);
697
698 cmd->cmdfunc(start, len, shiftcount, from, to);
699
700 /* write back to disk */
701 write_cur();
702 return;
703
704 block_usage:
705
706 dbprintf("usage: write (in data mode)\n");
707 for (i = 0; i < BWRITE_CMD_MAX; i++) {
708 dbprintf(" %-9.9s %s\n",
709 bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage);
710 }
711 dbprintf("\n");
712 return;
713}