mkswap.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. //usage:#define mkswap_trivial_usage
  9. //usage: "[-L LBL] BLOCKDEV [KBYTES]"
  10. //usage:#define mkswap_full_usage "\n\n"
  11. //usage: "Prepare BLOCKDEV to be used as swap partition\n"
  12. //usage: "\n -L LBL Label"
  13. #include "libbb.h"
  14. #include "common_bufsiz.h"
  15. #if ENABLE_SELINUX
  16. static void mkswap_selinux_setcontext(int fd, const char *path)
  17. {
  18. struct stat stbuf;
  19. if (!is_selinux_enabled())
  20. return;
  21. xfstat(fd, &stbuf, path);
  22. if (S_ISREG(stbuf.st_mode)) {
  23. security_context_t newcon;
  24. security_context_t oldcon = NULL;
  25. context_t context;
  26. if (fgetfilecon(fd, &oldcon) < 0) {
  27. if (errno != ENODATA)
  28. goto error;
  29. if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0)
  30. goto error;
  31. }
  32. context = context_new(oldcon);
  33. if (!context || context_type_set(context, "swapfile_t"))
  34. goto error;
  35. newcon = context_str(context);
  36. if (!newcon)
  37. goto error;
  38. /* fsetfilecon_raw is hidden */
  39. if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0)
  40. goto error;
  41. if (ENABLE_FEATURE_CLEAN_UP) {
  42. context_free(context);
  43. freecon(oldcon);
  44. }
  45. }
  46. return;
  47. error:
  48. bb_perror_msg_and_die("SELinux relabeling failed");
  49. }
  50. #else
  51. # define mkswap_selinux_setcontext(fd, path) ((void)0)
  52. #endif
  53. /* from Linux 2.6.23 */
  54. /*
  55. * Magic header for a swap area. ... Note that the first
  56. * kilobyte is reserved for boot loader or disk label stuff.
  57. */
  58. struct swap_header_v1 {
  59. /* char bootbits[1024]; Space for disklabel etc. */
  60. uint32_t version; /* second kbyte, word 0 */
  61. uint32_t last_page; /* 1 */
  62. uint32_t nr_badpages; /* 2 */
  63. char sws_uuid[16]; /* 3,4,5,6 */
  64. char sws_volume[16]; /* 7,8,9,10 */
  65. uint32_t padding[117]; /* 11..127 */
  66. uint32_t badpages[1]; /* 128 */
  67. /* total 129 32-bit words in 2nd kilobyte */
  68. } FIX_ALIASING;
  69. #define NWORDS 129
  70. #define hdr ((struct swap_header_v1*)bb_common_bufsiz1)
  71. #define INIT_G() do { setup_common_bufsiz(); } while (0)
  72. struct BUG_sizes {
  73. char swap_header_v1_wrong[sizeof(*hdr) != (NWORDS * 4) ? -1 : 1];
  74. char bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
  75. };
  76. /* Stored without terminating NUL */
  77. static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2";
  78. int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  79. int mkswap_main(int argc UNUSED_PARAM, char **argv)
  80. {
  81. int fd;
  82. unsigned pagesize;
  83. off_t len;
  84. const char *label = "";
  85. INIT_G();
  86. opt_complementary = "-1"; /* at least one param */
  87. /* TODO: -p PAGESZ, -U UUID */
  88. getopt32(argv, "L:", &label);
  89. argv += optind;
  90. fd = xopen(argv[0], O_WRONLY);
  91. /* Figure out how big the device is */
  92. len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1);
  93. pagesize = getpagesize();
  94. len -= pagesize;
  95. /* Announce our intentions */
  96. printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n", len);
  97. mkswap_selinux_setcontext(fd, argv[0]);
  98. /* hdr is zero-filled so far. Clear the first kbyte, or else
  99. * mkswap-ing former FAT partition does NOT erase its signature.
  100. *
  101. * util-linux-ng 2.17.2 claims to erase it only if it does not see
  102. * a partition table and is not run on whole disk. -f forces it.
  103. */
  104. xwrite(fd, hdr, 1024);
  105. /* Fill the header. */
  106. hdr->version = 1;
  107. hdr->last_page = (uoff_t)len / pagesize;
  108. if (ENABLE_FEATURE_MKSWAP_UUID) {
  109. char uuid_string[32];
  110. generate_uuid((void*)hdr->sws_uuid);
  111. bin2hex(uuid_string, hdr->sws_uuid, 16);
  112. /* f.e. UUID=dfd9c173-be52-4d27-99a5-c34c6c2ff55f */
  113. printf("UUID=%.8s" "-%.4s-%.4s-%.4s-%.12s\n",
  114. uuid_string,
  115. uuid_string+8,
  116. uuid_string+8+4,
  117. uuid_string+8+4+4,
  118. uuid_string+8+4+4+4
  119. );
  120. }
  121. safe_strncpy(hdr->sws_volume, label, 16);
  122. /* Write the header. Sync to disk because some kernel versions check
  123. * signature on disk (not in cache) during swapon. */
  124. xwrite(fd, hdr, NWORDS * 4);
  125. xlseek(fd, pagesize - 10, SEEK_SET);
  126. xwrite(fd, SWAPSPACE2, 10);
  127. fsync(fd);
  128. if (ENABLE_FEATURE_CLEAN_UP)
  129. close(fd);
  130. return 0;
  131. }