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*
swap_probe(PedGeometry * geom)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
swap_clobber(PedGeometry * geom)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
swap_init(PedFileSystem * fs,int fresh)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*
swap_alloc(PedGeometry * geom)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
swap_free(PedFileSystem * fs)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*
swap_open(PedGeometry * geom)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
swap_close(PedFileSystem * fs)252 swap_close (PedFileSystem* fs)
253 {
254 swap_free (fs);
255 return 1;
256 }
257
258 #ifndef DISCOVER_ONLY
259 static int
swap_new_find_bad_page(PedFileSystem * fs,unsigned int page)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
swap_new_remove_bad_page(PedFileSystem * fs,unsigned int page)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
swap_mark_page(PedFileSystem * fs,unsigned int page,int ok)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
swap_clear_pages(PedFileSystem * fs)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
swap_check_pages(PedFileSystem * fs,PedTimer * timer)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
swap_write(PedFileSystem * fs)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*
swap_create(PedGeometry * geom,PedTimer * timer)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
swap_resize(PedFileSystem * fs,PedGeometry * geom,PedTimer * timer)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*
swap_copy(const PedFileSystem * fs,PedGeometry * geom,PedTimer * timer)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
swap_check(PedFileSystem * fs,PedTimer * timer)445 swap_check (PedFileSystem* fs, PedTimer* timer)
446 {
447 return swap_check_pages (fs, timer)
448 && swap_write (fs);
449 }
450
451 static PedConstraint*
swap_get_create_constraint(const PedDevice * dev)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*
swap_get_resize_constraint(const PedFileSystem * fs)465 swap_get_resize_constraint (const PedFileSystem* fs)
466 {
467 return swap_get_create_constraint (fs->geom->dev);
468 }
469
470 static PedConstraint*
swap_get_copy_constraint(const PedFileSystem * fs,const PedDevice * dev)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
ped_file_system_linux_swap_init()512 ped_file_system_linux_swap_init ()
513 {
514 ped_file_system_type_register (&swap_type);
515 }
516
517 void
ped_file_system_linux_swap_done()518 ped_file_system_linux_swap_done ()
519 {
520 ped_file_system_type_unregister (&swap_type);
521 }
522
523