3
0

mkswap.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /* vi: set sw=4 ts=4: */
  2. /* mkswap.c - format swap device (Linux v1 only)
  3. *
  4. * Copyright 2006 Rob Landley <rob@landley.net>
  5. *
  6. * Licensed under GPLv2, see file LICENSE in this source tree.
  7. */
  8. //config:config MKSWAP
  9. //config: bool "mkswap"
  10. //config: default y
  11. //config: help
  12. //config: The mkswap utility is used to configure a file or disk partition as
  13. //config: Linux swap space. This allows Linux to use the entire file or
  14. //config: partition as if it were additional RAM, which can greatly increase
  15. //config: the capability of low-memory machines. This additional memory is
  16. //config: much slower than real RAM, but can be very helpful at preventing your
  17. //config: applications being killed by the Linux out of memory (OOM) killer.
  18. //config: Once you have created swap space using 'mkswap' you need to enable
  19. //config: the swap space using the 'swapon' utility.
  20. //config:
  21. //config:config FEATURE_MKSWAP_UUID
  22. //config: bool "UUID support"
  23. //config: default y
  24. //config: depends on MKSWAP
  25. //config: help
  26. //config: Generate swap spaces with universally unique identifiers.
  27. //applet:IF_MKSWAP(APPLET(mkswap, BB_DIR_SBIN, BB_SUID_DROP))
  28. //kbuild:lib-$(CONFIG_MKSWAP) += mkswap.o
  29. //usage:#define mkswap_trivial_usage
  30. //usage: "[-L LBL] BLOCKDEV [KBYTES]"
  31. //usage:#define mkswap_full_usage "\n\n"
  32. //usage: "Prepare BLOCKDEV to be used as swap partition\n"
  33. //usage: "\n -L LBL Label"
  34. #include "libbb.h"
  35. #include "common_bufsiz.h"
  36. #if ENABLE_SELINUX
  37. static void mkswap_selinux_setcontext(int fd, const char *path)
  38. {
  39. struct stat stbuf;
  40. if (!is_selinux_enabled())
  41. return;
  42. xfstat(fd, &stbuf, path);
  43. if (S_ISREG(stbuf.st_mode)) {
  44. security_context_t newcon;
  45. security_context_t oldcon = NULL;
  46. context_t context;
  47. if (fgetfilecon(fd, &oldcon) < 0) {
  48. if (errno != ENODATA)
  49. goto error;
  50. if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0)
  51. goto error;
  52. }
  53. context = context_new(oldcon);
  54. if (!context || context_type_set(context, "swapfile_t"))
  55. goto error;
  56. newcon = context_str(context);
  57. if (!newcon)
  58. goto error;
  59. /* fsetfilecon_raw is hidden */
  60. if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0)
  61. goto error;
  62. if (ENABLE_FEATURE_CLEAN_UP) {
  63. context_free(context);
  64. freecon(oldcon);
  65. }
  66. }
  67. return;
  68. error:
  69. bb_perror_msg_and_die("SELinux relabeling failed");
  70. }
  71. #else
  72. # define mkswap_selinux_setcontext(fd, path) ((void)0)
  73. #endif
  74. /* from Linux 2.6.23 */
  75. /*
  76. * Magic header for a swap area. ... Note that the first
  77. * kilobyte is reserved for boot loader or disk label stuff.
  78. */
  79. struct swap_header_v1 {
  80. /* char bootbits[1024]; Space for disklabel etc. */
  81. uint32_t version; /* second kbyte, word 0 */
  82. uint32_t last_page; /* 1 */
  83. uint32_t nr_badpages; /* 2 */
  84. char sws_uuid[16]; /* 3,4,5,6 */
  85. char sws_volume[16]; /* 7,8,9,10 */
  86. uint32_t padding[117]; /* 11..127 */
  87. uint32_t badpages[1]; /* 128 */
  88. /* total 129 32-bit words in 2nd kilobyte */
  89. } FIX_ALIASING;
  90. #define NWORDS 129
  91. #define hdr ((struct swap_header_v1*)bb_common_bufsiz1)
  92. #define INIT_G() do { setup_common_bufsiz(); } while (0)
  93. struct BUG_sizes {
  94. char swap_header_v1_wrong[sizeof(*hdr) != (NWORDS * 4) ? -1 : 1];
  95. char bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
  96. };
  97. /* Stored without terminating NUL */
  98. static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2";
  99. int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  100. int mkswap_main(int argc UNUSED_PARAM, char **argv)
  101. {
  102. int fd;
  103. unsigned pagesize;
  104. off_t len;
  105. const char *label = "";
  106. INIT_G();
  107. opt_complementary = "-1"; /* at least one param */
  108. /* TODO: -p PAGESZ, -U UUID */
  109. getopt32(argv, "L:", &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. }