test_rel.c revision 521e36857227b21e7ab47b0a97f788d2af9f9717
1/*
2 * test_rel.c
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#ifdef HAVE_GETOPT_H
17#include <getopt.h>
18#endif
19#include <fcntl.h>
20
21#include <linux/ext2_fs.h>
22
23#include <et/com_err.h>
24#include <ss/ss.h>
25#include <ext2fs/ext2fs.h>
26#include <ext2fs/irel.h>
27#include <ext2fs/brel.h>
28
29#include "test_rel.h"
30
31extern ss_request_table test_cmds;
32
33ext2_irel irel = NULL;
34ext2_brel brel = NULL;
35
36/*
37 * Helper function which parses an inode number.
38 */
39static int parse_inode(const char *request, const char *desc,
40		       const char *str, ino_t *ino)
41{
42	char *tmp;
43
44	*ino = strtoul(str, &tmp, 0);
45	if (*tmp) {
46		com_err(request, 0, "Bad %s - %s", desc, str);
47		return 1;
48	}
49	return 0;
50}
51
52/*
53 * Helper function which parses a block number.
54 */
55static int parse_block(const char *request, const char *desc,
56		       const char *str, blk_t *blk)
57{
58	char *tmp;
59
60	*blk = strtoul(str, &tmp, 0);
61	if (*tmp) {
62		com_err(request, 0, "Bad %s - %s", desc, str);
63		return 1;
64	}
65	return 0;
66}
67
68/*
69 * Helper function which assures that a brel table is open
70 */
71static int check_brel(char *request)
72{
73	if (brel)
74		return 0;
75	com_err(request, 0, "A block relocation table must be open.");
76	return 1;
77}
78
79/*
80 * Helper function which assures that an irel table is open
81 */
82static int check_irel(char *request)
83{
84	if (irel)
85		return 0;
86	com_err(request, 0, "An inode relocation table must be open.");
87	return 1;
88}
89
90/*
91 * Helper function which displays a brel entry
92 */
93static void display_brel_entry(blk_t old,
94			       struct ext2_block_relocate_entry *ent)
95{
96	printf("Old= %u, New= %u, Owner= %u:%u\n", old, ent->new,
97	       ent->owner.block_ref, ent->offset);
98}
99
100/*
101 * Helper function which displays an irel entry
102 */
103static void display_irel_entry(ino_t old,
104			       struct ext2_inode_relocate_entry *ent,
105			       int do_refs)
106{
107	struct ext2_inode_reference ref;
108	errcode_t	retval;
109	int		first = 1;
110
111	printf("Old= %lu, New= %lu, Original=%lu, Max_refs=%u\n", old,
112	       ent->new, ent->orig, ent->max_refs);
113	if (!do_refs)
114		return;
115
116	retval = ext2fs_irel_start_iter_ref(irel, old);
117	if (retval) {
118		printf("\tCouldn't get references: %s\n",
119		       error_message(retval));
120		return;
121	}
122	while (1) {
123		retval = ext2fs_irel_next_ref(irel, &ref);
124		if (retval) {
125			printf("(%s) ", error_message(retval));
126			break;
127		}
128		if (ref.block == 0)
129			break;
130		if (first) {
131			fputc('\t', stdout);
132			first = 0;
133		} else
134			printf(", ");
135		printf("%u:%u", ref.block, ref.offset);
136	}
137	if (!first)
138		fputc('\n', stdout);
139}
140
141/*
142 * These are the actual command table procedures
143 */
144void do_brel_ma_create(int argc, char **argv)
145{
146	const char *usage = "Usage: %s name max_blocks\n";
147	errcode_t	retval;
148	blk_t		max_blk;
149
150	if (argc < 3) {
151		printf(usage, argv[0]);
152		return;
153	}
154	if (parse_block(argv[0], "max_blocks", argv[2], &max_blk))
155		return;
156	retval = ext2fs_brel_memarray_create(argv[1], max_blk, &brel);
157	if (retval) {
158		com_err(argv[0], retval, "while opening memarray brel");
159		return;
160	}
161	return;
162}
163
164void do_brel_free(int argc, char **argv)
165{
166	if (check_brel(argv[0]))
167		return;
168	ext2fs_brel_free(brel);
169	brel = NULL;
170	return;
171}
172
173void do_brel_put(int argc, char **argv)
174{
175	const char *usage = "usage: %s old_block new_block [owner] [offset]";
176	errcode_t retval;
177	struct ext2_block_relocate_entry ent;
178	blk_t	old, new, offset=0, owner=0;
179
180	if (check_brel(argv[0]))
181		return;
182
183	if (argc < 3) {
184		printf(usage, argv[0]);
185		return;
186	}
187	if (parse_block(argv[0], "old block", argv[1], &old))
188		return;
189	if (parse_block(argv[0], "new block", argv[2], &new))
190		return;
191	if (argc > 3 &&
192	    parse_block(argv[0], "owner block", argv[3], &owner))
193		return;
194	if (argc > 4 &&
195	    parse_block(argv[0], "offset", argv[4], &offset))
196		return;
197	if (offset > 65535) {
198		printf("Offset too large.\n");
199		return;
200	}
201	ent.new = new;
202	ent.offset = (__u16) offset;
203	ent.flags = 0;
204	ent.owner.block_ref = owner;
205
206	retval = ext2fs_brel_put(brel, old, &ent);
207	if (retval) {
208		com_err(argv[0], retval, "while calling ext2fs_brel_put");
209		return;
210	}
211	return;
212}
213
214void do_brel_get(int argc, char **argv)
215{
216	const char *usage = "%s block";
217	errcode_t retval;
218	struct ext2_block_relocate_entry ent;
219	blk_t	blk;
220
221	if (check_brel(argv[0]))
222		return;
223	if (argc < 2) {
224		printf(usage, argv[0]);
225		return;
226	}
227	if (parse_block(argv[0], "block", argv[1], &blk))
228		return;
229	retval = ext2fs_brel_get(brel, blk, &ent);
230	if (retval) {
231		com_err(argv[0], retval, "while calling ext2fs_brel_get");
232		return;
233	}
234	display_brel_entry(blk, &ent);
235	return;
236}
237
238void do_brel_start_iter(int argc, char **argv)
239{
240	errcode_t retval;
241
242	if (check_brel(argv[0]))
243		return;
244
245	retval = ext2fs_brel_start_iter(brel);
246	if (retval) {
247		com_err(argv[0], retval, "while calling ext2fs_brel_start_iter");
248		return;
249	}
250	return;
251}
252
253void do_brel_next(int argc, char **argv)
254{
255	errcode_t retval;
256	struct ext2_block_relocate_entry ent;
257	blk_t	blk;
258
259	if (check_brel(argv[0]))
260		return;
261
262	retval = ext2fs_brel_next(brel, &blk, &ent);
263	if (retval) {
264		com_err(argv[0], retval, "while calling ext2fs_brel_next");
265		return;
266	}
267	if (blk == 0) {
268		printf("No more entries!\n");
269		return;
270	}
271	display_brel_entry(blk, &ent);
272	return;
273}
274
275void do_brel_dump(int argc, char **argv)
276{
277	errcode_t retval;
278	struct ext2_block_relocate_entry ent;
279	blk_t	blk;
280
281	if (check_brel(argv[0]))
282		return;
283
284	retval = ext2fs_brel_start_iter(brel);
285	if (retval) {
286		com_err(argv[0], retval, "while calling ext2fs_brel_start_iter");
287		return;
288	}
289
290	while (1) {
291		retval = ext2fs_brel_next(brel, &blk, &ent);
292		if (retval) {
293			com_err(argv[0], retval, "while calling ext2fs_brel_next");
294			return;
295		}
296		if (blk == 0)
297			break;
298
299		display_brel_entry(blk, &ent);
300	}
301	return;
302}
303
304void do_brel_move(int argc, char **argv)
305{
306	const char *usage = "%s old_block new_block";
307	errcode_t retval;
308	blk_t	old, new;
309
310	if (check_brel(argv[0]))
311		return;
312	if (argc < 2) {
313		printf(usage, argv[0]);
314		return;
315	}
316	if (parse_block(argv[0], "old block", argv[1], &old))
317		return;
318	if (parse_block(argv[0], "new block", argv[2], &new))
319		return;
320
321	retval = ext2fs_brel_move(brel, old, new);
322	if (retval) {
323		com_err(argv[0], retval, "while calling ext2fs_brel_move");
324		return;
325	}
326	return;
327}
328
329void do_brel_delete(int argc, char **argv)
330{
331	const char *usage = "%s block";
332	errcode_t retval;
333	blk_t	blk;
334
335	if (check_brel(argv[0]))
336		return;
337	if (argc < 2) {
338		printf(usage, argv[0]);
339		return;
340	}
341	if (parse_block(argv[0], "block", argv[1], &blk))
342		return;
343
344	retval = ext2fs_brel_delete(brel, blk);
345	if (retval) {
346		com_err(argv[0], retval, "while calling ext2fs_brel_delete");
347		return;
348	}
349}
350
351void do_irel_ma_create(int argc, char **argv)
352{
353	const char *usage = "Usage: %s name max_inode\n";
354	errcode_t	retval;
355	ino_t		max_ino;
356
357	if (argc < 3) {
358		printf(usage, argv[0]);
359		return;
360	}
361	if (parse_inode(argv[0], "max_inodes", argv[2], &max_ino))
362		return;
363	retval = ext2fs_irel_memarray_create(argv[1], max_ino, &irel);
364	if (retval) {
365		com_err(argv[0], retval, "while opening memarray irel");
366		return;
367	}
368	return;
369}
370
371void do_irel_free(int argc, char **argv)
372{
373	if (check_irel(argv[0]))
374		return;
375
376	ext2fs_irel_free(irel);
377	irel = NULL;
378	return;
379}
380
381void do_irel_put(int argc, char **argv)
382{
383	const char *usage = "%s old new max_refs";
384	struct ext2_inode_relocate_entry ent;
385	errcode_t retval;
386	ino_t	old, new, max_refs;
387
388	if (check_irel(argv[0]))
389		return;
390
391	if (argc < 4) {
392		printf(usage, argv[0]);
393		return;
394	}
395	if (parse_inode(argv[0], "old inode", argv[1], &old))
396		return;
397	if (parse_inode(argv[0], "new inode", argv[2], &new))
398		return;
399	if (parse_inode(argv[0], "max_refs", argv[3], &max_refs))
400		return;
401	if (max_refs > 65535) {
402		printf("max_refs too big\n");
403		return;
404	}
405	ent.new = new;
406	ent.max_refs = (__u16) max_refs;
407	ent.flags = 0;
408
409	retval = ext2fs_irel_put(irel, old, &ent);
410	if (retval) {
411		com_err(argv[0], retval, "while calling ext2fs_irel_put");
412		return;
413	}
414	return;
415}
416
417void do_irel_get(int argc, char **argv)
418{
419	const char *usage = "%s inode";
420	struct ext2_inode_relocate_entry ent;
421	errcode_t retval;
422	ino_t	old;
423
424	if (check_irel(argv[0]))
425		return;
426
427	if (argc < 2) {
428		printf(usage, argv[0]);
429		return;
430	}
431	if (parse_inode(argv[0], "inode", argv[1], &old))
432		return;
433
434	retval = ext2fs_irel_get(irel, old, &ent);
435	if (retval) {
436		com_err(argv[0], retval, "while calling ext2fs_irel_get");
437		return;
438	}
439	display_irel_entry(old, &ent, 1);
440	return;
441}
442
443void do_irel_get_by_orig(int argc, char **argv)
444{
445	const char *usage = "%s orig_inode";
446	errcode_t retval;
447	struct ext2_inode_relocate_entry ent;
448	ino_t	orig, old;
449
450	if (check_irel(argv[0]))
451		return;
452
453	if (argc < 2) {
454		printf(usage, argv[0]);
455		return;
456	}
457	if (parse_inode(argv[0], "original inode", argv[1], &orig))
458		return;
459
460	retval = ext2fs_irel_get_by_orig(irel, orig, &old, &ent);
461	if (retval) {
462		com_err(argv[0], retval, "while calling ext2fs_irel_get_by_orig");
463		return;
464	}
465	display_irel_entry(old, &ent, 1);
466	return;
467}
468
469void do_irel_start_iter(int argc, char **argv)
470{
471	errcode_t retval;
472
473	if (check_irel(argv[0]))
474		return;
475
476	retval = ext2fs_irel_start_iter(irel);
477	if (retval) {
478		com_err(argv[0], retval, "while calling ext2fs_irel_start_iter");
479		return;
480	}
481	return;
482}
483
484void do_irel_next(int argc, char **argv)
485{
486	errcode_t retval;
487	struct ext2_inode_relocate_entry ent;
488	ino_t	old;
489
490	if (check_irel(argv[0]))
491		return;
492
493	retval = ext2fs_irel_next(irel, &old, &ent);
494	if (retval) {
495		com_err(argv[0], retval, "while calling ext2fs_irel_next");
496		return;
497	}
498	if (old == 0) {
499		printf("No more entries!\n");
500		return;
501	}
502	display_irel_entry(old, &ent, 1);
503	return;
504}
505
506void do_irel_dump(int argc, char **argv)
507{
508	errcode_t retval;
509	struct ext2_inode_relocate_entry ent;
510	ino_t	ino;
511
512	if (check_irel(argv[0]))
513		return;
514
515	retval = ext2fs_irel_start_iter(irel);
516	if (retval) {
517		com_err(argv[0], retval, "while calling ext2fs_irel_start_iter");
518		return;
519	}
520
521	while (1) {
522		retval = ext2fs_irel_next(irel, &ino, &ent);
523		if (retval) {
524			com_err(argv[0], retval, "while calling ext2fs_irel_next");
525			return;
526		}
527		if (ino == 0)
528			break;
529
530		display_irel_entry(ino, &ent, 1);
531	}
532	return;
533}
534
535void do_irel_add_ref(int argc, char **argv)
536{
537	const char *usage = "%s inode block offset";
538	errcode_t retval;
539	struct ext2_inode_reference ref;
540	blk_t	block, offset;
541	ino_t	ino;
542
543
544	if (check_irel(argv[0]))
545		return;
546
547	if (argc < 4) {
548		printf(usage, argv[0]);
549		return;
550	}
551	if (parse_inode(argv[0], "inode", argv[1], &ino))
552		return;
553	if (parse_block(argv[0], "block", argv[2], &block))
554		return;
555	if (parse_block(argv[0], "offset", argv[3], &offset))
556		return;
557	if (offset > 65535) {
558		printf("Offset too big.\n");
559		return;
560	}
561	ref.block = block;
562	ref.offset = offset;
563
564	retval = ext2fs_irel_add_ref(irel, ino, &ref);
565	if (retval) {
566		com_err(argv[0], retval, "while calling ext2fs_irel_add_ref");
567		return;
568	}
569	return;
570}
571
572void do_irel_start_iter_ref(int argc, char **argv)
573{
574	const char *usage = "%s inode";
575	errcode_t retval;
576	ino_t	ino;
577
578	if (check_irel(argv[0]))
579		return;
580
581	if (argc < 2) {
582		printf(usage, argv[0]);
583		return;
584	}
585
586	if (parse_inode(argv[0], "inode", argv[1], &ino))
587		return;
588	retval = ext2fs_irel_start_iter_ref(irel, ino);
589	if (retval) {
590		com_err(argv[0], retval, "while calling ext2fs_irel_start_iter_ref");
591		return;
592	}
593	return;
594}
595
596void do_irel_next_ref(int argc, char **argv)
597{
598	struct ext2_inode_reference ref;
599	errcode_t retval;
600
601	if (check_irel(argv[0]))
602		return;
603
604	retval = ext2fs_irel_next_ref(irel, &ref);
605	if (retval) {
606		com_err(argv[0], retval, "while calling ext2fs_irel_next_ref");
607		return;
608	}
609	printf("Inode reference: %u:%u\n", ref.block, ref.offset);
610	return;
611}
612
613void do_irel_move(int argc, char **argv)
614{
615	const char *usage = "%s old new";
616	errcode_t retval;
617	ino_t	old, new;
618
619	if (check_irel(argv[0]))
620		return;
621
622	if (argc < 3) {
623		printf(usage, argv[0]);
624		return;
625	}
626	if (parse_inode(argv[0], "old inode", argv[1], &old))
627		return;
628	if (parse_inode(argv[0], "new inode", argv[2], &new))
629		return;
630
631	retval = ext2fs_irel_move(irel, old, new);
632	if (retval) {
633		com_err(argv[0], retval, "while calling ext2fs_irel_move");
634		return;
635	}
636	return;
637}
638
639void do_irel_delete(int argc, char **argv)
640{
641	const char *usage = "%s inode";
642	errcode_t retval;
643	ino_t	ino;
644
645	if (check_irel(argv[0]))
646		return;
647
648	if (argc < 2) {
649		printf(usage, argv[0]);
650		return;
651	}
652	if (parse_inode(argv[0], "inode", argv[1], &ino))
653		return;
654
655	retval = ext2fs_irel_delete(irel, ino);
656	if (retval) {
657		com_err(argv[0], retval, "while calling ext2fs_irel_delete");
658		return;
659	}
660	return;
661}
662
663static int source_file(const char *cmd_file, int sci_idx)
664{
665	FILE		*f;
666	char		buf[256];
667	char		*cp;
668	int		exit_status = 0;
669	int		retval;
670	int 		noecho;
671
672	if (strcmp(cmd_file, "-") == 0)
673		f = stdin;
674	else {
675		f = fopen(cmd_file, "r");
676		if (!f) {
677			perror(cmd_file);
678			exit(1);
679		}
680	}
681	setbuf(stdout, NULL);
682	setbuf(stderr, NULL);
683	while (!feof(f)) {
684		if (fgets(buf, sizeof(buf), f) == NULL)
685			break;
686		if (buf[0] == '#')
687			continue;
688		noecho = 0;
689		if (buf[0] == '-') {
690			noecho = 1;
691			buf[0] = ' ';
692		}
693		cp = strchr(buf, '\n');
694		if (cp)
695			*cp = 0;
696		cp = strchr(buf, '\r');
697		if (cp)
698			*cp = 0;
699		if (!noecho)
700			printf("test_rel: %s\n", buf);
701		retval = ss_execute_line(sci_idx, buf);
702		if (retval) {
703			ss_perror(sci_idx, retval, buf);
704			exit_status++;
705		}
706	}
707	return exit_status;
708}
709
710void main(int argc, char **argv)
711{
712	int		retval;
713	int		sci_idx;
714	const char	*usage = "Usage: test_rel [-R request] [-f cmd_file]";
715	char		c;
716	char		*request = 0;
717	int		exit_status = 0;
718	char		*cmd_file = 0;
719
720	initialize_ext2_error_table();
721
722	while ((c = getopt (argc, argv, "wR:f:")) != EOF) {
723		switch (c) {
724		case 'R':
725			request = optarg;
726			break;
727		case 'f':
728			cmd_file = optarg;
729			break;
730		default:
731			com_err(argv[0], 0, usage);
732			return;
733		}
734	}
735	sci_idx = ss_create_invocation("test_rel", "0.0", (char *) NULL,
736				       &test_cmds, &retval);
737	if (retval) {
738		ss_perror(sci_idx, retval, "creating invocation");
739		exit(1);
740	}
741
742	(void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
743	if (retval) {
744		ss_perror(sci_idx, retval, "adding standard requests");
745		exit (1);
746	}
747	if (request) {
748		retval = 0;
749		retval = ss_execute_line(sci_idx, request);
750		if (retval) {
751			ss_perror(sci_idx, retval, request);
752			exit_status++;
753		}
754	} else if (cmd_file) {
755		exit_status = source_file(cmd_file, sci_idx);
756	} else {
757		ss_listen(sci_idx);
758	}
759
760	exit(exit_status);
761}
762
763