mkswap.c 11 KB

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