1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 1999, 2000, 2002, 2007 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /* It's a bit silly calling a swap partition a file system. Oh well... */ 20 21 #include <config.h> 22 23 #include <parted/parted.h> 24 #include <parted/endian.h> 25 26 #if ENABLE_NLS 27 # include <libintl.h> 28 # define _(String) dgettext (PACKAGE, String) 29 #else 30 # define _(String) (String) 31 #endif /* ENABLE_NLS */ 32 33 #include <unistd.h> 34 35 #define SWAP_SPECIFIC(fs) ((SwapSpecific*) (fs->type_specific)) 36 #define BUFFER_SIZE 128 37 38 #define LINUXSWAP_BLOCK_SIZES ((int[2]){512, 0}) 39 40 typedef struct { 41 char page_map[1]; 42 } SwapOldHeader; 43 44 /* ripped from mkswap */ 45 typedef struct { 46 char bootbits[1024]; /* Space for disklabel etc. */ 47 uint32_t version; 48 uint32_t last_page; 49 uint32_t nr_badpages; 50 unsigned char sws_uuid[16]; 51 unsigned char sws_volume[16]; 52 uint32_t padding[117]; 53 uint32_t badpages[1]; 54 } SwapNewHeader; 55 56 typedef struct { 57 union { 58 SwapNewHeader new; 59 SwapOldHeader old; 60 }* header; 61 62 void* buffer; 63 int buffer_size; 64 65 PedSector page_sectors; 66 unsigned int page_count; 67 unsigned int version; 68 unsigned int max_bad_pages; 69 } SwapSpecific; 70 71 static PedFileSystemType swap_type; 72 73 static PedFileSystem* swap_open (PedGeometry* geom); 74 static int swap_close (PedFileSystem* fs); 75 76 static PedGeometry* 77 swap_probe (PedGeometry* geom) 78 { 79 PedFileSystem* fs; 80 SwapSpecific* fs_info; 81 PedGeometry* probed_geom; 82 PedSector length; 83 84 fs = swap_open (geom); 85 if (!fs) 86 goto error; 87 fs_info = SWAP_SPECIFIC (fs); 88 89 if (fs_info->version) 90 length = fs_info->page_sectors * fs_info->page_count; 91 else 92 length = geom->length; 93 probed_geom = ped_geometry_new (geom->dev, geom->start, length); 94 if (!probed_geom) 95 goto error_close_fs; 96 swap_close (fs); 97 return probed_geom; 98 99 error_close_fs: 100 swap_close (fs); 101 error: 102 return NULL; 103 } 104 105 #ifndef DISCOVER_ONLY 106 static int 107 swap_clobber (PedGeometry* geom) 108 { 109 PedFileSystem* fs; 110 char buf[512]; 111 112 fs = swap_open (geom); 113 if (!fs) 114 return 1; 115 116 memset (buf, 0, 512); 117 if (!ped_geometry_write (geom, buf, getpagesize() / 512 - 1, 1)) 118 goto error_close_fs; 119 120 swap_close (fs); 121 return 1; 122 123 error_close_fs: 124 swap_close (fs); 125 126 return 0; 127 } 128 #endif /* !DISCOVER_ONLY */ 129 130 static void 131 swap_init (PedFileSystem* fs, int fresh) 132 { 133 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 134 135 fs_info->page_sectors = getpagesize () / 512; 136 fs_info->page_count = fs->geom->length / fs_info->page_sectors; 137 fs_info->version = 1; 138 fs_info->max_bad_pages = (getpagesize() 139 - sizeof (SwapNewHeader)) / 4; 140 141 if (fresh) 142 memset (fs_info->header, 0, getpagesize()); 143 else 144 ped_geometry_read (fs->geom, fs_info->header, 145 0, fs_info->page_sectors); 146 } 147 148 static PedFileSystem* 149 swap_alloc (PedGeometry* geom) 150 { 151 PedFileSystem* fs; 152 SwapSpecific* fs_info; 153 154 fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); 155 if (!fs) 156 goto error; 157 158 fs->type_specific = (SwapSpecific*) ped_malloc (sizeof (SwapSpecific)); 159 if (!fs->type_specific) 160 goto error_free_fs; 161 162 fs_info = SWAP_SPECIFIC (fs); 163 fs_info->header = ped_malloc (getpagesize()); 164 if (!fs_info->header) 165 goto error_free_type_specific; 166 167 fs_info = SWAP_SPECIFIC (fs); 168 fs_info->buffer_size = getpagesize() * BUFFER_SIZE; 169 fs_info->buffer = ped_malloc (fs_info->buffer_size); 170 if (!fs_info->buffer) 171 goto error_free_header; 172 173 fs->geom = ped_geometry_duplicate (geom); 174 if (!fs->geom) 175 goto error_free_buffer; 176 fs->type = &swap_type; 177 return fs; 178 179 error_free_buffer: 180 ped_free (fs_info->buffer); 181 error_free_header: 182 ped_free (fs_info->header); 183 error_free_type_specific: 184 ped_free (fs->type_specific); 185 error_free_fs: 186 ped_free (fs); 187 error: 188 return NULL; 189 } 190 191 static void 192 swap_free (PedFileSystem* fs) 193 { 194 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 195 196 ped_free (fs_info->buffer); 197 ped_free (fs_info->header); 198 ped_free (fs->type_specific); 199 200 ped_geometry_destroy (fs->geom); 201 ped_free (fs); 202 } 203 204 static PedFileSystem* 205 swap_open (PedGeometry* geom) 206 { 207 PedFileSystem* fs; 208 SwapSpecific* fs_info; 209 const char* sig; 210 211 fs = swap_alloc (geom); 212 if (!fs) 213 goto error; 214 swap_init (fs, 0); 215 216 fs_info = SWAP_SPECIFIC (fs); 217 if (!ped_geometry_read (fs->geom, fs_info->header, 0, 218 fs_info->page_sectors)) 219 goto error_free_fs; 220 221 sig = ((char*) fs_info->header) + getpagesize() - 10; 222 if (strncmp (sig, "SWAP-SPACE", 10) == 0) { 223 fs_info->version = 0; 224 fs_info->page_count 225 = PED_MIN (fs->geom->length / fs_info->page_sectors, 226 8 * (getpagesize() - 10)); 227 } else if (strncmp (sig, "SWAPSPACE2", 10) == 0) { 228 fs_info->version = 1; 229 fs_info->page_count = fs_info->header->new.last_page; 230 } else if (strncmp (sig, "S1SUSPEND", 9) == 0) { 231 fs_info->version = -1; 232 } else { 233 char _sig [11]; 234 235 memcpy (_sig, sig, 10); 236 _sig [10] = 0; 237 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 238 _("Unrecognised linux swap signature '%10s'."), _sig); 239 goto error_free_fs; 240 } 241 242 fs->checked = 1; 243 return fs; 244 245 error_free_fs: 246 swap_free (fs); 247 error: 248 return NULL; 249 } 250 251 static int 252 swap_close (PedFileSystem* fs) 253 { 254 swap_free (fs); 255 return 1; 256 } 257 258 #ifndef DISCOVER_ONLY 259 static int 260 swap_new_find_bad_page (PedFileSystem* fs, unsigned int page) 261 { 262 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 263 unsigned int i; 264 265 for (i=0; i < fs_info->header->new.nr_badpages; i++) { 266 if (fs_info->header->new.badpages [i] == page) 267 return i; 268 } 269 270 return 0; 271 } 272 273 static int 274 swap_new_remove_bad_page (PedFileSystem* fs, unsigned int page) 275 { 276 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 277 unsigned int pos; 278 279 pos = swap_new_find_bad_page (fs, page); 280 if (!pos) 281 return 0; 282 283 for (; pos < fs_info->header->new.nr_badpages; pos++) { 284 fs_info->header->new.badpages [pos - 1] 285 = fs_info->header->new.badpages [pos]; 286 } 287 288 return 1; 289 } 290 291 static int 292 swap_mark_page (PedFileSystem* fs, unsigned int page, int ok) 293 { 294 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 295 char* ptr; 296 unsigned int mask; 297 298 if (fs_info->version == 0) { 299 ptr = &fs_info->header->old.page_map [page/8]; 300 mask = 1 << (page%8); 301 *ptr = (*ptr & ~mask) + ok * mask; 302 } else { 303 if (ok) { 304 if (swap_new_remove_bad_page (fs, page)) 305 fs_info->header->new.nr_badpages--; 306 } else { 307 if (swap_new_find_bad_page (fs, page)) 308 return 1; 309 310 if (fs_info->header->new.nr_badpages 311 > fs_info->max_bad_pages) { 312 ped_exception_throw (PED_EXCEPTION_ERROR, 313 PED_EXCEPTION_CANCEL, 314 _("Too many bad pages.")); 315 return 0; 316 } 317 318 fs_info->header->new.badpages 319 [fs_info->header->new.nr_badpages] = page; 320 fs_info->header->new.nr_badpages++; 321 } 322 } 323 324 return 1; 325 } 326 327 static void 328 swap_clear_pages (PedFileSystem* fs) 329 { 330 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 331 unsigned int i; 332 333 for (i = 1; i < fs_info->page_count; i++) { 334 swap_mark_page (fs, i, 1); 335 } 336 337 if (fs_info->version == 0) { 338 for (; i < 1024; i++) { 339 swap_mark_page (fs, i, 0); 340 } 341 } 342 } 343 344 static int 345 swap_check_pages (PedFileSystem* fs, PedTimer* timer) 346 { 347 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 348 PedSector result; 349 int first_page = 1; 350 int stop_page = 0; 351 int last_page = fs_info->page_count - 1; 352 PedTimer* nested_timer; 353 354 ped_timer_reset (timer); 355 ped_timer_set_state_name (timer, _("checking for bad blocks")); 356 357 swap_clear_pages (fs); 358 while (first_page <= last_page) { 359 nested_timer = ped_timer_new_nested ( 360 timer, 361 1.0 * (last_page - first_page) / last_page); 362 result = ped_geometry_check ( 363 fs->geom, 364 fs_info->buffer, 365 fs_info->buffer_size / 512, 366 first_page * fs_info->page_sectors, 367 fs_info->page_sectors, 368 (last_page - first_page + 1) 369 * fs_info->page_sectors, 370 nested_timer); 371 ped_timer_destroy_nested (nested_timer); 372 if (!result) 373 return 1; 374 stop_page = result / fs_info->page_sectors; 375 if (!swap_mark_page (fs, stop_page, 0)) 376 return 0; 377 first_page = stop_page + 1; 378 } 379 return 1; 380 } 381 382 static int 383 swap_write (PedFileSystem* fs) 384 { 385 SwapSpecific* fs_info = SWAP_SPECIFIC (fs); 386 char* sig = ((char*) fs_info->header) + getpagesize() - 10; 387 388 if (fs_info->version == 0) { 389 memcpy (sig, "SWAP-SPACE", 10); 390 } else { 391 fs_info->header->new.version = 1; 392 fs_info->header->new.last_page = fs_info->page_count - 1; 393 fs_info->header->new.nr_badpages = 0; 394 memcpy (sig, "SWAPSPACE2", 10); 395 } 396 397 return ped_geometry_write (fs->geom, fs_info->header, 0, 398 fs_info->page_sectors); 399 } 400 401 static PedFileSystem* 402 swap_create (PedGeometry* geom, PedTimer* timer) 403 { 404 PedFileSystem* fs; 405 406 fs = swap_alloc (geom); 407 if (!fs) 408 goto error; 409 swap_init (fs, 1); 410 if (!swap_write (fs)) 411 goto error_free_fs; 412 return fs; 413 414 error_free_fs: 415 swap_free (fs); 416 error: 417 return NULL; 418 } 419 420 static int 421 swap_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) 422 { 423 PedGeometry* old_geom = fs->geom; 424 425 fs->geom = ped_geometry_duplicate (geom); 426 swap_init (fs, old_geom->start != geom->start); 427 if (!swap_write (fs)) 428 goto error; 429 ped_geometry_destroy (old_geom); 430 return 1; 431 432 error: 433 ped_geometry_destroy (fs->geom); 434 fs->geom = old_geom; 435 return 0; 436 } 437 438 static PedFileSystem* 439 swap_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) 440 { 441 return ped_file_system_create (geom, &swap_type, timer); 442 } 443 444 static int 445 swap_check (PedFileSystem* fs, PedTimer* timer) 446 { 447 return swap_check_pages (fs, timer) 448 && swap_write (fs); 449 } 450 451 static PedConstraint* 452 swap_get_create_constraint (const PedDevice* dev) 453 { 454 PedGeometry full_dev; 455 456 if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1)) 457 return NULL; 458 459 return ped_constraint_new (ped_alignment_any, ped_alignment_any, 460 &full_dev, &full_dev, 461 getpagesize() / 512, dev->length); 462 } 463 464 static PedConstraint* 465 swap_get_resize_constraint (const PedFileSystem* fs) 466 { 467 return swap_get_create_constraint (fs->geom->dev); 468 } 469 470 static PedConstraint* 471 swap_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev) 472 { 473 return swap_get_create_constraint (dev); 474 } 475 #endif /* !DISCOVER_ONLY */ 476 477 static PedFileSystemOps swap_ops = { 478 .probe = swap_probe, 479 #ifndef DISCOVER_ONLY 480 .clobber = swap_clobber, 481 .open = swap_open, 482 .create = swap_create, 483 .close = swap_close, 484 .check = swap_check, 485 .copy = swap_copy, 486 .resize = swap_resize, 487 .get_create_constraint = swap_get_create_constraint, 488 .get_resize_constraint = swap_get_resize_constraint, 489 .get_copy_constraint = swap_get_copy_constraint 490 #else 491 .clobber = NULL, 492 .open = NULL, 493 .create = NULL, 494 .close = NULL, 495 .check = NULL, 496 .copy = NULL, 497 .resize = NULL, 498 .get_create_constraint = NULL, 499 .get_resize_constraint = NULL, 500 .get_copy_constraint = NULL 501 #endif /* !DISCOVER_ONLY */ 502 }; 503 504 static PedFileSystemType swap_type = { 505 .next = NULL, 506 .ops = &swap_ops, 507 .name = "linux-swap", 508 .block_sizes = LINUXSWAP_BLOCK_SIZES 509 }; 510 511 void 512 ped_file_system_linux_swap_init () 513 { 514 ped_file_system_type_register (&swap_type); 515 } 516 517 void 518 ped_file_system_linux_swap_done () 519 { 520 ped_file_system_type_unregister (&swap_type); 521 } 522