lineedit: do not hang on error, but return error indicator.
[oweals/busybox.git] / util-linux / mkswap.c
index 11c411b6ac14043f3ce2f0bfcb83b740c235638d..53537fcd9dceb1e28742a3c9d572af964df50d93 100644 (file)
@@ -3,9 +3,8 @@
  *
  * Copyright 2006 Rob Landley <rob@landley.net>
  *
- * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  */
-
 #include "libbb.h"
 
 #if ENABLE_SELINUX
@@ -16,8 +15,7 @@ static void mkswap_selinux_setcontext(int fd, const char *path)
        if (!is_selinux_enabled())
                return;
 
-       if (fstat(fd, &stbuf) < 0)
-               bb_perror_msg_and_die("fstat failed");
+       xfstat(fd, &stbuf, argv[0]);
        if (S_ISREG(stbuf.st_mode)) {
                security_context_t newcon;
                security_context_t oldcon = NULL;
@@ -48,82 +46,97 @@ static void mkswap_selinux_setcontext(int fd, const char *path)
        bb_perror_msg_and_die("SELinux relabeling failed");
 }
 #else
-#define mkswap_selinux_setcontext(fd, path) ((void)0)
+# define mkswap_selinux_setcontext(fd, path) ((void)0)
 #endif
 
-#if 0 /* from Linux 2.6.23 */
+/* from Linux 2.6.23 */
 /*
- * Magic header for a swap area. The first part of the union is
- * what the swap magic looks like for the old (limited to 128MB)
- * swap area format, the second part of the union adds - in the
- * old reserved area - some extra information. Note that the first
- * kilobyte is reserved for boot loader or disk label stuff...
+ * Magic header for a swap area. ... Note that the first
+ * kilobyte is reserved for boot loader or disk label stuff.
  */
-union swap_header {
-       struct {
-               char reserved[PAGE_SIZE - 10];
-               char magic[10];                 /* SWAP-SPACE or SWAPSPACE2 */
-       } magic;
-       struct {
-               char            bootbits[1024]; /* Space for disklabel etc. */
-               __u32           version;        /* second kbyte, word 0 */
-               __u32           last_page;      /* 1 */
-               __u32           nr_badpages;    /* 2 */
-               unsigned char   sws_uuid[16];   /* 3,4,5,6 */
-               unsigned char   sws_volume[16]; /* 7,8,9,10  */
-               __u32           padding[117];   /* 11..127 */
-               __u32           badpages[1];    /* 128, total 129 32-bit words */
-       } info;
-};
-#endif
+struct swap_header_v1 {
+/*     char     bootbits[1024];    Space for disklabel etc. */
+       uint32_t version;        /* second kbyte, word 0 */
+       uint32_t last_page;      /* 1 */
+       uint32_t nr_badpages;    /* 2 */
+       char     sws_uuid[16];   /* 3,4,5,6 */
+       char     sws_volume[16]; /* 7,8,9,10 */
+       uint32_t padding[117];   /* 11..127 */
+       uint32_t badpages[1];    /* 128 */
+       /* total 129 32-bit words in 2nd kilobyte */
+} FIX_ALIASING;
 
 #define NWORDS 129
-#define hdr ((uint32_t*)(&bb_common_bufsiz1))
+#define hdr ((struct swap_header_v1*)bb_common_bufsiz1)
 
-struct BUG_bufsiz1_is_too_small {
-       char BUG_bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
+struct BUG_sizes {
+       char swap_header_v1_wrong[sizeof(*hdr)  != (NWORDS * 4) ? -1 : 1];
+       char bufsiz1_is_too_small[COMMON_BUFSIZE < (NWORDS * 4) ? -1 : 1];
 };
 
 /* Stored without terminating NUL */
 static const char SWAPSPACE2[sizeof("SWAPSPACE2")-1] ALIGN1 = "SWAPSPACE2";
 
 int mkswap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int mkswap_main(int argc, char **argv)
+int mkswap_main(int argc UNUSED_PARAM, char **argv)
 {
-       int fd, pagesize;
+       int fd;
+       unsigned pagesize;
        off_t len;
+       const char *label = "";
 
-       // No options supported.
+       opt_complementary = "-1"; /* at least one param */
+       /* TODO: -p PAGESZ, -U UUID */
+       getopt32(argv, "L:", &label);
+       argv += optind;
 
-       if (argc != 2) bb_show_usage();
+       fd = xopen(argv[0], O_WRONLY);
 
-       // Figure out how big the device is and announce our intentions.
-
-       fd = xopen(argv[1], O_RDWR);
-       /* fdlength was reported to be unreliable - use seek */
-       len = xlseek(fd, 0, SEEK_END);
-#if ENABLE_SELINUX
-       xlseek(fd, 0, SEEK_SET);
-#endif
+       /* Figure out how big the device is */
+       len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1);
        pagesize = getpagesize();
-       printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n",
-                       len - pagesize);
-       mkswap_selinux_setcontext(fd, argv[1]);
-
-       // Make a header. hdr is zero-filled so far...
-       hdr[0] = 1;
-       hdr[1] = (len / pagesize) - 1;
-
-       // Write the header.  Sync to disk because some kernel versions check
-       // signature on disk (not in cache) during swapon.
+       len -= pagesize;
+
+       /* Announce our intentions */
+       printf("Setting up swapspace version 1, size = %"OFF_FMT"u bytes\n", len);
+       mkswap_selinux_setcontext(fd, argv[0]);
+
+       /* hdr is zero-filled so far. Clear the first kbyte, or else
+        * mkswap-ing former FAT partition does NOT erase its signature.
+        *
+        * util-linux-ng 2.17.2 claims to erase it only if it does not see
+        * a partition table and is not run on whole disk. -f forces it.
+        */
+       xwrite(fd, hdr, 1024);
+
+       /* Fill the header. */
+       hdr->version = 1;
+       hdr->last_page = (uoff_t)len / pagesize;
+
+       if (ENABLE_FEATURE_MKSWAP_UUID) {
+               char uuid_string[32];
+               generate_uuid((void*)hdr->sws_uuid);
+               bin2hex(uuid_string, hdr->sws_uuid, 16);
+               /* f.e. UUID=dfd9c173-be52-4d27-99a5-c34c6c2ff55f */
+               printf("UUID=%.8s"  "-%.4s-%.4s-%.4s-%.12s\n",
+                       uuid_string,
+                       uuid_string+8,
+                       uuid_string+8+4,
+                       uuid_string+8+4+4,
+                       uuid_string+8+4+4+4
+               );
+       }
+       safe_strncpy(hdr->sws_volume, label, 16);
 
-       xlseek(fd, 1024, SEEK_SET);
+       /* Write the header.  Sync to disk because some kernel versions check
+        * signature on disk (not in cache) during swapon. */
        xwrite(fd, hdr, NWORDS * 4);
        xlseek(fd, pagesize - 10, SEEK_SET);
        xwrite(fd, SWAPSPACE2, 10);
        fsync(fd);
 
-       if (ENABLE_FEATURE_CLEAN_UP) close(fd);
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(fd);
 
        return 0;
 }