summaryrefslogtreecommitdiffstats
path: root/disk-utils/mkswap.c
diff options
context:
space:
mode:
Diffstat (limited to 'disk-utils/mkswap.c')
-rw-r--r--disk-utils/mkswap.c83
1 files changed, 67 insertions, 16 deletions
diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c
index 30c4ea8..9c80b07 100644
--- a/disk-utils/mkswap.c
+++ b/disk-utils/mkswap.c
@@ -83,10 +83,13 @@ struct mkswap_control {
int user_pagesize; /* --pagesize */
int pagesize; /* final pagesize used for the header */
+ off_t offset; /* offset of the header in the target */
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;
@@ -94,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)
@@ -201,14 +205,17 @@ static void __attribute__((__noreturn__)) usage(void)
fprintf(out,
_(" -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,
_(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
- printf(USAGE_HELP_OPTIONS(27));
+ fprintf(out, USAGE_HELP_OPTIONS(27));
- printf(USAGE_MAN_TAIL("mkswap(8)"));
+ fprintf(out, USAGE_MAN_TAIL("mkswap(8)"));
exit(EXIT_SUCCESS);
}
@@ -346,17 +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 (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;
}
@@ -377,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);
@@ -472,11 +506,15 @@ static void wipe_device(struct mkswap_control *ctl)
static void write_header_to_device(struct mkswap_control *ctl)
{
+ off_t offset;
+
assert(ctl);
assert(ctl->fd > -1);
assert(ctl->signature_page);
- if (lseek(ctl->fd, SIGNATURE_OFFSET, SEEK_SET) != SIGNATURE_OFFSET)
+ offset = SIGNATURE_OFFSET + ctl->offset;
+
+ if (lseek(ctl->fd, offset, SEEK_SET) != offset)
errx(EXIT_FAILURE, _("unable to rewind swap-device"));
if (write_all(ctl->fd, (char *) ctl->signature_page + SIGNATURE_OFFSET,
@@ -510,6 +548,9 @@ int main(int argc, char **argv)
{ "swapversion", required_argument, NULL, 'v' },
{ "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 },
@@ -528,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: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);
@@ -574,6 +615,16 @@ int main(int argc, char **argv)
_("invalid endianness %s is not supported"), optarg);
}
break;
+ case 'o':
+ 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;