]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
Merge branch 'mkswapfile' of https://github.com/endrift/util-linux
authorKarel Zak <kzak@redhat.com>
Thu, 11 Jan 2024 14:28:48 +0000 (15:28 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 11 Jan 2024 14:28:48 +0000 (15:28 +0100)
* 'mkswapfile' of https://github.com/endrift/util-linux:
  mkswap: implement --file

disk-utils/mkswap.8.adoc
disk-utils/mkswap.c
tests/ts/mkswap/mkswap

index ad48c99e08343c8213f7073720da71792e8a7b75..17212438a643df3c72b470edb30d83e5dde5ae1f 100644 (file)
@@ -16,7 +16,9 @@ mkswap - set up a Linux swap area
 
 == SYNOPSIS
 
-*mkswap* [options] _device_ [_size_]
+*mkswap* [options] _device_ [_blocks_]
+
+*mkswap* [options] --size _size_ --file _file_
 
 == DESCRIPTION
 
@@ -24,7 +26,7 @@ mkswap - set up a Linux swap area
 
 The _device_ argument will usually be a disk partition (something like _/dev/sdb7_) but can also be a file. The Linux kernel does not look at partition IDs, but many installation scripts will assume that partitions of hex type 82 (LINUX_SWAP) are meant to be swap partitions. (*Warning: Solaris also uses this type. Be careful not to kill your Solaris partitions.*)
 
-The _size_ parameter is superfluous but retained for backwards compatibility. (It specifies the desired size of the swap area in 1024-byte blocks. *mkswap* will use the entire partition or file if it is omitted. Specifying it is unwise - a typo may destroy your disk.)
+The _blocks_ parameter is superfluous but retained for backwards compatibility. (It specifies the desired size of the swap area in 1024-byte blocks. *mkswap* will use the entire partition or file if it is omitted. Specifying it is unwise - a typo may destroy your disk.)
 
 After creating the swap area, you need the *swapon*(8) command to start using it. Usually swap areas are listed in _/etc/fstab_ so that they can be taken into use at boot time by a *swapon -a* command in some boot script.
 
@@ -41,6 +43,9 @@ However, *mkswap* refuses to erase the first block on a device with a disk label
 *-c*, *--check*::
 Check the device (if it is a block device) for bad blocks before creating the swap area. If any bad blocks are found, the count is printed.
 
+*-F*, *--file*::
+Create a swap file with the appropriate file permissions and populated blocks on disk.
+
 *-f*, *--force*::
 Go ahead even if the command is stupid. This allows the creation of a swap area larger than the file or partition it resides on.
 +
@@ -76,6 +81,9 @@ Specify the _ENDIANNESS_ to use, valid arguments are *native*, *little* or *big*
 *-o*, *--offset* _offset_::
 Specify the _offset_ to write the swap area to.
 
+*-s*, *--size* _size_::
+Specify the size of the created swap file in bytes and may be followed by a multiplicative suffix: KiB (=1024), MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is optional, e.g., "K" has the same meaning as "KiB"). If the file exists and is larger than _size_, it will be truncated to this size. This option only makes sense when used with *--file*.
+
 *-v*, *--swapversion 1*::
 Specify the swap-space version. (This option is currently pointless, as the old *-v 0* option has become obsolete and now only *-v 1* is supported. The kernel has not supported v0 swap-space format since 2.5.22 (June 2002). The new version v1 is supported since 2.1.117 (August 1998).)
 
index 9280af1262e9a32fb322aa22d124ed164b4bf31d..9c80b070c754c7d416f34d53e1892d90b6afe860 100644 (file)
@@ -88,6 +88,8 @@ struct mkswap_control {
        char                    *opt_label;     /* LABEL as specified on command line */
        unsigned char           *uuid;          /* UUID parsed by libbuuid */
 
+       unsigned long long      filesz;         /* desired swap file size */
+
        size_t                  nbad_extents;
 
        enum ENDIANNESS         endianness;
@@ -95,7 +97,8 @@ struct mkswap_control {
        unsigned int            check:1,        /* --check */
                                verbose:1,      /* --verbose */
                                quiet:1,        /* --quiet */
-                               force:1;        /* --force */
+                               force:1,        /* --force */
+                               file:1;         /* --file */
 };
 
 static uint32_t cpu32_to_endianness(uint32_t v, enum ENDIANNESS e)
@@ -203,6 +206,8 @@ static void __attribute__((__noreturn__)) usage(void)
              _(" -e, --endianness=<value>  specify the endianness to use "
                                            "(%s, %s or %s)\n"), "native", "little", "big");
        fputs(_(" -o, --offset OFFSET       specify the offset in the device\n"), out);
