mkswap.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * mkswap.c - format swap device (Linux v1 only)
  4. *
  5. * Copyright 2006 Rob Landley <rob@landley.net>
  6. *
  7. * Licensed under GPLv2, see file LICENSE in this source tree.
  8. */
  9. //config:config MKSWAP
  10. //config: bool "mkswap (5.8 kb)"
  11. //config: default y
  12. //config: help
  13. //config: The mkswap utility is used to configure a file or disk partition as
  14. //config: Linux swap space. This allows Linux to use the entire file or
  15. //config: partition as if it were additional RAM, which can greatly increase
  16. //config: the capability of low-memory machines. This additional memory is
  17. //config: much slower than real RAM, but can be very helpful at preventing your
  18. //config: applications being killed by the Linux out of memory (OOM) killer.
  19. //config: Once you have created swap space using 'mkswap' you need to enable
  20. //config: the swap space using the 'swapon' utility.
  21. //config:
  22. //config:config FEATURE_MKSWAP_UUID
  23. //config: bool "UUID support"
  24. //config: default y
  25. //config: depends on MKSWAP
  26. //config: help
  27. //config: Generate swap spaces with universally unique identifiers.
  28. //applet:IF_MKSWAP(APPLET(mkswap, BB_DIR_SBIN, BB_SUID_DROP))
  29. //kbuild:lib-$(CONFIG_MKSWAP) += mkswap.o
  30. //usage:#define mkswap_trivial_usage
  31. //usage: "[-L LBL] BLOCKDEV [KBYTES]"
  32. //usage:#define mkswap_full_usage "\n\n"
  33. //usage: "Prepare BLOCKDEV to be used as swap partition\n"
  34. //usage: "\n -L LBL Label"
  35. #include "libbb.h"
  36. #include "common_bufsiz.h"
  37. #if ENABLE_SELINUX
  38. static void mkswap_selinux_setcontext(int fd, const char *path)
  39. {
  40. struct stat stbuf;
  41. if (!is_selinux_enabled())
  42. return;
  43. xfstat(fd, &stbuf, path);
  44. if (S_ISREG(stbuf.st_mode)) {
  45. security_context_t newcon;
  46. security_context_t oldcon = NULL;
  47. context_t context;
  48. if (fgetfilecon(fd, &oldcon) < 0) {
  49. if (errno != ENODATA)
  50. goto error;
  51. if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0)
  52. goto error;
  53. }
  54. context = context_new(oldcon);
  55. if (!context || context_type_set(context, "swapfile_t"))
  56. goto error;
  57. newcon = context_str(context);
  58. if (!newcon)
  59. goto error;
  60. /* fsetfilecon_raw is hidden */
  61. if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0)
  62. goto error;
  63. if (ENABLE_FEATURE_CLEAN_UP) {
  64. context_free(context);
  65. freecon(oldcon);
  66. }
  67. }
  68. return;
  69. error:
  70. bb_perror_msg_and_die("SELinux relabeling failed");
  71. }
  72. #else
  73. # define mkswap_selinux_setcontext(fd, path) ((void)0)
  74. #endif
  75. /* from Linux 2.6.23 */
  76. /*
  77. * Magic header for a swap area. ... Note that the first
  78. * kilobyte is reserved for boot loader or disk label stuff.
  79. */
  80. struct swap_header_v1 {
  81. /* char bootbits[1024]; Space for disklabel etc. */
  82. uint32_t version; /* second kbyte, word 0 */
  83. uint32_t last_page; /* 1 */
  84. uint32_t nr_badpages; /* 2 */
  85. char sws_uuid[16]; /* 3,4,5,6 */
  86. char sws_volume[16]; /* 7,8,9,10 */
  87. uint32_t padding[117]; /* 11..127 */
  88. uint32_t badpages[1]; /* 128 */
  89. /* total 129 32-bit words in 2nd kilobyte */
  90. } FIX_ALIASING;
  91. #define NWORDS 129
  92. #define hdr ((struct swap_header_v1*)bb_common_bufsiz1)
  93. #define INIT_G() do { setup_common_bufsiz(); } while (0)
  94. struct BUG_sizes {
  95. char swap_header_v1_wrong[sizeof(*hdr) != (NWORDS * 4) ? -1 : 1];
  96. char bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
  97. };
  98. /* Stored without terminating NUL */
  99. static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2";
  100. int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  101. int mkswap_main(int argc UNUSED_PARAM, char **argv)
  102. {
  103. int fd;
  104. unsigned pagesize;
  105. off_t len;
  106. const char *label = "";
  107. INIT_G();
  108. /* TODO: -p PAGESZ, -U UUID */
  109. getopt32(argv, "^" "L:" "\0" "-1"/*at least one arg*/, &label);
  110. argv += optind;
  111. fd = xopen(argv[0], O_WRONLY);
  112. /* Figure out how big the device is */
  113. len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1);
  114. pagesize = getpagesize();
  115. len -= pagesize;
  116. /* Announce our intentions */
  117. printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n", len);
  118. mkswap_selinux_setcontext(fd, argv[0]);
  119. /* hdr is zero-filled so far. Clear the first kbyte, or else
  120. * mkswap-ing former FAT partition does NOT erase its signature.
  121. *
  122. * util-linux-ng 2.17.2 claims to erase it only if it does not see
  123. * a partition table and is not run on whole disk. -f forces it.
  124. */
  125. xwrite(fd, hdr, 1024);
  126. /* Fill the header. */
  127. hdr->version = 1;
  128. hdr->last_page = (uoff_t)len / pagesize;
  129. if (ENABLE_FEATURE_MKSWAP_UUID) {
  130. char uuid_string[32];
  131. generate_uuid((void*)hdr->sws_uuid);
  132. bin2hex(uuid_string, hdr->sws_uuid, 16);
  133. /* f.e. UUID=dfd9c173-be52-4d27-99a5-c34c6c2ff55f */
  134. printf("UUID=%.8s" "-%.4s-%.4s-%.4s-%.12s\n",
  135. uuid_string,
  136. uuid_string+8,
  137. uuid_string+8+4,
  138. uuid_string+8+4+4,
  139. uuid_string+8+4+4+4
  140. );
  141. }
  142. safe_strncpy(hdr->sws_volume, label, 16);
  143. /* Write the header. Sync to disk because some kernel versions check
  144. * signature on disk (not in cache) during swapon. */
  145. xwrite(fd, hdr, NWORDS * 4);
  146. xlseek(fd, pagesize - 10, SEEK_SET);
  147. xwrite(fd, SWAPSPACE2, 10);
  148. fsync(fd);
  149. if (ENABLE_FEATURE_CLEAN_UP)
  150. close(fd);
  151. return 0;
  152. }