Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 1 | /* |
| 2 | * csum.c --- checksumming of ext3 structures |
| 3 | * |
| 4 | * Copyright (C) 2006 Cluster File Systems, Inc. |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 5 | * Copyright (C) 2006, 2007 by Andreas Dilger <adilger@clusterfs.com> |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 6 | * |
| 7 | * %Begin-Header% |
Theodore Ts'o | 543547a | 2010-05-17 21:31:56 -0400 | [diff] [blame] | 8 | * This file may be redistributed under the terms of the GNU Library |
| 9 | * General Public License, version 2. |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 10 | * %End-Header% |
| 11 | */ |
| 12 | |
Theodore Ts'o | d1154eb | 2011-09-18 17:34:37 -0400 | [diff] [blame] | 13 | #include "config.h" |
Theodore Ts'o | 0eeec8a | 2008-09-12 09:10:39 -0400 | [diff] [blame] | 14 | #if HAVE_SYS_TYPES_H |
| 15 | #include <sys/types.h> |
| 16 | #endif |
| 17 | |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 18 | #include "ext2_fs.h" |
| 19 | #include "ext2fs.h" |
| 20 | #include "crc16.h" |
| 21 | #include <assert.h> |
| 22 | |
| 23 | #ifndef offsetof |
| 24 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| 25 | #endif |
| 26 | |
| 27 | #ifdef DEBUG |
| 28 | #define STATIC |
| 29 | #else |
| 30 | #define STATIC static |
| 31 | #endif |
| 32 | |
Theodore Ts'o | 8714178 | 2012-03-15 12:13:25 -0400 | [diff] [blame] | 33 | __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group) |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 34 | { |
| 35 | __u16 crc = 0; |
| 36 | struct ext2_group_desc *desc; |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 37 | size_t size; |
| 38 | |
| 39 | size = fs->super->s_desc_size; |
| 40 | if (size < EXT2_MIN_DESC_SIZE) |
| 41 | size = EXT2_MIN_DESC_SIZE; |
| 42 | if (size > sizeof(struct ext4_group_desc)) { |
| 43 | printf("%s: illegal s_desc_size(%zd)\n", __func__, size); |
| 44 | size = sizeof(struct ext4_group_desc); |
| 45 | } |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 46 | |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 47 | desc = ext2fs_group_desc(fs, fs->group_desc, group); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 48 | |
| 49 | if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { |
Theodore Ts'o | d32c915 | 2011-07-07 13:50:22 -0400 | [diff] [blame] | 50 | size_t offset = offsetof(struct ext2_group_desc, bg_checksum); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 51 | |
| 52 | #ifdef WORDS_BIGENDIAN |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 53 | struct ext4_group_desc swabdesc; |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 54 | |
| 55 | /* Have to swab back to little-endian to do the checksum */ |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 56 | memcpy(&swabdesc, desc, size); |
| 57 | ext2fs_swap_group_desc2(fs, |
| 58 | (struct ext2_group_desc *) &swabdesc); |
| 59 | desc = (struct ext2_group_desc *) &swabdesc; |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 60 | |
| 61 | group = ext2fs_swab32(group); |
| 62 | #endif |
Theodore Ts'o | c4dcb1c | 2008-08-24 22:44:33 -0400 | [diff] [blame] | 63 | crc = ext2fs_crc16(~0, fs->super->s_uuid, |
| 64 | sizeof(fs->super->s_uuid)); |
| 65 | crc = ext2fs_crc16(crc, &group, sizeof(group)); |
| 66 | crc = ext2fs_crc16(crc, desc, offset); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 67 | offset += sizeof(desc->bg_checksum); /* skip checksum */ |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 68 | /* for checksum of struct ext4_group_desc do the rest...*/ |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 69 | if (offset < size) { |
Theodore Ts'o | c4dcb1c | 2008-08-24 22:44:33 -0400 | [diff] [blame] | 70 | crc = ext2fs_crc16(crc, (char *)desc + offset, |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 71 | size - offset); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 72 | } |
| 73 | } |
| 74 | |
| 75 | return crc; |
| 76 | } |
| 77 | |
| 78 | int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group) |
| 79 | { |
Theodore Ts'o | 4729455 | 2008-07-13 19:03:59 -0400 | [diff] [blame] | 80 | if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, |
| 81 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 82 | (ext2fs_bg_checksum(fs, group) != |
Theodore Ts'o | 4729455 | 2008-07-13 19:03:59 -0400 | [diff] [blame] | 83 | ext2fs_group_desc_csum(fs, group))) |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 84 | return 0; |
| 85 | |
| 86 | return 1; |
| 87 | } |
| 88 | |
| 89 | void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group) |
| 90 | { |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 91 | if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, |
| 92 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) |
| 93 | return; |
| 94 | |
| 95 | /* ext2fs_bg_checksum_set() sets the actual checksum field but |
| 96 | * does not calculate the checksum itself. */ |
| 97 | ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group)); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap, |
| 101 | __u32 inodes_per_grp, dgrp_t grp_no) |
| 102 | { |
| 103 | ext2_ino_t i, start_ino, end_ino; |
| 104 | |
| 105 | start_ino = grp_no * inodes_per_grp + 1; |
| 106 | end_ino = start_ino + inodes_per_grp - 1; |
| 107 | |
| 108 | for (i = end_ino; i >= start_ino; i--) { |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 109 | if (ext2fs_fast_test_inode_bitmap2(bitmap, i)) |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 110 | return i - start_ino + 1; |
| 111 | } |
| 112 | return inodes_per_grp; |
| 113 | } |
| 114 | |
| 115 | /* update the bitmap flags, set the itable high watermark, and calculate |
| 116 | * checksums for the group descriptors */ |
Andreas Dilger | f628ace | 2008-03-31 10:50:19 -0400 | [diff] [blame] | 117 | errcode_t ext2fs_set_gdt_csum(ext2_filsys fs) |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 118 | { |
| 119 | struct ext2_super_block *sb = fs->super; |
Theodore Ts'o | 8895f43 | 2008-06-07 11:53:56 -0400 | [diff] [blame] | 120 | int dirty = 0; |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 121 | dgrp_t i; |
| 122 | |
Andreas Dilger | f628ace | 2008-03-31 10:50:19 -0400 | [diff] [blame] | 123 | if (!fs->inode_map) |
| 124 | return EXT2_ET_NO_INODE_BITMAP; |
| 125 | |
Theodore Ts'o | 16b851c | 2008-04-20 23:33:34 -0400 | [diff] [blame] | 126 | if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, |
| 127 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) |
Andreas Dilger | f628ace | 2008-03-31 10:50:19 -0400 | [diff] [blame] | 128 | return 0; |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 129 | |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 130 | for (i = 0; i < fs->group_desc_count; i++) { |
Theodore Ts'o | d32c915 | 2011-07-07 13:50:22 -0400 | [diff] [blame] | 131 | __u32 old_csum = ext2fs_bg_checksum(fs, i); |
| 132 | __u32 old_unused = ext2fs_bg_itable_unused(fs, i); |
| 133 | __u32 old_flags = ext2fs_bg_flags(fs, i); |
| 134 | __u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 135 | |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 136 | if (old_free_inodes_count == sb->s_inodes_per_group) { |
| 137 | ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); |
| 138 | ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group); |
Theodore Ts'o | 16b851c | 2008-04-20 23:33:34 -0400 | [diff] [blame] | 139 | } else { |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 140 | int unused = |
| 141 | sb->s_inodes_per_group - |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 142 | find_last_inode_ingrp(fs->inode_map, |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 143 | sb->s_inodes_per_group, i); |
| 144 | |
| 145 | ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT); |
| 146 | ext2fs_bg_itable_unused_set(fs, i, unused); |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 147 | } |
| 148 | |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 149 | ext2fs_group_desc_csum_set(fs, i); |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 150 | if (old_flags != ext2fs_bg_flags(fs, i)) |
Andreas Dilger | 80fc4e6 | 2008-03-31 00:40:51 -0400 | [diff] [blame] | 151 | dirty = 1; |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 152 | if (old_unused != ext2fs_bg_itable_unused(fs, i)) |
Andreas Dilger | 80fc4e6 | 2008-03-31 00:40:51 -0400 | [diff] [blame] | 153 | dirty = 1; |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 154 | if (old_csum != ext2fs_bg_checksum(fs, i)) |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 155 | dirty = 1; |
| 156 | } |
| 157 | if (dirty) |
| 158 | ext2fs_mark_super_dirty(fs); |
Andreas Dilger | f628ace | 2008-03-31 10:50:19 -0400 | [diff] [blame] | 159 | return 0; |
Jose R. Santos | ca2634a | 2007-10-21 21:03:19 -0500 | [diff] [blame] | 160 | } |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 161 | |
| 162 | #ifdef DEBUG |
Eric Sandeen | c816ecb | 2010-12-14 13:00:01 -0600 | [diff] [blame] | 163 | #include "e2p/e2p.h" |
| 164 | |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 165 | void print_csum(const char *msg, ext2_filsys fs, dgrp_t group) |
| 166 | { |
| 167 | __u16 crc1, crc2, crc3; |
| 168 | dgrp_t swabgroup; |
Andreas Dilger | f797cf3 | 2012-11-29 05:47:51 -0700 | [diff] [blame] | 169 | struct ext2_group_desc *desc; |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 170 | size_t size; |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 171 | struct ext2_super_block *sb = fs->super; |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 172 | int offset = offsetof(struct ext2_group_desc, bg_checksum); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 173 | #ifdef WORDS_BIGENDIAN |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 174 | struct ext4_group_desc swabdesc; |
| 175 | #endif |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 176 | |
Andreas Dilger | f797cf3 | 2012-11-29 05:47:51 -0700 | [diff] [blame] | 177 | desc = ext2fs_group_desc(fs, fs->group_desc, group); |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 178 | size = fs->super->s_desc_size; |
| 179 | if (size < EXT2_MIN_DESC_SIZE) |
| 180 | size = EXT2_MIN_DESC_SIZE; |
| 181 | if (size > sizeof(struct ext4_group_desc)) |
| 182 | size = sizeof(struct ext4_group_desc); |
| 183 | #ifdef WORDS_BIGENDIAN |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 184 | /* Have to swab back to little-endian to do the checksum */ |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 185 | memcpy(&swabdesc, desc, size); |
| 186 | ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc); |
| 187 | desc = (struct ext2_group_desc *) &swabdesc; |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 188 | |
| 189 | swabgroup = ext2fs_swab32(group); |
| 190 | #else |
| 191 | swabgroup = group; |
| 192 | #endif |
| 193 | |
| 194 | crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid)); |
| 195 | crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup)); |
Theodore Ts'o | 1d18a55 | 2010-02-15 09:51:28 -0500 | [diff] [blame] | 196 | crc3 = ext2fs_crc16(crc2, desc, offset); |
| 197 | offset += sizeof(desc->bg_checksum); /* skip checksum */ |
| 198 | /* for checksum of struct ext4_group_desc do the rest...*/ |
| 199 | if (offset < size) |
| 200 | crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset); |
| 201 | |
Andreas Dilger | f797cf3 | 2012-11-29 05:47:51 -0700 | [diff] [blame] | 202 | printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n", |
Theodore Ts'o | 562f264 | 2010-12-20 10:06:58 -0500 | [diff] [blame] | 203 | msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3, |
Eric Sandeen | c816ecb | 2010-12-14 13:00:01 -0600 | [diff] [blame] | 204 | ext2fs_group_desc_csum(fs, group)); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23, |
| 208 | 0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb }; |
| 209 | |
| 210 | int main(int argc, char **argv) |
| 211 | { |
| 212 | struct ext2_super_block param; |
| 213 | errcode_t retval; |
| 214 | ext2_filsys fs; |
| 215 | int i; |
| 216 | __u16 csum1, csum2, csum_known = 0xd3a4; |
| 217 | |
| 218 | memset(¶m, 0, sizeof(param)); |
Valerie Aurora Henson | 4efbac6 | 2009-09-07 20:46:34 -0400 | [diff] [blame] | 219 | ext2fs_blocks_count_set(¶m, 32768); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 220 | |
Valerie Aurora Henson | 8f82ef9 | 2009-08-05 00:27:10 -0400 | [diff] [blame] | 221 | retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 222 | test_io_manager, &fs); |
| 223 | if (retval) { |
| 224 | com_err("setup", retval, |
| 225 | "While initializing filesystem"); |
| 226 | exit(1); |
| 227 | } |
| 228 | memcpy(fs->super->s_uuid, sb_uuid, 16); |
| 229 | fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM; |
| 230 | |
| 231 | for (i=0; i < fs->group_desc_count; i++) { |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 232 | ext2fs_block_bitmap_loc_set(fs, i, 124); |
| 233 | ext2fs_inode_bitmap_loc_set(fs, i, 125); |
| 234 | ext2fs_inode_table_loc_set(fs, i, 126); |
| 235 | ext2fs_bg_free_blocks_count_set(fs, i, 31119); |
| 236 | ext2fs_bg_free_inodes_count_set(fs, i, 15701); |
| 237 | ext2fs_bg_used_dirs_count_set(fs, i, 2); |
Eric Sandeen | e633b58 | 2009-10-25 21:41:32 -0400 | [diff] [blame] | 238 | ext2fs_bg_flags_zap(fs, i); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 239 | }; |
| 240 | |
| 241 | csum1 = ext2fs_group_desc_csum(fs, 0); |
| 242 | print_csum("csum0000", fs, 0); |
| 243 | |
| 244 | if (csum1 != csum_known) { |
| 245 | printf("checksum for group 0 should be %04x\n", csum_known); |
| 246 | exit(1); |
| 247 | } |
| 248 | csum2 = ext2fs_group_desc_csum(fs, 1); |
| 249 | print_csum("csum0001", fs, 1); |
| 250 | if (csum1 == csum2) { |
| 251 | printf("checksums for different groups shouldn't match\n"); |
| 252 | exit(1); |
| 253 | } |
| 254 | csum2 = ext2fs_group_desc_csum(fs, 2); |
| 255 | print_csum("csumffff", fs, 2); |
| 256 | if (csum1 == csum2) { |
| 257 | printf("checksums for different groups shouldn't match\n"); |
| 258 | exit(1); |
| 259 | } |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 260 | ext2fs_bg_checksum_set(fs, 0, csum1); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 261 | csum2 = ext2fs_group_desc_csum(fs, 0); |
| 262 | print_csum("csum_set", fs, 0); |
| 263 | if (csum1 != csum2) { |
| 264 | printf("checksums should not depend on checksum field\n"); |
| 265 | exit(1); |
| 266 | } |
| 267 | if (!ext2fs_group_desc_csum_verify(fs, 0)) { |
| 268 | printf("checksums should verify against gd_checksum\n"); |
| 269 | exit(1); |
| 270 | } |
| 271 | memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid)); |
| 272 | print_csum("new_uuid", fs, 0); |
| 273 | if (ext2fs_group_desc_csum_verify(fs, 0) != 0) { |
| 274 | printf("checksums for different filesystems shouldn't match\n"); |
| 275 | exit(1); |
| 276 | } |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 277 | csum1 = ext2fs_group_desc_csum(fs, 0); |
| 278 | ext2fs_bg_checksum_set(fs, 0, csum1); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 279 | print_csum("csum_new", fs, 0); |
Valerie Aurora Henson | d7cca6b | 2009-10-25 21:43:47 -0400 | [diff] [blame] | 280 | ext2fs_bg_free_blocks_count_set(fs, 0, 1); |
Theodore Ts'o | 470e737 | 2009-05-29 11:01:22 -0400 | [diff] [blame] | 281 | csum2 = ext2fs_group_desc_csum(fs, 0); |
| 282 | print_csum("csum_blk", fs, 0); |
| 283 | if (csum1 == csum2) { |
| 284 | printf("checksums for different data shouldn't match\n"); |
| 285 | exit(1); |
| 286 | } |
| 287 | |
| 288 | return 0; |
| 289 | } |
| 290 | #endif |