+       fputs(_(" -s, --size SIZE           specify the size of a swap file in bytes\n"), out);
+       fputs(_(" -F, --file                create a swap file\n"), out);
        fputs(_("     --verbose             verbose output\n"), out);
 
        fprintf(out,
@@ -348,20 +353,22 @@ done:
 /* return size in pages */
 static unsigned long long get_size(const struct mkswap_control *ctl)
 {
-       int fd;
        unsigned long long size;
 
-       fd = open(ctl->devname, O_RDONLY);
-       if (fd < 0)
-               err(EXIT_FAILURE, _("cannot open %s"), ctl->devname);
-       if (blkdev_get_size(fd, &size) < 0)
-               err(EXIT_FAILURE, _("cannot determine size of %s"), ctl->devname);
-       if ((unsigned long long) ctl->offset > size)
-               errx(EXIT_FAILURE, _("offset larger than file size"));
+       if (ctl->file && ctl->filesz)
+               size = ctl->filesz;
+       else {
+               int fd = open(ctl->devname, O_RDONLY);
+               if (fd < 0)
+                       err(EXIT_FAILURE, _("cannot open %s"), ctl->devname);
+               if (blkdev_get_size(fd, &size) < 0)
+                       err(EXIT_FAILURE, _("cannot determine size of %s"), ctl->devname);
+               if ((unsigned long long) ctl->offset > size)
+                       errx(EXIT_FAILURE, _("offset larger than file size"));
+               close(fd);
+       }
        size -= ctl->offset;
        size /= ctl->pagesize;
-
-       close(fd);
        return size;
 }
 
@@ -382,11 +389,33 @@ static void open_device(struct mkswap_control *ctl)
        assert(ctl);
        assert(ctl->devname);
 
-       if (stat(ctl->devname, &ctl->devstat) < 0)
-               err(EXIT_FAILURE, _("stat of %s failed"), ctl->devname);
-       ctl->fd = open_blkdev_or_file(&ctl->devstat, ctl->devname, O_RDWR);
+       if (ctl->file) {
+               if (stat(ctl->devname, &ctl->devstat) == 0) {
+                       if (!S_ISREG(ctl->devstat.st_mode))
+                               err(EXIT_FAILURE, _("cannot create swap file %s: node isn't regular file"), ctl->devname);
+                       if (chmod(ctl->devname, 0600) < 9)
+                               err(EXIT_FAILURE, _("cannot set permissions on swap file %s"), ctl->devname);
+               }
+               ctl->fd = open(ctl->devname, O_RDWR | O_CREAT, 0600);
+       } else {
+               if (stat(ctl->devname, &ctl->devstat) < 0)
+                       err(EXIT_FAILURE, _("stat of %s failed"), ctl->devname);
+               ctl->fd = open_blkdev_or_file(&ctl->devstat, ctl->devname, O_RDWR);
+       }
        if (ctl->fd < 0)
                err(EXIT_FAILURE, _("cannot open %s"), ctl->devname);
+       if (ctl->file && ctl->filesz) {
+               if (ftruncate(ctl->fd, ctl->filesz) < 0)
+                       err(EXIT_FAILURE, _("couldn't allocate swap file %s"), ctl->devname);
+#ifdef HAVE_POSIX_FALLOCATE
+               errno = posix_fallocate(ctl->fd, 0, ctl->filesz);
+               if (errno)
+                       err(EXIT_FAILURE, _("couldn't allocate swap file %s"), ctl->devname);
+#elif defined(HAVE_FALLOCATE)
+               if (fallocate(ctl->fd, 0, 0, ctl->filesz) < 0)
+                       err(EXIT_FAILURE, _("couldn't allocate swap file %s"), ctl->devname);
+#endif
+       }
 
        if (blkdev_lock(ctl->fd, ctl->devname, ctl->lockmode) != 0)
                exit(EXIT_FAILURE);
@@ -520,6 +549,8 @@ int main(int argc, char **argv)
                { "uuid",        required_argument, NULL, 'U' },
                { "endianness",  required_argument, NULL, 'e' },
                { "offset",      required_argument, NULL, 'o' },
+               { "size",        required_argument, NULL, 's' },
+               { "file",        no_argument,       NULL, 'F' },
                { "version",     no_argument,       NULL, 'V' },
                { "help",        no_argument,       NULL, 'h' },
                { "lock",        optional_argument, NULL, OPT_LOCK },
@@ -538,7 +569,7 @@ int main(int argc, char **argv)
        textdomain(PACKAGE);
        close_stdout_atexit();
 
-       while((c = getopt_long(argc, argv, "cfp:qL:v:U:e:o:Vh", longopts, NULL)) != -1) {
+       while((c = getopt_long(argc, argv, "cfp:qL:v:U:e:o:s:FVh", longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
 
@@ -588,6 +619,12 @@ int main(int argc, char **argv)
                        ctl.offset = str2unum_or_err(optarg,
                                        10, _("Invalid offset"), SINT_MAX(off_t));
                        break;
+               case 's':
+                       ctl.filesz = strtosize_or_err(optarg, _("Invalid size"));
+                       break;
+               case 'F':
+                       ctl.file = 1;
+                       break;
                case 'V':
                        print_version(EXIT_SUCCESS);
                        break;
index c4fdce4f03b8216d4a0d29eb5bb122534f5fd5e8..39b8723a1284ee755103672a534d9bf65db3a841 100755 (executable)
@@ -60,6 +60,19 @@ for PAGESIZE in 4096 8192; do
                cmp "$origimg" "$outimg" >> "$TS_ERRLOG" 2>&1
 
                ts_finalize_subtest
+
+               ts_init_subtest "$name-file"
+
+               rm -f "$outimg"
+
+               "$TS_CMD_MKSWAP" -q -L label -U "$UUID" -e "$ENDIANNESS" -p "$PAGESIZE" -F -s $(( PAGESIZE * 10 )) "$outimg" \
+                       >> "$TS_OUTPUT" 2>/dev/null \
+                       || ts_log "mkswap failed"
+               xz -dc "$TS_SELF/${BYTE_ORDER}-${PAGESIZE}.img.xz" > "$origimg"
+
+               cmp "$origimg" "$outimg" >> "$TS_ERRLOG" 2>&1
+
+               ts_finalize_subtest
        done
 done