]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/write.c
apply gettext translation to more strings
[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 <xfs/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_("[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 ));
83
84 }
85
86 static int
87 write_f(
88 int argc,
89 char **argv)
90 {
91 pfunc_t pf;
92 extern char *progname;
93
94 if (x.isreadonly & LIBXFS_ISREADONLY) {
95 dbprintf(_("%s started in read only mode, writing disabled\n"),
96 progname);
97 return 0;
98 }
99
100 if (cur_typ == NULL) {
101 dbprintf(_("no current type\n"));
102 return 0;
103 }
104
105 pf = cur_typ->pfunc;
106 if (pf == NULL) {
107 dbprintf(_("no handler function for type %s, write unsupported.\n"),
108 cur_typ->name);
109 return 0;
110 }
111
112 /* move past the "write" command */
113 argc--;
114 argv++;
115
116 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
117
118 return 0;
119 }
120
121 /* compare significant portions of commands */
122
123 static int
124 sigcmp(
125 char *s1,
126 char *s2,
127 int sig)
128 {
129 int sigcnt;
130
131 if (!s1 || !s2)
132 return 0;
133
134 for (sigcnt = 0; *s1 == *s2; s1++, s2++) {
135 sigcnt++;
136 if (*s1 == '\0')
137 return 1;
138 }
139 if (*s1 && *s2)
140 return 0;
141
142 if (sig && (sigcnt >= sig))
143 return 1;
144
145 return 0;
146 }
147
148 /* ARGSUSED */
149 static void
150 bwrite_lshift(
151 int start,
152 int len,
153 int shift,
154 int from,
155 int to)
156 {
157 char *base;
158
159 if (shift == -1)
160 shift = 1;
161 if (start == -1)
162 start = 0;
163 if (len == -1)
164 len = iocur_top->len - start;
165
166 if (len+start > iocur_top->len) {
167 dbprintf(_("length (%d) too large for data block size (%d)"),
168 len, iocur_top->len);
169 }
170
171 base = (char *)iocur_top->data + start;
172
173 memcpy(base, base+shift, len-shift);
174 memset(base+(len-shift), 0, shift);
175 }
176
177 /* ARGSUSED */
178 static void
179 bwrite_rshift(
180 int start,
181 int len,
182 int shift,
183 int from,
184 int to)
185 {
186 char *base;
187
188 if (shift == -1)
189 shift = 1;
190 if (start == -1)
191 start = 0;
192 if (len == -1)
193 len = iocur_top->len - start;
194
195 if (len+start > iocur_top->len) {
196 dbprintf(_("length (%d) too large for data block size (%d)"),
197 len, iocur_top->len);
198 }
199
200 base = (char *)iocur_top->data + start;
201
202 memcpy(base+shift, base, len-shift);
203 memset(base, 0, shift);
204 }
205
206 /* ARGSUSED */
207 static void
208 bwrite_lrot(
209 int start,
210 int len,
211 int shift,
212 int from,
213 int to)
214 {
215 char *base;
216 char *hold_region;
217
218 if (shift == -1)
219 shift = 1;
220 if (start == -1)
221 start = 0;
222 if (len == -1)
223 len = iocur_top->len - start;
224
225 if (len+start > iocur_top->len) {
226 dbprintf(_("length (%d) too large for data block size (%d)"),
227 len, iocur_top->len);
228 }
229
230 base = (char *)iocur_top->data + start;
231
232 hold_region = xmalloc(shift);
233 memcpy(hold_region, base, shift);
234 memcpy(base, base+shift, len-shift);
235 memcpy(base+(len-shift), hold_region, shift);
236 }
237
238 /* ARGSUSED */
239 static void
240 bwrite_rrot(
241 int start,
242 int len,
243 int shift,
244 int from,
245 int to)
246 {
247 char *base;
248 char *hold_region;
249
250 if (shift == -1)
251 shift = 1;
252 if (start == -1)
253 start = 0;
254 if (len == -1)
255 len = iocur_top->len - start;
256
257 if (len+start > iocur_top->len) {
258 dbprintf(_("length (%d) too large for data block size (%d)"),
259 len, iocur_top->len);
260 }
261
262 base = (char *)iocur_top->data + start;
263
264 hold_region = xmalloc(shift);
265 memcpy(hold_region, base+(len-shift), shift);
266 memmove(base+shift, base, len-shift);
267 memcpy(base, hold_region, shift);
268 }
269
270 /* ARGSUSED */
271 static void
272 bwrite_seq(
273 int start,
274 int len,
275 int step,
276 int from,
277 int to)
278 {
279 int i;
280 int tmp;
281 int base;
282 int range;
283 int top;
284 char *buf;
285
286 if (start == -1)
287 start = 0;
288
289 if (len == -1)
290 len = iocur_top->len - start;
291
292 if (len+start > iocur_top->len) {
293 dbprintf(_("length (%d) too large for data block size (%d)"),
294 len, iocur_top->len);
295 }
296
297 if (from == -1 || from > 255)
298 from = 0;
299 if (to == -1 || to > 255)
300 to = 255;
301 if (step == -1)
302 step = 1;
303
304 base = from;
305 top = to;
306 if (from > to) {
307 base = to;
308 top = from;
309 if (step > 0)
310 step = -step;
311 }
312
313 range = top - base;
314 buf = (char *)iocur_top->data + start;
315
316 tmp = 0;
317 for (i = start; i < start+len; i++) {
318 *buf++ = tmp + base;
319 tmp = (tmp + step)%(range+1);
320 }
321 }
322
323 /* ARGSUSED */
324 static void
325 bwrite_random(
326 int start,
327 int len,
328 int shift,
329 int from,
330 int to)
331 {
332 int i;
333 char *buf;
334
335 if (start == -1)
336 start = 0;
337
338 if (len == -1)
339 len = iocur_top->len - start;
340
341 if (len+start > iocur_top->len) {
342 dbprintf(_("length (%d) too large for data block size (%d)"),
343 len, iocur_top->len);
344 }
345
346 buf = (char *)iocur_top->data + start;
347
348 for (i = start; i < start+len; i++)
349 *buf++ = (char)lrand48();
350 }
351
352 /* ARGSUSED */
353 static void
354 bwrite_fill(
355 int start,
356 int len,
357 int value,
358 int from,
359 int to)
360 {
361 char *base;
362
363 if (value == -1)
364 value = 0;
365 if (start == -1)
366 start = 0;
367 if (len == -1)
368 len = iocur_top->len - start;
369
370 if (len+start > iocur_top->len) {
371 dbprintf(_("length (%d) too large for data block size (%d)"),
372 len, iocur_top->len);
373 }
374
375 base = (char *)iocur_top->data + start;
376
377 memset(base, value, len);
378 }
379
380 static struct bw_cmd {
381 void (*cmdfunc)(int,int,int,int,int);
382 char *cmdstr;
383 int sig_chars;
384 int argmin;
385 int argmax;
386 int shiftcount_arg;
387 int from_arg;
388 int to_arg;
389 int start_arg;
390 int len_arg;
391 char *usage;
392 } bw_cmdtab[] = {
393 /* cmd sig min max sh frm to start len */
394 { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
395 "[shiftcount] [start] [len]", },
396 { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
397 "[shiftcount] [start] [len]", },
398 { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
399 "[shiftcount] [start] [len]", },
400 { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
401 "[shiftcount] [start] [len]", },
402 { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
403 "[from] [to] [start] [len]", },
404 { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2,
405 "[start] [len]", },
406 { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
407 "num [start] [len]" }
408 };
409
410 #define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
411
412 static int
413 convert_oct(
414 char *arg,
415 int *ret)
416 {
417 int count;
418 int i;
419 int val = 0;
420
421 /* only allow 1 case, '\' and 3 octal digits (or less) */
422
423 for (count = 0; count < 3; count++) {
424 if (arg[count] == '\0')
425 break;
426
427 if ((arg[count] < '0') && (arg[count] > '7'))
428 break;
429 }
430
431 for (i = 0; i < count; i++) {
432 val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3);
433 }
434
435 *ret = val&0xff;
436
437 return(count);
438 }
439
440 #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
441
442 static char *
443 convert_arg(
444 char *arg,
445 int bit_length)
446 {
447 int i;
448 static char *buf = NULL;
449 char *rbuf;
450 long long *value;
451 int alloc_size;
452 char *ostr;
453 int octval, ret;
454
455 if (bit_length <= 64)
456 alloc_size = 8;
457 else
458 alloc_size = (bit_length+7)/8;
459
460 buf = xrealloc(buf, alloc_size);
461 memset(buf, 0, alloc_size);
462 value = (long long *)buf;
463 rbuf = buf;
464
465 if (*arg == '\"') {
466 /* handle strings */
467
468 /* zap closing quote if there is one */
469 if ((ostr = strrchr(arg+1, '\"')) != NULL)
470 *ostr = '\0';
471
472 ostr = arg+1;
473 for (i = 0; i < alloc_size; i++) {
474 if (!*ostr)
475 break;
476
477 /* do octal */
478 if (*ostr == '\\') {
479 if (*(ostr+1) >= '0' || *(ostr+1) <= '7') {
480 ret = convert_oct(ostr+1, &octval);
481 *rbuf++ = octval;
482 ostr += ret+1;
483 continue;
484 }
485 }
486 *rbuf++ = *ostr++;
487 }
488
489 return buf;
490 } else if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
491 /*
492 * handle hex blocks ie
493 * #00112233445566778899aabbccddeeff
494 * and uuids ie
495 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
496 *
497 * (but if it starts with "-" assume it's just an integer)
498 */
499 int bytes=bit_length/8;
500
501 /* skip leading hash */
502 if (*arg=='#') arg++;
503
504 while (*arg && bytes--) {
505 /* skip hypens */
506 while (*arg=='-') arg++;
507
508 /* get first nybble */
509 if (!isxdigit((int)*arg)) return NULL;
510 *rbuf=NYBBLE((int)*arg)<<4;
511 arg++;
512
513 /* skip more hyphens */
514 while (*arg=='-') arg++;
515
516 /* get second nybble */
517 if (!isxdigit((int)*arg)) return NULL;
518 *rbuf++|=NYBBLE((int)*arg);
519 arg++;
520 }
521 if (bytes<0&&*arg) return NULL;
522 return buf;
523 } else {
524 /*
525 * handle integers
526 */
527 *value = strtoll(arg, NULL, 0);
528
529 #if __BYTE_ORDER == BIG_ENDIAN
530 /* hackery for big endian */
531 if (bit_length <= 8) {
532 rbuf += 7;
533 } else if (bit_length <= 16) {
534 rbuf += 6;
535 } else if (bit_length <= 32) {
536 rbuf += 4;
537 }
538 #endif
539 return rbuf;
540 }
541 }
542
543
544 /* ARGSUSED */
545 void
546 write_struct(
547 const field_t *fields,
548 int argc,
549 char **argv)
550 {
551 const ftattr_t *fa;
552 flist_t *fl;
553 flist_t *sfl;
554 int bit_length;
555 char *buf;
556 int parentoffset;
557
558 if (argc != 2) {
559 dbprintf(_("usage: write fieldname value\n"));
560 return;
561 }
562
563 fl = flist_scan(argv[0]);
564 if (!fl) {
565 dbprintf(_("unable to parse '%s'.\n"), argv[0]);
566 return;
567 }
568
569 /* if we're a root field type, go down 1 layer to get field list */
570 if (fields->name[0] == '\0') {
571 fa = &ftattrtab[fields->ftyp];
572 ASSERT(fa->ftyp == fields->ftyp);
573 fields = fa->subfld;
574 }
575
576 /* run down the field list and set offsets into the data */
577 if (!flist_parse(fields, fl, iocur_top->data, 0)) {
578 flist_free(fl);
579 dbprintf(_("parsing error\n"));
580 return;
581 }
582
583 sfl = fl;
584 parentoffset = 0;
585 while (sfl->child) {
586 parentoffset = sfl->offset;
587 sfl = sfl->child;
588 }
589
590 bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
591 bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
592
593 /* convert this to a generic conversion routine */
594 /* should be able to handle str, num, or even labels */
595
596 buf = convert_arg(argv[1], bit_length);
597 if (!buf) {
598 dbprintf(_("unable to convert value '%s'.\n"), argv[1]);
599 return;
600 }
601
602 setbitval(iocur_top->data, sfl->offset, bit_length, buf);
603 write_cur();
604
605 flist_print(fl);
606 print_flist(fl);
607 flist_free(fl);
608 }
609
610 /* ARGSUSED */
611 void
612 write_string(
613 const field_t *fields,
614 int argc,
615 char **argv)
616 {
617 char *buf;
618 int i;
619
620 if (argc != 1) {
621 dbprintf(_("usage (in string mode): write \"string...\"\n"));
622 return;
623 }
624
625 buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8));
626 for (i = 0; i < iocur_top->len; i++) {
627 ((char *)iocur_top->data)[i] = *buf;
628 if (*buf++ == '\0')
629 break;
630 }
631
632 /* write back to disk */
633 write_cur();
634 }
635
636 /* ARGSUSED */
637 void
638 write_block(
639 const field_t *fields,
640 int argc,
641 char **argv)
642 {
643 int i;
644 int shiftcount = -1;
645 int start = -1;
646 int len = -1;
647 int from = -1;
648 int to = -1;
649 struct bw_cmd *cmd = NULL;
650
651 if (argc <= 1 || argc > 5)
652 goto block_usage;
653
654 for (i = 0; i < BWRITE_CMD_MAX; i++) {
655 if (sigcmp(argv[0], bw_cmdtab[i].cmdstr,
656 bw_cmdtab[i].sig_chars)) {
657 cmd = &bw_cmdtab[i];
658 break;
659 }
660 }
661
662 if (!cmd) {
663 dbprintf(_("write: invalid subcommand\n"));
664 goto block_usage;
665 }
666
667 if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) {
668 dbprintf(_("write %s: invalid number of arguments\n"),
669 cmd->cmdstr);
670 goto block_usage;
671 }
672
673 if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc))
674 shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0);
675 if (cmd->start_arg && (cmd->start_arg < argc))
676 start = (int)strtoul(argv[cmd->start_arg], NULL, 0);
677 if (cmd->len_arg && (cmd->len_arg < argc))
678 len = (int)strtoul(argv[cmd->len_arg], NULL, 0);
679 if (cmd->from_arg && (cmd->len_arg < argc))
680 from = (int)strtoul(argv[cmd->from_arg], NULL, 0);
681 if (cmd->to_arg && (cmd->len_arg < argc))
682 to = (int)strtoul(argv[cmd->to_arg], NULL, 0);
683
684 cmd->cmdfunc(start, len, shiftcount, from, to);
685
686 /* write back to disk */
687 write_cur();
688 return;
689
690 block_usage:
691
692 dbprintf(_("usage: write (in data mode)\n"));
693 for (i = 0; i < BWRITE_CMD_MAX; i++) {
694 dbprintf(" %-9.9s %s\n",
695 bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage);
696 }
697 dbprintf("\n");
698 return;
699 }