aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mkswap.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux/mkswap.c')
-rw-r--r--util-linux/mkswap.c152
1 files changed, 73 insertions, 79 deletions
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c
index 4107329a6..ce123e502 100644
--- a/util-linux/mkswap.c
+++ b/util-linux/mkswap.c
@@ -59,9 +59,17 @@ static int DEV = -1;
59static long PAGES = 0; 59static long PAGES = 0;
60static int check = 0; 60static int check = 0;
61static int badpages = 0; 61static int badpages = 0;
62#if ENABLE_FEATURE_MKSWAP_V0
62static int version = -1; 63static int version = -1;
63
64#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) 64#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
65#else
66#define version 1
67/* and make sure that we optimize away anything which would deal with checking
68 * the kernel revision as we have v1 support only anyway.
69 */
70#define MAKE_VERSION(p,q,r) 1
71#define get_kernel_revision() 1
72#endif
65 73
66/* 74/*
67 * The definition of the union swap_header uses the constant PAGE_SIZE. 75 * The definition of the union swap_header uses the constant PAGE_SIZE.
@@ -74,7 +82,7 @@ static unsigned int *signature_page;
74 82
75static struct swap_header_v1 { 83static struct swap_header_v1 {
76 char bootbits[1024]; /* Space for disklabel etc. */ 84 char bootbits[1024]; /* Space for disklabel etc. */
77 unsigned int version; 85 unsigned int swap_version;
78 unsigned int last_page; 86 unsigned int last_page;
79 unsigned int nr_badpages; 87 unsigned int nr_badpages;
80 unsigned int padding[125]; 88 unsigned int padding[125];
@@ -172,23 +180,11 @@ static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
172 return (r & m) != 0; 180 return (r & m) != 0;
173} 181}
174 182
175
176static void page_ok(int page) 183static void page_ok(int page)
177{ 184{
178 if (version == 0) 185 if (ENABLE_FEATURE_MKSWAP_V0) {
179 bit_set(signature_page, page); 186 bit_set(signature_page, page);
180}
181
182static inline void page_bad(int page)
183{
184 if (version == 0)
185 bit_test_and_clear(signature_page, page);
186 else {
187 if (badpages == MAX_BADPAGES)
188 bb_error_msg_and_die("too many bad pages");
189 p->badpages[badpages] = page;
190 } 187 }
191 badpages++;
192} 188}
193 189
194static void check_blocks(void) 190static void check_blocks(void)
@@ -200,7 +196,7 @@ static void check_blocks(void)
200 buffer = xmalloc(pagesize); 196 buffer = xmalloc(pagesize);
201 current_page = 0; 197 current_page = 0;
202 while (current_page < PAGES) { 198 while (current_page < PAGES) {
203 if (!check) { 199 if (!check && version == 0) {
204 page_ok(current_page++); 200 page_ok(current_page++);
205 continue; 201 continue;
206 } 202 }
@@ -208,15 +204,23 @@ static void check_blocks(void)
208 current_page * pagesize) 204 current_page * pagesize)
209 bb_error_msg_and_die("seek failed in check_blocks"); 205 bb_error_msg_and_die("seek failed in check_blocks");
210 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { 206 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
211 page_bad(current_page++); 207 current_page++;
208 if (version == 0)
209 bit_test_and_clear(signature_page, current_page);
210 else {
211 if (badpages == MAX_BADPAGES)
212 bb_error_msg_and_die("too many bad pages");
213 p->badpages[badpages] = current_page;
214 }
215 badpages++;
212 continue; 216 continue;
213 } 217 }
214 page_ok(current_page++); 218 page_ok(current_page++);
215 } 219 }
216 if (badpages == 1) 220 if (ENABLE_FEATURE_CLEAN_UP)
217 printf("one bad page\n"); 221 free(buffer);
218 else if (badpages > 1) 222 if (badpages > 0)
219 printf("%d bad pages\n", badpages); 223 printf("%d bad page%s\n", badpages, (badpages==1)?"":"s");
220} 224}
221 225
222static long valid_offset(int fd, int offset) 226static long valid_offset(int fd, int offset)
@@ -249,17 +253,15 @@ static int find_size(int fd)
249} 253}
250 254
251/* return size in pages, to avoid integer overflow */ 255/* return size in pages, to avoid integer overflow */
252static long get_size(const char *file) 256static inline long get_size(const char *file)
253{ 257{
254 int fd; 258 int fd;
255 long size; 259 long size;
256 260
257 if ((fd = open(file, O_RDONLY)) < 0) 261 if ((fd = open(file, O_RDONLY)) < 0) /* TODO: bb_xopen3 */
258 bb_perror_msg_and_die("%s", file); 262 bb_perror_msg_and_die("%s", file);
259 if (ioctl(fd, BLKGETSIZE, &size) >= 0) { 263 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
260 int sectors_per_page = pagesize / 512; 264 size /= pagesize / 512;
261
262 size /= sectors_per_page;
263 } else { 265 } else {
264 size = find_size(fd) / pagesize; 266 size = find_size(fd) / pagesize;
265 } 267 }
@@ -274,66 +276,53 @@ int mkswap_main(int argc, char **argv)
274 int sz; 276 int sz;
275 int maxpages; 277 int maxpages;
276 int goodpages; 278 int goodpages;
277 int offset; 279#ifdef __sparc__
278 int force = 0; 280 int force = 0;
281#endif
279 282
280 init_signature_page(); /* get pagesize */ 283 init_signature_page(); /* get pagesize */
281 284
282 while (argc-- > 1) { 285 bb_opt_complementally = "?"; /* call bb_show_usage internally */
283 argv++; 286 sz = bb_getopt_ulflags(argc, argv, "+cfv:", &tmp);
284 if (argv[0][0] != '-') { 287 if (sz & 1)
285 if (device_name) { 288 check = 1;
286 int blocks_per_page = pagesize / 1024; 289#ifdef __sparc__
287 290 if (sz & 2)
288 PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page; 291 force = 1;
289 if (*tmp) 292#endif
290 bb_show_usage(); 293#if ENABLE_FEATURE_MKSWAP_V0
291 } else 294 if (sz & 4) {
292 device_name = argv[0]; 295 version = bb_xgetlarg(tmp, 10, 0, 1);
296 } else {
297 if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
298 version = 0;
299 else
300 version = 1;
301 }
302#endif
303
304 argv += optind;
305 argc -= optind;
306
307 goodpages = pagesize / 1024; /* cache division */
308 while (argc--) {
309 if (device_name) {
310 PAGES = bb_xgetlarg(argv[0], 0, 10, sz * goodpages) / goodpages;
311 argc = 0; /* ignore any surplus args.. */
293 } else { 312 } else {
294 switch (argv[0][1]) { 313 device_name = argv[0];
295 case 'c': 314 sz = get_size(device_name);
296 check = 1; 315 argv++;
297 break;
298 case 'f':
299 force = 1;
300 break;
301 case 'v':
302 version = atoi(argv[0] + 2);
303 break;
304 default:
305 bb_show_usage();
306 }
307 } 316 }
308 } 317 }
318
309 if (!device_name) { 319 if (!device_name) {
310 bb_error_msg("error: Nowhere to set up swap on?"); 320 bb_error_msg_and_die("error: Nowhere to set up swap on?");
311 bb_show_usage();
312 } 321 }
313 sz = get_size(device_name);
314 if (!PAGES) { 322 if (!PAGES) {
315 PAGES = sz; 323 PAGES = sz;
316 } else if (PAGES > sz && !force) {
317 bb_error_msg("error: size %ld is larger than device size %d",
318 PAGES * (pagesize / 1024), sz * (pagesize / 1024));
319 return EXIT_FAILURE;
320 } 324 }
321 325
322 if (version == -1) {
323 if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
324 version = 0;
325 else
326 version = 1;
327 }
328 if (version != 0 && version != 1) {
329 bb_error_msg("error: unknown version %d", version);
330 bb_show_usage();
331 }
332 if (PAGES < 10) {
333 bb_error_msg("error: swap area needs to be at least %ldkB",
334 (long) (10 * pagesize / 1024));
335 bb_show_usage();
336 }
337#if 0 326#if 0
338 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); 327 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
339#else 328#else
@@ -350,7 +339,7 @@ int mkswap_main(int argc, char **argv)
350 if (PAGES > maxpages) { 339 if (PAGES > maxpages) {
351 PAGES = maxpages; 340 PAGES = maxpages;
352 bb_error_msg("warning: truncating swap area to %ldkB", 341 bb_error_msg("warning: truncating swap area to %ldkB",
353 PAGES * pagesize / 1024); 342 PAGES * goodpages);
354 } 343 }
355 344
356 DEV = open(device_name, O_RDWR); 345 DEV = open(device_name, O_RDWR);
@@ -389,7 +378,7 @@ int mkswap_main(int argc, char **argv)
389 if (version == 0 && !bit_test_and_clear(signature_page, 0)) 378 if (version == 0 && !bit_test_and_clear(signature_page, 0))
390 bb_error_msg_and_die("fatal: first page unreadable"); 379 bb_error_msg_and_die("fatal: first page unreadable");
391 if (version == 1) { 380 if (version == 1) {
392 p->version = version; 381 p->swap_version = version;
393 p->last_page = PAGES - 1; 382 p->last_page = PAGES - 1;
394 p->nr_badpages = badpages; 383 p->nr_badpages = badpages;
395 } 384 }
@@ -401,11 +390,12 @@ int mkswap_main(int argc, char **argv)
401 version, (long) (goodpages * pagesize)); 390 version, (long) (goodpages * pagesize));
402 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); 391 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
403 392
404 offset = ((version == 0) ? 0 : 1024); 393 sz = ((version == 0) ? 0 : 1024); /* offset */
405 if (lseek(DEV, offset, SEEK_SET) != offset) 394 if (lseek(DEV, sz, SEEK_SET) != sz)
406 bb_error_msg_and_die("unable to rewind swap-device"); 395 bb_error_msg_and_die("unable to rewind swap-device");
407 if (write(DEV, (char *) signature_page + offset, pagesize - offset) 396 goodpages = pagesize - sz; /* cache substraction */
408 != pagesize - offset) 397 if (write(DEV, (char *) signature_page + sz, goodpages)
398 != goodpages)
409 bb_error_msg_and_die("unable to write signature page"); 399 bb_error_msg_and_die("unable to write signature page");
410 400
411 /* 401 /*
@@ -414,5 +404,9 @@ int mkswap_main(int argc, char **argv)
414 */ 404 */
415 if (fsync(DEV)) 405 if (fsync(DEV))
416 bb_error_msg_and_die("fsync failed"); 406 bb_error_msg_and_die("fsync failed");
407 if (ENABLE_FEATURE_CLEAN_UP) {
408 close(DEV);
409 free(signature_page);
410 }
417 return EXIT_SUCCESS; 411 return EXIT_SUCCESS;
418} 412}