Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 1 | /* |
| 2 | * set_fields.c --- set a superblock value |
| 3 | * |
| 4 | * Copyright (C) 2000, 2001, 2002, 2003, 2004 by 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 | |
Theodore Ts'o | 07f031f | 2005-02-03 20:38:52 -0500 | [diff] [blame] | 12 | #define _XOPEN_SOURCE 500 /* for inclusion of strptime() */ |
Theodore Ts'o | 619a8ea | 2005-01-19 13:26:38 -0500 | [diff] [blame] | 13 | |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 14 | #include <stdio.h> |
| 15 | #include <unistd.h> |
| 16 | #include <stdlib.h> |
| 17 | #include <ctype.h> |
| 18 | #include <string.h> |
Theodore Ts'o | 8192c63 | 2008-01-01 10:27:38 -0500 | [diff] [blame^] | 19 | #include <strings.h> |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 20 | #include <time.h> |
| 21 | #include <sys/types.h> |
| 22 | #include <sys/stat.h> |
| 23 | #ifdef HAVE_ERRNO_H |
| 24 | #include <errno.h> |
| 25 | #endif |
| 26 | #include <fcntl.h> |
| 27 | #include <utime.h> |
| 28 | |
| 29 | #include "debugfs.h" |
| 30 | #include "uuid/uuid.h" |
| 31 | #include "e2p/e2p.h" |
| 32 | |
| 33 | static struct ext2_super_block set_sb; |
| 34 | static struct ext2_inode set_inode; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 35 | static struct ext2_group_desc set_gd; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 36 | static ext2_ino_t set_ino; |
| 37 | static int array_idx; |
| 38 | |
| 39 | #define FLAG_ARRAY 0x0001 |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 40 | |
| 41 | struct field_set_info { |
| 42 | const char *name; |
| 43 | void *ptr; |
| 44 | unsigned int size; |
| 45 | errcode_t (*func)(struct field_set_info *info, char *arg); |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 46 | int flags; |
| 47 | int max_idx; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 48 | }; |
| 49 | |
| 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); |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 56 | static errcode_t parse_bmap(struct field_set_info *info, char *arg); |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 57 | |
| 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 }, |
| 74 | /* s_magic */ |
| 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, |
| 95 | 4, parse_uint }, |
| 96 | { "prealloc_blocks", &set_sb.s_prealloc_blocks, 1, parse_uint }, |
| 97 | { "prealloc_dir_blocks", &set_sb.s_prealloc_dir_blocks, 1, |
| 98 | parse_uint }, |
| 99 | { "reserved_gdt_blocks", &set_sb.s_reserved_gdt_blocks, 2, |
| 100 | parse_uint }, |
| 101 | /* s_padding1 */ |
| 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 }, |
Theodore Ts'o | 89c8015 | 2005-01-20 21:45:27 -0500 | [diff] [blame] | 113 | { "jnl_blocks", &set_sb.s_jnl_blocks[0], 4, parse_uint, FLAG_ARRAY, |
| 114 | 17 }, |
Theodore Ts'o | f77704e | 2006-11-11 22:32:35 -0500 | [diff] [blame] | 115 | { "flags", &set_sb.s_flags, 4, parse_uint }, |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 116 | { 0, 0, 0, 0 } |
| 117 | }; |
| 118 | |
| 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 }, |
Theodore Ts'o | 38d732b | 2005-09-06 05:42:44 -0400 | [diff] [blame] | 123 | { "size", &set_inode.i_size, 4, parse_uint }, |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 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 }, |
Theodore Ts'o | d362a3f | 2007-04-19 01:53:53 -0400 | [diff] [blame] | 132 | { "version", &set_inode.osd1.linux1.l_i_version, 4, parse_uint }, |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 133 | { "translator", &set_inode.osd1.hurd1.h_i_translator, 4, parse_uint }, |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 134 | { "block", &set_inode.i_block[0], 4, parse_uint, FLAG_ARRAY, |
| 135 | EXT2_NDIR_BLOCKS }, |
| 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 }, |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 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 }, |
Theodore Ts'o | 5d17119 | 2006-11-11 06:32:03 -0500 | [diff] [blame] | 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 }, |
Theodore Ts'o | caf037a | 2005-07-04 12:24:40 -0500 | [diff] [blame] | 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 }, |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 149 | { "bmap", NULL, 4, parse_bmap, FLAG_ARRAY }, |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 150 | { 0, 0, 0, 0 } |
| 151 | }; |
| 152 | |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 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 }, |
| 164 | { 0, 0, 0, 0 } |
| 165 | }; |
| 166 | |
| 167 | |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 168 | static struct field_set_info *find_field(struct field_set_info *fields, |
| 169 | char *field) |
| 170 | { |
| 171 | struct field_set_info *ss; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 172 | const char *prefix; |
| 173 | char *arg, *delim, *idx, *tmp; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 174 | int prefix_len; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 175 | |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 176 | if (fields == super_fields) |
| 177 | prefix = "s_"; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 178 | else if (fields == inode_fields) |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 179 | prefix = "i_"; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 180 | else |
| 181 | prefix = "bg_"; |
| 182 | prefix_len = strlen(prefix); |
| 183 | if (strncmp(field, prefix, prefix_len) == 0) |
| 184 | field += prefix_len; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 185 | |
| 186 | arg = malloc(strlen(field)+1); |
| 187 | if (!arg) |
| 188 | return NULL; |
| 189 | strcpy(arg, field); |
| 190 | |
| 191 | idx = strchr(arg, '['); |
| 192 | if (idx) { |
| 193 | *idx++ = 0; |
| 194 | delim = idx + strlen(idx) - 1; |
| 195 | if (!*idx || *delim != ']') |
| 196 | idx = 0; |
| 197 | else |
| 198 | *delim = 0; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 199 | } |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 200 | /* |
| 201 | * Can we parse the number? |
| 202 | */ |
| 203 | if (idx) { |
| 204 | array_idx = strtol(idx, &tmp, 0); |
| 205 | if (*tmp) |
| 206 | idx = 0; |
| 207 | } |
| 208 | |
| 209 | for (ss = fields ; ss->name ; ss++) { |
| 210 | if (ss->flags & FLAG_ARRAY) { |
| 211 | if (!idx || (strcmp(ss->name, arg) != 0)) |
| 212 | continue; |
| 213 | if (ss->max_idx > 0 && array_idx >= ss->max_idx) |
| 214 | continue; |
| 215 | } else { |
| 216 | if (strcmp(ss->name, field) != 0) |
| 217 | continue; |
| 218 | } |
| 219 | return ss; |
| 220 | } |
| 221 | |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 222 | return NULL; |
| 223 | } |
| 224 | |
| 225 | static errcode_t parse_uint(struct field_set_info *info, char *arg) |
| 226 | { |
| 227 | unsigned long num; |
| 228 | char *tmp; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 229 | union { |
| 230 | __u32 *ptr32; |
| 231 | __u16 *ptr16; |
| 232 | __u8 *ptr8; |
| 233 | } u; |
| 234 | |
| 235 | u.ptr8 = (__u8 *) info->ptr; |
| 236 | if (info->flags & FLAG_ARRAY) |
| 237 | u.ptr8 += array_idx * info->size; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 238 | |
| 239 | num = strtoul(arg, &tmp, 0); |
| 240 | if (*tmp) { |
| 241 | fprintf(stderr, "Couldn't parse '%s' for field %s.\n", |
| 242 | arg, info->name); |
| 243 | return EINVAL; |
| 244 | } |
| 245 | switch (info->size) { |
| 246 | case 4: |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 247 | *u.ptr32 = num; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 248 | break; |
| 249 | case 2: |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 250 | *u.ptr16 = num; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 251 | break; |
| 252 | case 1: |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 253 | *u.ptr8 = num; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 254 | break; |
| 255 | } |
| 256 | return 0; |
| 257 | } |
| 258 | |
| 259 | static errcode_t parse_int(struct field_set_info *info, char *arg) |
| 260 | { |
| 261 | long num; |
| 262 | char *tmp; |
| 263 | __s32 *ptr32; |
| 264 | __s16 *ptr16; |
| 265 | __s8 *ptr8; |
| 266 | |
| 267 | num = strtol(arg, &tmp, 0); |
| 268 | if (*tmp) { |
| 269 | fprintf(stderr, "Couldn't parse '%s' for field %s.\n", |
| 270 | arg, info->name); |
| 271 | return EINVAL; |
| 272 | } |
| 273 | switch (info->size) { |
| 274 | case 4: |
| 275 | ptr32 = (__s32 *) info->ptr; |
| 276 | *ptr32 = num; |
| 277 | break; |
| 278 | case 2: |
| 279 | ptr16 = (__s16 *) info->ptr; |
| 280 | *ptr16 = num; |
| 281 | break; |
| 282 | case 1: |
| 283 | ptr8 = (__s8 *) info->ptr; |
| 284 | *ptr8 = num; |
| 285 | break; |
| 286 | } |
| 287 | return 0; |
| 288 | } |
| 289 | |
| 290 | static errcode_t parse_string(struct field_set_info *info, char *arg) |
| 291 | { |
| 292 | char *cp = (char *) info->ptr; |
| 293 | |
| 294 | if (strlen(arg) >= info->size) { |
| 295 | fprintf(stderr, "Error maximum size for %s is %d.\n", |
| 296 | info->name, info->size); |
| 297 | return EINVAL; |
| 298 | } |
| 299 | strcpy(cp, arg); |
| 300 | return 0; |
| 301 | } |
| 302 | |
| 303 | static errcode_t parse_time(struct field_set_info *info, char *arg) |
| 304 | { |
Theodore Ts'o | e3e9253 | 2006-05-21 19:26:06 -0400 | [diff] [blame] | 305 | time_t t; |
| 306 | __u32 *ptr32; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 307 | |
| 308 | ptr32 = (__u32 *) info->ptr; |
| 309 | |
Theodore Ts'o | 4efae60 | 2005-09-24 21:56:38 -0400 | [diff] [blame] | 310 | t = string_to_time(arg); |
| 311 | |
| 312 | if (t == ((time_t) -1)) { |
| 313 | fprintf(stderr, "Couldn't parse '%s' for field %s.\n", |
| 314 | arg, info->name); |
| 315 | return EINVAL; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 316 | } |
Theodore Ts'o | 4efae60 | 2005-09-24 21:56:38 -0400 | [diff] [blame] | 317 | *ptr32 = t; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 318 | return 0; |
| 319 | } |
| 320 | |
| 321 | static errcode_t parse_uuid(struct field_set_info *info, char *arg) |
| 322 | { |
| 323 | unsigned char * p = (unsigned char *) info->ptr; |
| 324 | |
| 325 | if ((strcasecmp(arg, "null") == 0) || |
| 326 | (strcasecmp(arg, "clear") == 0)) { |
| 327 | uuid_clear(p); |
| 328 | } else if (strcasecmp(arg, "time") == 0) { |
| 329 | uuid_generate_time(p); |
| 330 | } else if (strcasecmp(arg, "random") == 0) { |
| 331 | uuid_generate(p); |
| 332 | } else if (uuid_parse(arg, p)) { |
| 333 | fprintf(stderr, "Invalid UUID format: %s\n", arg); |
| 334 | return EINVAL; |
| 335 | } |
| 336 | return 0; |
| 337 | } |
| 338 | |
| 339 | static errcode_t parse_hashalg(struct field_set_info *info, char *arg) |
| 340 | { |
| 341 | int hashv; |
| 342 | unsigned char *p = (unsigned char *) info->ptr; |
| 343 | |
| 344 | hashv = e2p_string2hash(arg); |
| 345 | if (hashv < 0) { |
| 346 | fprintf(stderr, "Invalid hash algorithm: %s\n", arg); |
| 347 | return EINVAL; |
| 348 | } |
| 349 | *p = hashv; |
| 350 | return 0; |
| 351 | } |
| 352 | |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 353 | static errcode_t parse_bmap(struct field_set_info *info, char *arg) |
| 354 | { |
| 355 | unsigned long num; |
| 356 | blk_t blk; |
| 357 | errcode_t retval; |
| 358 | char *tmp; |
| 359 | |
| 360 | num = strtoul(arg, &tmp, 0); |
| 361 | if (*tmp) { |
| 362 | fprintf(stderr, "Couldn't parse '%s' for field %s.\n", |
| 363 | arg, info->name); |
| 364 | return EINVAL; |
| 365 | } |
| 366 | blk = num; |
| 367 | |
| 368 | retval = ext2fs_bmap(current_fs, set_ino, &set_inode, 0, BMAP_SET, |
| 369 | array_idx, &blk); |
| 370 | if (retval) { |
| 371 | com_err("set_inode", retval, "while setting block map"); |
| 372 | } |
Theodore Ts'o | 619a8ea | 2005-01-19 13:26:38 -0500 | [diff] [blame] | 373 | return retval; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 374 | } |
| 375 | |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 376 | |
| 377 | static void print_possible_fields(struct field_set_info *fields) |
| 378 | { |
| 379 | struct field_set_info *ss; |
| 380 | const char *type, *cmd; |
| 381 | FILE *f; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 382 | char name[40], idx[40]; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 383 | |
| 384 | if (fields == super_fields) { |
| 385 | type = "Superblock"; |
| 386 | cmd = "set_super_value"; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 387 | } else if (fields == inode_fields) { |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 388 | type = "Inode"; |
| 389 | cmd = "set_inode"; |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 390 | } else { |
| 391 | type = "Block group descriptor"; |
| 392 | cmd = "set_block_group"; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 393 | } |
| 394 | f = open_pager(); |
| 395 | |
| 396 | fprintf(f, "%s fields supported by the %s command:\n", type, cmd); |
| 397 | |
| 398 | for (ss = fields ; ss->name ; ss++) { |
| 399 | type = "unknown"; |
| 400 | if (ss->func == parse_string) |
| 401 | type = "string"; |
| 402 | else if (ss->func == parse_int) |
| 403 | type = "integer"; |
| 404 | else if (ss->func == parse_uint) |
| 405 | type = "unsigned integer"; |
| 406 | else if (ss->func == parse_uuid) |
| 407 | type = "UUID"; |
| 408 | else if (ss->func == parse_hashalg) |
| 409 | type = "hash algorithm"; |
| 410 | else if (ss->func == parse_time) |
| 411 | type = "date/time"; |
Theodore Ts'o | 1d3a951 | 2005-01-07 21:14:12 -0500 | [diff] [blame] | 412 | else if (ss->func == parse_bmap) |
| 413 | type = "set physical->logical block map"; |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 414 | strcpy(name, ss->name); |
| 415 | if (ss->flags & FLAG_ARRAY) { |
| 416 | if (ss->max_idx > 0) |
| 417 | sprintf(idx, "[%d]", ss->max_idx); |
| 418 | else |
| 419 | strcpy(idx, "[]"); |
| 420 | strcat(name, idx); |
| 421 | } |
| 422 | fprintf(f, "\t%-20s\t%s\n", name, type); |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 423 | } |
| 424 | close_pager(f); |
| 425 | } |
| 426 | |
| 427 | |
| 428 | void do_set_super(int argc, char *argv[]) |
| 429 | { |
| 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; |
| 434 | |
| 435 | if ((argc == 2) && !strcmp(argv[1], "-l")) { |
| 436 | print_possible_fields(super_fields); |
| 437 | return; |
| 438 | } |
| 439 | |
| 440 | if (common_args_process(argc, argv, 3, 3, "set_super_value", |
| 441 | usage, CHECK_FS_RW)) |
| 442 | return; |
| 443 | |
| 444 | if ((ss = find_field(super_fields, argv[1])) == 0) { |
| 445 | com_err(argv[0], 0, "invalid field specifier: %s", argv[1]); |
| 446 | return; |
| 447 | } |
| 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); |
| 452 | } |
| 453 | } |
| 454 | |
| 455 | void do_set_inode(int argc, char *argv[]) |
| 456 | { |
| 457 | const char *usage = "<inode> <field> <value>\n" |
Theodore Ts'o | 1d3a951 | 2005-01-07 21:14:12 -0500 | [diff] [blame] | 458 | "\t\"set_inode_field -l\" will list the names of " |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 459 | "the fields in an ext2 inode\n\twhich can be set."; |
| 460 | static struct field_set_info *ss; |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 461 | |
| 462 | if ((argc == 2) && !strcmp(argv[1], "-l")) { |
| 463 | print_possible_fields(inode_fields); |
| 464 | return; |
| 465 | } |
| 466 | |
| 467 | if (common_args_process(argc, argv, 4, 4, "set_inode", |
| 468 | usage, CHECK_FS_RW)) |
| 469 | return; |
| 470 | |
| 471 | if ((ss = find_field(inode_fields, argv[2])) == 0) { |
| 472 | com_err(argv[0], 0, "invalid field specifier: %s", argv[2]); |
| 473 | return; |
| 474 | } |
| 475 | |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 476 | set_ino = string_to_inode(argv[1]); |
| 477 | if (!set_ino) |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 478 | return; |
| 479 | |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 480 | if (debugfs_read_inode(set_ino, &set_inode, argv[1])) |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 481 | return; |
| 482 | |
| 483 | if (ss->func(ss, argv[3]) == 0) { |
Theodore Ts'o | 08fd3f3 | 2004-12-23 14:11:34 -0500 | [diff] [blame] | 484 | if (debugfs_write_inode(set_ino, &set_inode, argv[1])) |
Theodore Ts'o | 7dec050 | 2004-12-21 20:37:36 -0500 | [diff] [blame] | 485 | return; |
| 486 | } |
| 487 | } |
Theodore Ts'o | c7c1209 | 2007-04-13 15:56:00 -0400 | [diff] [blame] | 488 | |
| 489 | void do_set_block_group_descriptor(int argc, char *argv[]) |
| 490 | { |
| 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; |
| 495 | dgrp_t set_bg; |
| 496 | char *end; |
| 497 | |
| 498 | if ((argc == 2) && !strcmp(argv[1], "-l")) { |
| 499 | print_possible_fields(ext2_bg_fields); |
| 500 | return; |
| 501 | } |
| 502 | |
| 503 | if (common_args_process(argc, argv, 4, 4, "set_block_group_descriptor", |
| 504 | usage, CHECK_FS_RW)) |
| 505 | return; |
| 506 | |
| 507 | set_bg = strtoul(argv[1], &end, 0); |
| 508 | if (*end) { |
| 509 | com_err(argv[0], 0, "invalid block group number: %s", argv[1]); |
| 510 | return; |
| 511 | } |
| 512 | |
| 513 | if (set_bg >= current_fs->group_desc_count) { |
| 514 | com_err(argv[0], 0, "block group number too big: %d", set_bg); |
| 515 | return; |
| 516 | } |
| 517 | |
| 518 | |
| 519 | if ((ss = find_field(ext2_bg_fields, argv[2])) == 0) { |
| 520 | com_err(argv[0], 0, "invalid field specifier: %s", argv[2]); |
| 521 | return; |
| 522 | } |
| 523 | |
| 524 | set_gd = current_fs->group_desc[set_bg]; |
| 525 | |
| 526 | if (ss->func(ss, argv[3]) == 0) { |
| 527 | current_fs->group_desc[set_bg] = set_gd; |
| 528 | ext2fs_mark_super_dirty(current_fs); |
| 529 | } |
| 530 | } |