2 * set_fields.c --- set a superblock value
4 * Copyright (C) 2000, 2001, 2002, 2003, 2004 by Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
12 #define _XOPEN_SOURCE 500 /* for inclusion of strptime() */
21 #include <sys/types.h>
30 #include "uuid/uuid.h"
33 static struct ext2_super_block set_sb
;
34 static struct ext2_inode set_inode
;
35 static struct ext2_group_desc set_gd
;
36 static ext2_ino_t set_ino
;
39 #define FLAG_ARRAY 0x0001
41 struct field_set_info
{
45 errcode_t (*func
)(struct field_set_info
*info
, char *arg
);
50 static errcode_t
parse_uint(struct field_set_info
*info
, char *arg
);
51 static errcode_t
parse_int(struct field_set_info
*info
, char *arg
);
52 static errcode_t
parse_string(struct field_set_info
*info
, char *arg
);
53 static errcode_t
parse_uuid(struct field_set_info
*info
, char *arg
);
54 static errcode_t
parse_hashalg(struct field_set_info
*info
, char *arg
);
55 static errcode_t
parse_time(struct field_set_info
*info
, char *arg
);
56 static errcode_t
parse_bmap(struct field_set_info
*info
, char *arg
);
58 static struct field_set_info super_fields
[] = {
59 { "inodes_count", &set_sb
.s_inodes_count
, 4, parse_uint
},
60 { "blocks_count", &set_sb
.s_blocks_count
, 4, parse_uint
},
61 { "r_blocks_count", &set_sb
.s_r_blocks_count
, 4, parse_uint
},
62 { "free_blocks_count", &set_sb
.s_free_blocks_count
, 4, parse_uint
},
63 { "free_inodes_count", &set_sb
.s_free_inodes_count
, 4, parse_uint
},
64 { "first_data_block", &set_sb
.s_first_data_block
, 4, parse_uint
},
65 { "log_block_size", &set_sb
.s_log_block_size
, 4, parse_uint
},
66 { "log_frag_size", &set_sb
.s_log_frag_size
, 4, parse_int
},
67 { "blocks_per_group", &set_sb
.s_blocks_per_group
, 4, parse_uint
},
68 { "frags_per_group", &set_sb
.s_frags_per_group
, 4, parse_uint
},
69 { "inodes_per_group", &set_sb
.s_inodes_per_group
, 4, parse_uint
},
70 { "mtime", &set_sb
.s_mtime
, 4, parse_time
},
71 { "wtime", &set_sb
.s_wtime
, 4, parse_time
},
72 { "mnt_count", &set_sb
.s_mnt_count
, 2, parse_uint
},
73 { "max_mnt_count", &set_sb
.s_max_mnt_count
, 2, parse_int
},
75 { "state", &set_sb
.s_state
, 2, parse_uint
},
76 { "errors", &set_sb
.s_errors
, 2, parse_uint
},
77 { "minor_rev_level", &set_sb
.s_minor_rev_level
, 2, parse_uint
},
78 { "lastcheck", &set_sb
.s_lastcheck
, 4, parse_time
},
79 { "checkinterval", &set_sb
.s_checkinterval
, 4, parse_uint
},
80 { "creator_os", &set_sb
.s_creator_os
, 4, parse_uint
},
81 { "rev_level", &set_sb
.s_rev_level
, 4, parse_uint
},
82 { "def_resuid", &set_sb
.s_def_resuid
, 2, parse_uint
},
83 { "def_resgid", &set_sb
.s_def_resgid
, 2, parse_uint
},
84 { "first_ino", &set_sb
.s_first_ino
, 4, parse_uint
},
85 { "inode_size", &set_sb
.s_inode_size
, 2, parse_uint
},
86 { "block_group_nr", &set_sb
.s_block_group_nr
, 2, parse_uint
},
87 { "feature_compat", &set_sb
.s_feature_compat
, 4, parse_uint
},
88 { "feature_incompat", &set_sb
.s_feature_incompat
, 4, parse_uint
},
89 { "feature_ro_compat", &set_sb
.s_feature_ro_compat
, 4, parse_uint
},
90 { "uuid", &set_sb
.s_uuid
, 16, parse_uuid
},
91 { "volume_name", &set_sb
.s_volume_name
, 16, parse_string
},
92 { "last_mounted", &set_sb
.s_last_mounted
, 64, parse_string
},
93 { "lastcheck", &set_sb
.s_lastcheck
, 4, parse_uint
},
94 { "algorithm_usage_bitmap", &set_sb
.s_algorithm_usage_bitmap
,
96 { "prealloc_blocks", &set_sb
.s_prealloc_blocks
, 1, parse_uint
},
97 { "prealloc_dir_blocks", &set_sb
.s_prealloc_dir_blocks
, 1,
99 { "reserved_gdt_blocks", &set_sb
.s_reserved_gdt_blocks
, 2,
102 { "journal_uuid", &set_sb
.s_journal_uuid
, 16, parse_uuid
},
103 { "journal_inum", &set_sb
.s_journal_inum
, 4, parse_uint
},
104 { "journal_dev", &set_sb
.s_journal_dev
, 4, parse_uint
},
105 { "last_orphan", &set_sb
.s_last_orphan
, 4, parse_uint
},
106 { "hash_seed", &set_sb
.s_hash_seed
, 16, parse_uuid
},
107 { "def_hash_version", &set_sb
.s_def_hash_version
, 1, parse_hashalg
},
108 { "jnl_backup_type", &set_sb
.s_jnl_backup_type
, 1, parse_uint
},
109 /* s_reserved_word_pad */
110 { "default_mount_opts", &set_sb
.s_default_mount_opts
, 4, parse_uint
},
111 { "first_meta_bg", &set_sb
.s_first_meta_bg
, 4, parse_uint
},
112 { "mkfs_time", &set_sb
.s_mkfs_time
, 4, parse_time
},
113 { "jnl_blocks", &set_sb
.s_jnl_blocks
[0], 4, parse_uint
, FLAG_ARRAY
,
115 { "flags", &set_sb
.s_flags
, 4, parse_uint
},
119 static struct field_set_info inode_fields
[] = {
120 { "inodes_count", &set_sb
.s_inodes_count
, 4, parse_uint
},
121 { "mode", &set_inode
.i_mode
, 2, parse_uint
},
122 { "uid", &set_inode
.i_uid
, 2, parse_uint
},
123 { "size", &set_inode
.i_size
, 4, parse_uint
},
124 { "atime", &set_inode
.i_atime
, 4, parse_time
},
125 { "ctime", &set_inode
.i_ctime
, 4, parse_time
},
126 { "mtime", &set_inode
.i_mtime
, 4, parse_time
},
127 { "dtime", &set_inode
.i_dtime
, 4, parse_time
},
128 { "gid", &set_inode
.i_gid
, 2, parse_uint
},
129 { "links_count", &set_inode
.i_links_count
, 2, parse_uint
},
130 { "blocks", &set_inode
.i_blocks
, 4, parse_uint
},
131 { "flags", &set_inode
.i_flags
, 4, parse_uint
},
132 { "version", &set_inode
.osd1
.linux1
.l_i_version
, 4, parse_uint
},
133 { "translator", &set_inode
.osd1
.hurd1
.h_i_translator
, 4, parse_uint
},
134 { "block", &set_inode
.i_block
[0], 4, parse_uint
, FLAG_ARRAY
,
136 { "block[IND]", &set_inode
.i_block
[EXT2_IND_BLOCK
], 4, parse_uint
},
137 { "block[DIND]", &set_inode
.i_block
[EXT2_DIND_BLOCK
], 4, parse_uint
},
138 { "block[TIND]", &set_inode
.i_block
[EXT2_TIND_BLOCK
], 4, parse_uint
},
139 { "generation", &set_inode
.i_generation
, 4, parse_uint
},
140 { "file_acl", &set_inode
.i_file_acl
, 4, parse_uint
},
141 { "dir_acl", &set_inode
.i_dir_acl
, 4, parse_uint
},
142 { "faddr", &set_inode
.i_faddr
, 4, parse_uint
},
143 { "blocks_hi", &set_inode
.osd2
.linux2
.l_i_blocks_hi
, 2, parse_uint
},
144 { "frag", &set_inode
.osd2
.hurd2
.h_i_frag
, 1, parse_uint
},
145 { "fsize", &set_inode
.osd2
.hurd2
.h_i_fsize
, 1, parse_uint
},
146 { "uid_high", &set_inode
.osd2
.linux2
.l_i_uid_high
, 2, parse_uint
},
147 { "gid_high", &set_inode
.osd2
.linux2
.l_i_gid_high
, 2, parse_uint
},
148 { "author", &set_inode
.osd2
.hurd2
.h_i_author
, 4, parse_uint
},
149 { "bmap", NULL
, 4, parse_bmap
, FLAG_ARRAY
},
153 static struct field_set_info ext2_bg_fields
[] = {
154 { "block_bitmap", &set_gd
.bg_block_bitmap
, 4, parse_uint
},
155 { "inode_bitmap", &set_gd
.bg_inode_bitmap
, 4, parse_uint
},
156 { "inode_table", &set_gd
.bg_inode_table
, 4, parse_uint
},
157 { "free_blocks_count", &set_gd
.bg_free_blocks_count
, 2, parse_uint
},
158 { "free_inodes_count", &set_gd
.bg_free_inodes_count
, 2, parse_uint
},
159 { "used_dirs_count", &set_gd
.bg_used_dirs_count
, 2, parse_uint
},
160 { "flags", &set_gd
.bg_flags
, 2, parse_uint
},
161 { "reserved", &set_gd
.bg_reserved
, 2, parse_uint
, FLAG_ARRAY
, 2 },
162 { "itable_unused", &set_gd
.bg_itable_unused
, 2, parse_uint
},
163 { "checksum", &set_gd
.bg_checksum
, 2, parse_uint
},
168 static struct field_set_info
*find_field(struct field_set_info
*fields
,
171 struct field_set_info
*ss
;
173 char *arg
, *delim
, *idx
, *tmp
;
176 if (fields
== super_fields
)
178 else if (fields
== inode_fields
)
182 prefix_len
= strlen(prefix
);
183 if (strncmp(field
, prefix
, prefix_len
) == 0)
186 arg
= malloc(strlen(field
)+1);
191 idx
= strchr(arg
, '[');
194 delim
= idx
+ strlen(idx
) - 1;
195 if (!*idx
|| *delim
!= ']')
201 * Can we parse the number?
204 array_idx
= strtol(idx
, &tmp
, 0);
209 for (ss
= fields
; ss
->name
; ss
++) {
210 if (ss
->flags
& FLAG_ARRAY
) {
211 if (!idx
|| (strcmp(ss
->name
, arg
) != 0))
213 if (ss
->max_idx
> 0 && array_idx
>= ss
->max_idx
)
216 if (strcmp(ss
->name
, field
) != 0)
225 static errcode_t
parse_uint(struct field_set_info
*info
, char *arg
)
235 u
.ptr8
= (__u8
*) info
->ptr
;
236 if (info
->flags
& FLAG_ARRAY
)
237 u
.ptr8
+= array_idx
* info
->size
;
239 num
= strtoul(arg
, &tmp
, 0);
241 fprintf(stderr
, "Couldn't parse '%s' for field %s.\n",
245 switch (info
->size
) {
259 static errcode_t
parse_int(struct field_set_info
*info
, char *arg
)
267 num
= strtol(arg
, &tmp
, 0);
269 fprintf(stderr
, "Couldn't parse '%s' for field %s.\n",
273 switch (info
->size
) {
275 ptr32
= (__s32
*) info
->ptr
;
279 ptr16
= (__s16
*) info
->ptr
;
283 ptr8
= (__s8
*) info
->ptr
;
290 static errcode_t
parse_string(struct field_set_info
*info
, char *arg
)
292 char *cp
= (char *) info
->ptr
;
294 if (strlen(arg
) >= info
->size
) {
295 fprintf(stderr
, "Error maximum size for %s is %d.\n",
296 info
->name
, info
->size
);
303 static errcode_t
parse_time(struct field_set_info
*info
, char *arg
)
308 ptr32
= (__u32
*) info
->ptr
;
310 t
= string_to_time(arg
);
312 if (t
== ((time_t) -1)) {
313 fprintf(stderr
, "Couldn't parse '%s' for field %s.\n",
321 static errcode_t
parse_uuid(struct field_set_info
*info
, char *arg
)
323 unsigned char * p
= (unsigned char *) info
->ptr
;
325 if ((strcasecmp(arg
, "null") == 0) ||
326 (strcasecmp(arg
, "clear") == 0)) {
328 } else if (strcasecmp(arg
, "time") == 0) {
329 uuid_generate_time(p
);
330 } else if (strcasecmp(arg
, "random") == 0) {
332 } else if (uuid_parse(arg
, p
)) {
333 fprintf(stderr
, "Invalid UUID format: %s\n", arg
);
339 static errcode_t
parse_hashalg(struct field_set_info
*info
, char *arg
)
342 unsigned char *p
= (unsigned char *) info
->ptr
;
344 hashv
= e2p_string2hash(arg
);
346 fprintf(stderr
, "Invalid hash algorithm: %s\n", arg
);
353 static errcode_t
parse_bmap(struct field_set_info
*info
, char *arg
)
360 num
= strtoul(arg
, &tmp
, 0);
362 fprintf(stderr
, "Couldn't parse '%s' for field %s.\n",
368 retval
= ext2fs_bmap(current_fs
, set_ino
, &set_inode
, 0, BMAP_SET
,
371 com_err("set_inode", retval
, "while setting block map");
377 static void print_possible_fields(struct field_set_info
*fields
)
379 struct field_set_info
*ss
;
380 const char *type
, *cmd
;
382 char name
[40], idx
[40];
384 if (fields
== super_fields
) {
386 cmd
= "set_super_value";
387 } else if (fields
== inode_fields
) {
391 type
= "Block group descriptor";
392 cmd
= "set_block_group";
396 fprintf(f
, "%s fields supported by the %s command:\n", type
, cmd
);
398 for (ss
= fields
; ss
->name
; ss
++) {
400 if (ss
->func
== parse_string
)
402 else if (ss
->func
== parse_int
)
404 else if (ss
->func
== parse_uint
)
405 type
= "unsigned integer";
406 else if (ss
->func
== parse_uuid
)
408 else if (ss
->func
== parse_hashalg
)
409 type
= "hash algorithm";
410 else if (ss
->func
== parse_time
)
412 else if (ss
->func
== parse_bmap
)
413 type
= "set physical->logical block map";
414 strcpy(name
, ss
->name
);
415 if (ss
->flags
& FLAG_ARRAY
) {
417 sprintf(idx
, "[%d]", ss
->max_idx
);
422 fprintf(f
, "\t%-20s\t%s\n", name
, type
);
428 void do_set_super(int argc
, char *argv
[])
430 const char *usage
= "<field> <value>\n"
431 "\t\"set_super_value -l\" will list the names of "
432 "superblock fields\n\twhich can be set.";
433 static struct field_set_info
*ss
;
435 if ((argc
== 2) && !strcmp(argv
[1], "-l")) {
436 print_possible_fields(super_fields
);
440 if (common_args_process(argc
, argv
, 3, 3, "set_super_value",
444 if ((ss
= find_field(super_fields
, argv
[1])) == 0) {
445 com_err(argv
[0], 0, "invalid field specifier: %s", argv
[1]);
448 set_sb
= *current_fs
->super
;
449 if (ss
->func(ss
, argv
[2]) == 0) {
450 *current_fs
->super
= set_sb
;
451 ext2fs_mark_super_dirty(current_fs
);
455 void do_set_inode(int argc
, char *argv
[])
457 const char *usage
= "<inode> <field> <value>\n"
458 "\t\"set_inode_field -l\" will list the names of "
459 "the fields in an ext2 inode\n\twhich can be set.";
460 static struct field_set_info
*ss
;
462 if ((argc
== 2) && !strcmp(argv
[1], "-l")) {
463 print_possible_fields(inode_fields
);
467 if (common_args_process(argc
, argv
, 4, 4, "set_inode",
471 if ((ss
= find_field(inode_fields
, argv
[2])) == 0) {
472 com_err(argv
[0], 0, "invalid field specifier: %s", argv
[2]);
476 set_ino
= string_to_inode(argv
[1]);
480 if (debugfs_read_inode(set_ino
, &set_inode
, argv
[1]))
483 if (ss
->func(ss
, argv
[3]) == 0) {
484 if (debugfs_write_inode(set_ino
, &set_inode
, argv
[1]))
489 void do_set_block_group_descriptor(int argc
, char *argv
[])
491 const char *usage
= "<bg number> <field> <value>\n"
492 "\t\"set_block_group_descriptor -l\" will list the names of "
493 "the fields in a block group descriptor\n\twhich can be set.";
494 struct field_set_info
*ss
;
498 if ((argc
== 2) && !strcmp(argv
[1], "-l")) {
499 print_possible_fields(ext2_bg_fields
);
503 if (common_args_process(argc
, argv
, 4, 4, "set_block_group_descriptor",
507 set_bg
= strtoul(argv
[1], &end
, 0);
509 com_err(argv
[0], 0, "invalid block group number: %s", argv
[1]);
513 if (set_bg
>= current_fs
->group_desc_count
) {
514 com_err(argv
[0], 0, "block group number too big: %d", set_bg
);
519 if ((ss
= find_field(ext2_bg_fields
, argv
[2])) == 0) {
520 com_err(argv
[0], 0, "invalid field specifier: %s", argv
[2]);
524 set_gd
= current_fs
->group_desc
[set_bg
];
526 if (ss
->func(ss
, argv
[3]) == 0) {
527 current_fs
->group_desc
[set_bg
] = set_gd
;
528 ext2fs_mark_super_dirty(current_fs
);