Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/util-linux/mkswap.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/util-linux/mkswap.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 /* 3 * mkswap.c - set up a linux swap device 2 /* mkswap.c - format swap device (Linux v1 only) 4 3 * 5 * (C) 1991 Linus Torvalds. This file may be redistributed as per 6 * the Linux copyright. 4 * Copyright 2006 Rob Landley <rob@landley.net> 5 * 6 * Licensed under GPL version 2, see file LICENSE in this tarball for details. 7 7 */ 8 8 9 /* 10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand. 11 * 12 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks] 13 * 14 * -c for readability checking. (Use it unless you are SURE!) 15 * -vN for swap areas version N. (Only N=0,1 known today.) 16 * -f for forcing swap creation even if it would smash partition table. 17 * 18 * The device may be a block device or an image of one, but this isn't 19 * enforced (but it's not much fun on a character device :-). 20 * 21 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the 22 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. 23 * 24 * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. 25 * 26 * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. 27 * V1_MAX_PAGES fixes, jj, 990325. 28 * 29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> 30 * - added Native Language Support 31 * 32 * from util-linux -- adapted for busybox by 33 * Erik Andersen <andersen@codepoet.org>. I ripped out Native Language 34 * Support, made some stuff smaller, and fitted for life in busybox. 35 * 36 */ 9 #include "libbb.h" 37 10 38 #include "busybox.h" 39 #include <unistd.h> 40 #include <string.h> 41 #include <fcntl.h> 42 #include <sys/ioctl.h> /* for _IO */ 43 #include <sys/utsname.h> 44 #include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */ 45 /* we also get PAGE_SIZE via getpagesize() */ 46 47 static char *device_name = NULL; 48 static int DEV = -1; 49 static long PAGES = 0; 50 static int check = 0; 51 static int badpages = 0; 52 #if ENABLE_FEATURE_MKSWAP_V0 53 static int version = -1; 54 #else 55 #define version 1 56 /* and make sure that we optimize away anything which would deal with checking 57 * the kernel revision as we have v1 support only anyway. 58 */ 59 #undef KERNEL_VERSION 60 #define KERNEL_VERSION(p,q,r) 1 61 #define get_linux_version_code() 1 62 #endif 63 64 /* 65 * The definition of the union swap_header uses the constant PAGE_SIZE. 66 * Unfortunately, on some architectures this depends on the hardware model, 67 * and can only be found at run time -- we use getpagesize(). 68 */ 69 70 static int pagesize; 71 static unsigned int *signature_page; 72 73 static struct swap_header_v1 { 74 char bootbits[1024]; /* Space for disklabel etc. */ 75 unsigned int swap_version; 76 unsigned int last_page; 77 unsigned int nr_badpages; 78 unsigned int padding[125]; 79 unsigned int badpages[1]; 80 } *p; 81 82 static inline void init_signature_page(void) 83 { 84 pagesize = getpagesize(); 85 86 #ifdef PAGE_SIZE 87 if (pagesize != PAGE_SIZE) 88 bb_error_msg("Assuming pages of size %d", pagesize); 89 #endif 90 signature_page = (unsigned int *) xmalloc(pagesize); 91 memset(signature_page, 0, pagesize); 92 p = (struct swap_header_v1 *) signature_page; 93 } 94 95 static inline void write_signature(char *sig) 96 { 97 char *sp = (char *) signature_page; 98 99 strncpy(sp + pagesize - 10, sig, 10); 100 } 101 102 #define V0_MAX_PAGES (8 * (pagesize - 10)) 103 /* Before 2.2.0pre9 */ 104 #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1) 105 /* Since 2.2.0pre9: 106 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL)) 107 with variations on 108 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) 109 #define SWP_OFFSET(entry) ((entry) >> 8) 110 on the various architectures. Below the result - yuk. 111 112 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2 113 i386 2^12 o<<8 e>>8 1<<24 1<<19 114 mips 2^12 o<<15 e>>15 1<<17 1<<19 115 alpha 2^13 o<<40 e>>40 1<<24 1<<18 116 m68k 2^12 o<<12 e>>12 1<<20 1<<19 117 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18} 118 sparc64 2^13 o<<13 e>>13 1<<51 1<<18 119 ppc 2^12 o<<8 e>>8 1<<24 1<<19 120 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16} 121 armv 2^12 o<<9 e>>9 1<<23 1<<19 122 123 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere. 124 125 The bad part is that we need to know this since the kernel will 126 refuse a swap space if it is too large. 127 */ 128 /* patch from jj - why does this differ from the above? */ 129 #if defined(__alpha__) 130 #define V1_MAX_PAGES ((1 << 24) - 1) 131 #elif defined(__mips__) 132 #define V1_MAX_PAGES ((1 << 17) - 1) 133 #elif defined(__sparc_v9__) 134 #define V1_MAX_PAGES ((3 << 29) - 1) 135 #elif defined(__sparc__) 136 #define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1)) 137 #else 138 #define V1_MAX_PAGES V1_OLD_MAX_PAGES 139 #endif 140 /* man page now says: 141 The maximum useful size of a swap area now depends on the architecture. 142 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, 143 128GB on alpha and 3TB on sparc64. 144 */ 145 146 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) 147 148 static inline void bit_set(unsigned int *addr, unsigned int nr) 149 { 150 unsigned int r, m; 151 152 addr += nr / (8 * sizeof(int)); 153 154 r = *addr; 155 m = 1 << (nr & (8 * sizeof(int) - 1)); 156 157 *addr = r | m; 158 } 159 160 static int bit_test_and_clear(unsigned int *addr, unsigned int nr) 161 { 162 unsigned int r, m; 163 164 addr += nr / (8 * sizeof(int)); 165 166 r = *addr; 167 m = 1 << (nr & (8 * sizeof(int) - 1)); 168 169 *addr = r & ~m; 170 return (r & m) != 0; 171 } 172 173 static void page_ok(int page) 174 { 175 if (ENABLE_FEATURE_MKSWAP_V0) { 176 bit_set(signature_page, page); 177 } 178 } 179 180 static void check_blocks(void) 181 { 182 unsigned int current_page; 183 int do_seek = 1; 184 char *buffer; 185 186 buffer = xmalloc(pagesize); 187 current_page = 0; 188 while (current_page < PAGES) { 189 if (!check && version == 0) { 190 page_ok(current_page++); 191 continue; 192 } 193 if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) != 194 current_page * pagesize) 195 bb_error_msg_and_die("seek failed in check_blocks"); 196 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { 197 current_page++; 198 if (version == 0) 199 bit_test_and_clear(signature_page, current_page); 200 else { 201 if (badpages == MAX_BADPAGES) 202 bb_error_msg_and_die("too many bad pages"); 203 p->badpages[badpages] = current_page; 204 } 205 badpages++; 206 continue; 207 } 208 page_ok(current_page++); 209 } 210 if (ENABLE_FEATURE_CLEAN_UP) 211 free(buffer); 212 if (badpages > 0) 213 printf("%d bad page%s\n", badpages, (badpages==1)?"":"s"); 214 } 215 216 static long valid_offset(int fd, int offset) 217 { 218 char ch; 219 220 if (lseek(fd, offset, 0) < 0) 221 return 0; 222 if (read(fd, &ch, 1) < 1) 223 return 0; 224 return 1; 225 } 226 227 static int find_size(int fd) 228 { 229 unsigned int high, low; 230 231 low = 0; 232 for (high = 1; high > 0 && valid_offset(fd, high); high *= 2) 233 low = high; 234 while (low < high - 1) { 235 const int mid = (low + high) / 2; 236 237 if (valid_offset(fd, mid)) 238 low = mid; 239 else 240 high = mid; 241 } 242 return (low + 1); 243 } 244 245 /* return size in pages, to avoid integer overflow */ 246 static inline long get_size(const char *file) 247 { 248 int fd; 249 long size; 250 251 fd = bb_xopen3(file, O_RDONLY, 0); 252 if (ioctl(fd, BLKGETSIZE, &size) >= 0) { 253 size /= pagesize / 512; 254 } else { 255 size = find_size(fd) / pagesize; 256 } 257 close(fd); 258 return size; 259 } 260 11 int mkswap_main(int argc, char **argv); 261 12 int mkswap_main(int argc, char **argv) 262 13 { 263 char *tmp; 264 struct stat statbuf; 265 int sz; 266 int maxpages; 267 int goodpages; 268 #ifdef __sparc__ 269 int force = 0; 270 #endif 14 int fd, pagesize; 15 off_t len; 16 unsigned int hdr[129]; 271 17 272 init_signature_page(); /* get pagesize */18 // No options supported. 273 19 274 bb_opt_complementally = "?"; /* call bb_show_usage internally */ 275 sz = bb_getopt_ulflags(argc, argv, "+cfv:", &tmp); 276 if (sz & 1) 277 check = 1; 278 #ifdef __sparc__ 279 if (sz & 2) 280 force = 1; 281 #endif 282 #if ENABLE_FEATURE_MKSWAP_V0 283 if (sz & 4) { 284 version = bb_xgetlarg(tmp, 10, 0, 1); 285 } else { 286 if (get_linux_version_code() < KERNEL_VERSION(2, 1, 117)) 287 version = 0; 288 else 289 version = 1; 290 } 291 #endif 20 if (argc != 2) bb_show_usage(); 292 21 293 argv += optind; 294 argc -= optind; 22 // Figure out how big the device is and announce our intentions. 295 23 296 goodpages = pagesize / 1024; /* cache division */ 297 while (argc--) { 298 if (device_name) { 299 PAGES = bb_xgetlarg(argv[0], 0, 10, sz * goodpages) / goodpages; 300 argc = 0; /* ignore any surplus args.. */ 301 } else { 302 device_name = argv[0]; 303 sz = get_size(device_name); 304 argv++; 305 } 306 } 24 fd = xopen(argv[1], O_RDWR); 25 len = fdlength(fd); 26 pagesize = getpagesize(); 27 printf("Setting up swapspace version 1, size = %"OFF_FMT"d bytes\n", 28 len - pagesize); 307 29 308 if (!device_name) { 309 bb_error_msg_and_die("error: Nowhere to set up swap on?"); 310 } 311 if (!PAGES) { 312 PAGES = sz; 313 } 30 // Make a header. 314 31 315 #if 0 316 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); 317 #else 318 if (!version) 319 maxpages = V0_MAX_PAGES; 320 else if (get_linux_version_code() >= KERNEL_VERSION(2,2,1)) 321 maxpages = V1_MAX_PAGES; 322 else { 323 maxpages = V1_OLD_MAX_PAGES; 324 if (maxpages > V1_MAX_PAGES) 325 maxpages = V1_MAX_PAGES; 326 } 327 #endif 328 if (PAGES > maxpages) { 329 PAGES = maxpages; 330 bb_error_msg("warning: truncating swap area to %ldkB", 331 PAGES * goodpages); 332 } 32 memset(hdr, 0, sizeof(hdr)); 33 hdr[0] = 1; 34 hdr[1] = (len / pagesize) - 1; 333 35 334 DEV = bb_xopen3(device_name, O_RDWR, 0); 335 if (fstat(DEV, &statbuf) < 0) 336 bb_perror_msg_and_die("%s", device_name); 337 if (!S_ISBLK(statbuf.st_mode)) 338 check = 0; 339 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) 340 bb_error_msg_and_die("Will not try to make swapdevice on '%s'", device_name); 36 // Write the header. Sync to disk because some kernel versions check 37 // signature on disk (not in cache) during swapon. 341 38 342 #ifdef __sparc__ 343 if (!force && version == 0) {344 /* Don't overwrite partition table unless forced */345 unsigned char *buffer = (unsigned char *) signature_page;346 unsigned short *q, sum;39 xlseek(fd, 1024, SEEK_SET); 40 xwrite(fd, hdr, sizeof(hdr)); 41 xlseek(fd, pagesize-10, SEEK_SET); 42 xwrite(fd, "SWAPSPACE2", 10); 43 fsync(fd); 347 44 348 if (read(DEV, buffer, 512) != 512) 349 bb_error_msg_and_die("fatal: first page unreadable"); 350 if (buffer[508] == 0xDA && buffer[509] == 0xBE) { 351 q = (unsigned short *) (buffer + 510); 352 for (sum = 0; q >= (unsigned short *) buffer;) 353 sum ^= *q--; 354 if (!sum) { 355 bb_error_msg("Device '%s' contains a valid Sun disklabel.\n" 356 "This probably means creating v0 swap would destroy your partition table\n" 357 "No swap created. If you really want to create swap v0 on that device, use\n" 358 "the -f option to force it.", device_name); 359 return EXIT_FAILURE; 360 } 361 } 362 } 363 #endif 45 if (ENABLE_FEATURE_CLEAN_UP) close(fd); 364 46 365 if (version == 0 || check) 366 check_blocks(); 367 if (version == 0 && !bit_test_and_clear(signature_page, 0)) 368 bb_error_msg_and_die("fatal: first page unreadable"); 369 if (version == 1) { 370 p->swap_version = version; 371 p->last_page = PAGES - 1; 372 p->nr_badpages = badpages; 373 } 374 375 goodpages = PAGES - badpages - 1; 376 if (goodpages <= 0) 377 bb_error_msg_and_die("Unable to set up swap-space: unreadable"); 378 printf("Setting up swapspace version %d, size = %ld bytes\n", 379 version, (long) (goodpages * pagesize)); 380 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); 381 382 sz = ((version == 0) ? 0 : 1024); /* offset */ 383 if (lseek(DEV, sz, SEEK_SET) != sz) 384 bb_error_msg_and_die("unable to rewind swap-device"); 385 goodpages = pagesize - sz; /* cache substraction */ 386 if (write(DEV, (char *) signature_page + sz, goodpages) 387 != goodpages) 388 bb_error_msg_and_die("unable to write signature page"); 389 390 /* 391 * A subsequent swapon() will fail if the signature 392 * is not actually on disk. (This is a kernel bug.) 393 */ 394 if (fsync(DEV)) 395 bb_error_msg_and_die("fsync failed"); 396 if (ENABLE_FEATURE_CLEAN_UP) { 397 close(DEV); 398 free(signature_page); 399 } 400 return EXIT_SUCCESS; 47 return 0; 401 48 }
Note:
See TracChangeset
for help on using the changeset viewer.