mkswap.c 3.9 KB

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