2 * mkswap.c - set up a linux swap device
4 * Copyright (C) 1991 Linus Torvalds
5 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
7 * Copyright (C) 1999 Jakub Jelinek <jj@ultra.linux.cz>
8 * Copyright (C) 2007-2014 Karel Zak <kzak@redhat.com>
17 #include <sys/utsname.h>
19 #include <sys/ioctl.h>
23 #ifdef HAVE_LIBSELINUX
24 # include <selinux/selinux.h>
25 # include <selinux/context.h>
27 #ifdef HAVE_LINUX_FIEMAP_H
28 # include <linux/fs.h>
29 # include <linux/fiemap.h>
32 #include "linux_version.h"
33 #include "swapheader.h"
37 #include "pathnames.h"
41 #include "closestream.h"
42 #include "ismounted.h"
52 #define MIN_GOODPAGES 10
54 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
56 struct mkswap_control
{
57 struct swap_header_v1_2
*hdr
; /* swap header */
58 void *signature_page
;/* buffer with swap header */
60 char *devname
; /* device or file name */
61 const char *lockmode
; /* as specified by --lock */
62 struct stat devstat
; /* stat() result */
63 int fd
; /* swap file descriptor */
65 unsigned long long npages
; /* number of pages */
66 unsigned long nbadpages
; /* number of bad pages */
68 int user_pagesize
; /* --pagesize */
69 int pagesize
; /* final pagesize used for the header */
71 char *opt_label
; /* LABEL as specified on command line */
72 unsigned char *uuid
; /* UUID parsed by libbuuid */
74 unsigned int check
:1, /* --check */
75 force
:1; /* --force */
78 static void init_signature_page(struct mkswap_control
*ctl
)
80 const int kernel_pagesize
= getpagesize();
82 if (ctl
->user_pagesize
) {
83 if (ctl
->user_pagesize
< 0 || !is_power_of_2(ctl
->user_pagesize
) ||
84 (size_t) ctl
->user_pagesize
< sizeof(struct swap_header_v1_2
) + 10)
86 _("Bad user-specified page size %u"),
88 if (ctl
->user_pagesize
!= kernel_pagesize
)
89 warnx(_("Using user-specified page size %d, "
90 "instead of the system value %d"),
91 ctl
->user_pagesize
, kernel_pagesize
);
92 ctl
->pagesize
= ctl
->user_pagesize
;
94 ctl
->pagesize
= kernel_pagesize
;
96 ctl
->signature_page
= xcalloc(1, ctl
->pagesize
);
97 ctl
->hdr
= (struct swap_header_v1_2
*) ctl
->signature_page
;
100 static void deinit_signature_page(struct mkswap_control
*ctl
)
102 free(ctl
->signature_page
);
105 ctl
->signature_page
= NULL
;
108 static void set_signature(const struct mkswap_control
*ctl
)
110 char *sp
= (char *) ctl
->signature_page
;
113 memcpy(sp
+ ctl
->pagesize
- SWAP_SIGNATURE_SZ
, SWAP_SIGNATURE
, SWAP_SIGNATURE_SZ
);
116 static void set_uuid_and_label(const struct mkswap_control
*ctl
)
123 memcpy(ctl
->hdr
->uuid
, ctl
->uuid
, sizeof(ctl
->hdr
->uuid
));
126 if (ctl
->opt_label
) {
127 xstrncpy(ctl
->hdr
->volume_name
,
128 ctl
->opt_label
, sizeof(ctl
->hdr
->volume_name
));
129 if (strlen(ctl
->opt_label
) > strlen(ctl
->hdr
->volume_name
))
130 warnx(_("Label was truncated."));
134 if (ctl
->uuid
|| ctl
->opt_label
) {
136 printf("LABEL=%s, ", ctl
->hdr
->volume_name
);
138 printf(_("no label, "));
141 char uuid_string
[UUID_STR_LEN
];
142 uuid_unparse(ctl
->uuid
, uuid_string
);
143 printf("UUID=%s\n", uuid_string
);
146 printf(_("no uuid\n"));
150 static void __attribute__((__noreturn__
)) usage(void)
155 " %s [options] device [size]\n"),
156 program_invocation_short_name
);
158 fputs(USAGE_SEPARATOR
, out
);
159 fputs(_("Set up a Linux swap area.\n"), out
);
163 " -c, --check check bad blocks before creating the swap area\n"
164 " -f, --force allow swap size area be larger than device\n"
165 " -p, --pagesize SIZE specify page size in bytes\n"
166 " -L, --label LABEL specify label\n"
167 " -v, --swapversion NUM specify swap-space version number\n"
168 " -U, --uuid UUID specify the uuid to use\n"
171 _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
172 printf(USAGE_HELP_OPTIONS(27));
174 printf(USAGE_MAN_TAIL("mkswap(8)"));
178 static void page_bad(struct mkswap_control
*ctl
, unsigned int page
)
180 const unsigned long max_badpages
=
181 (ctl
->pagesize
- 1024 - 128 * sizeof(int) - 10) / sizeof(int);
183 if (ctl
->nbadpages
== max_badpages
)
184 errx(EXIT_FAILURE
, _("too many bad pages: %lu"), max_badpages
);
186 ctl
->hdr
->badpages
[ctl
->nbadpages
] = page
;
190 static void check_blocks(struct mkswap_control
*ctl
)
192 unsigned int current_page
= 0;
197 assert(ctl
->fd
> -1);
199 buffer
= xmalloc(ctl
->pagesize
);
200 while (current_page
< ctl
->npages
) {
202 off_t offset
= (off_t
) current_page
* ctl
->pagesize
;
204 if (do_seek
&& lseek(ctl
->fd
, offset
, SEEK_SET
) != offset
)
205 errx(EXIT_FAILURE
, _("seek failed in check_blocks"));
207 rc
= read(ctl
->fd
, buffer
, ctl
->pagesize
);
208 do_seek
= (rc
< 0 || rc
!= ctl
->pagesize
);
210 page_bad(ctl
, current_page
);
213 printf(P_("%lu bad page\n", "%lu bad pages\n", ctl
->nbadpages
), ctl
->nbadpages
);
218 #ifdef HAVE_LINUX_FIEMAP_H
219 static void check_extents_print_hdr(int *n
)
223 warnx(_("extents check failed:"));
228 static void check_extents(struct mkswap_control
*ctl
)
230 char buf
[BUFSIZ
] = { 0 };
231 struct fiemap
*fiemap
= (struct fiemap
*) buf
;
232 int last
= 0, nerrs
= 0;
233 uint64_t last_logical
= 0;
235 memset(fiemap
, 0, sizeof(struct fiemap
));
241 fiemap
->fm_length
= ~0ULL;
242 fiemap
->fm_flags
= 0;
243 fiemap
->fm_extent_count
=
244 (sizeof(buf
) - sizeof(*fiemap
)) / sizeof(struct fiemap_extent
);
246 rc
= ioctl(ctl
->fd
, FS_IOC_FIEMAP
, (unsigned long) fiemap
);
248 warn(_("FIEMAP failed -- ignore extents check"));
252 n
= fiemap
->fm_mapped_extents
;
254 for (i
= 0; i
< n
; i
++) {
255 struct fiemap_extent
*e
= &fiemap
->fm_extents
[i
];
257 if (e
->fe_logical
> last_logical
) {
258 check_extents_print_hdr(&nerrs
);
259 fprintf(stderr
, (" - hole detected at offset %ju (size %ju bytes)\n"),
260 (uintmax_t) last_logical
,
261 (uintmax_t) e
->fe_logical
- last_logical
);
264 last_logical
= (e
->fe_logical
+ e
->fe_length
);
266 if (e
->fe_flags
& FIEMAP_EXTENT_LAST
)
268 if (e
->fe_flags
& FIEMAP_EXTENT_UNKNOWN
) {
269 check_extents_print_hdr(&nerrs
);
270 fprintf(stderr
, _(" - unknown file extent type at offset %ju\n"),
271 (uintmax_t) last_logical
);
273 if (e
->fe_flags
& FIEMAP_EXTENT_DATA_INLINE
){
274 check_extents_print_hdr(&nerrs
);
275 fprintf(stderr
, _(" - data inline extent at offset %ju\n"),
276 (uintmax_t) last_logical
);
278 if (e
->fe_flags
& FIEMAP_EXTENT_SHARED
){
279 check_extents_print_hdr(&nerrs
);
280 fprintf(stderr
, _(" - shared extent at offset %ju\n"),
281 (uintmax_t) last_logical
);
283 if (e
->fe_flags
& FIEMAP_EXTENT_DELALLOC
){
284 check_extents_print_hdr(&nerrs
);
285 fprintf(stderr
, _(" - deallocated extent at offset %ju\n"),
286 (uintmax_t) last_logical
);
290 fiemap
->fm_start
= fiemap
->fm_extents
[n
- 1].fe_logical
291 + fiemap
->fm_extents
[n
- 1].fe_length
;
295 fprintf(stderr
, _("file %s can be rejected by kernel on swap activation.\n\n"),
298 #endif /* HAVE_LINUX_FIEMAP_H */
300 /* return size in pages */
301 static unsigned long long get_size(const struct mkswap_control
*ctl
)
304 unsigned long long size
;
306 fd
= open(ctl
->devname
, O_RDONLY
);
308 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
309 if (blkdev_get_size(fd
, &size
) == 0)
310 size
/= ctl
->pagesize
;
317 static blkid_probe
new_prober(const struct mkswap_control
*ctl
)
319 blkid_probe pr
= blkid_new_probe();
321 errx(EXIT_FAILURE
, _("unable to alloc new libblkid probe"));
322 if (blkid_probe_set_device(pr
, ctl
->fd
, 0, 0))
323 errx(EXIT_FAILURE
, _("unable to assign device to libblkid probe"));
328 static void open_device(struct mkswap_control
*ctl
)
331 assert(ctl
->devname
);
333 if (stat(ctl
->devname
, &ctl
->devstat
) < 0)
334 err(EXIT_FAILURE
, _("stat of %s failed"), ctl
->devname
);
335 ctl
->fd
= open_blkdev_or_file(&ctl
->devstat
, ctl
->devname
, O_RDWR
);
337 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
339 if (blkdev_lock(ctl
->fd
, ctl
->devname
, ctl
->lockmode
) != 0)
342 if (ctl
->check
&& S_ISREG(ctl
->devstat
.st_mode
)) {
344 warnx(_("warning: checking bad blocks from swap file is not supported: %s"),
349 static void wipe_device(struct mkswap_control
*ctl
)
354 blkid_probe pr
= NULL
;
357 const char *v
= NULL
;
359 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
360 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
363 pr
= new_prober(ctl
);
364 blkid_probe_enable_partitions(pr
, 1);
365 blkid_probe_enable_superblocks(pr
, 0);
367 if (blkid_do_fullprobe(pr
) == 0 &&
368 blkid_probe_lookup_value(pr
, "PTTYPE", &v
, NULL
) == 0 && v
) {
373 /* don't zap if compiled without libblkid */
382 char buf
[1024] = { '\0' };
384 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
385 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
387 if (write_all(ctl
->fd
, buf
, sizeof(buf
)))
388 errx(EXIT_FAILURE
, _("unable to erase bootbits sectors"));
391 * Wipe rest of the device
394 pr
= new_prober(ctl
);
396 blkid_probe_enable_superblocks(pr
, 1);
397 blkid_probe_enable_partitions(pr
, 0);
398 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_MAGIC
|BLKID_SUBLKS_TYPE
);
400 while (blkid_do_probe(pr
) == 0) {
401 const char *data
= NULL
;
403 if (blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
) == 0 && data
)
404 warnx(_("%s: warning: wiping old %s signature."), ctl
->devname
, data
);
405 blkid_do_wipe(pr
, 0);
409 warnx(_("%s: warning: don't erase bootbits sectors"),
412 fprintf(stderr
, _(" (%s partition table detected). "), type
);
414 fprintf(stderr
, _(" (compiled without libblkid). "));
415 fprintf(stderr
, _("Use -f to force.\n"));
419 blkid_free_probe(pr
);
423 #define SIGNATURE_OFFSET 1024
425 static void write_header_to_device(struct mkswap_control
*ctl
)
428 assert(ctl
->fd
> -1);
429 assert(ctl
->signature_page
);
431 if (lseek(ctl
->fd
, SIGNATURE_OFFSET
, SEEK_SET
) != SIGNATURE_OFFSET
)
432 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
434 if (write_all(ctl
->fd
, (char *) ctl
->signature_page
+ SIGNATURE_OFFSET
,
435 ctl
->pagesize
- SIGNATURE_OFFSET
) == -1)
437 _("%s: unable to write signature page"),
441 int main(int argc
, char **argv
)
443 struct mkswap_control ctl
= { .fd
= -1 };
446 int version
= SWAP_VERSION
;
447 char *block_count
= NULL
, *strsz
= NULL
;
449 const char *opt_uuid
= NULL
;
453 OPT_LOCK
= CHAR_MAX
+ 1,
455 static const struct option longopts
[] = {
456 { "check", no_argument
, NULL
, 'c' },
457 { "force", no_argument
, NULL
, 'f' },
458 { "pagesize", required_argument
, NULL
, 'p' },
459 { "label", required_argument
, NULL
, 'L' },
460 { "swapversion", required_argument
, NULL
, 'v' },
461 { "uuid", required_argument
, NULL
, 'U' },
462 { "version", no_argument
, NULL
, 'V' },
463 { "help", no_argument
, NULL
, 'h' },
464 { "lock", optional_argument
, NULL
, OPT_LOCK
},
468 setlocale(LC_ALL
, "");
469 bindtextdomain(PACKAGE
, LOCALEDIR
);
471 close_stdout_atexit();
473 while((c
= getopt_long(argc
, argv
, "cfp:L:v:U:Vh", longopts
, NULL
)) != -1) {
482 ctl
.user_pagesize
= strtou32_or_err(optarg
, _("parsing page size failed"));
485 ctl
.opt_label
= optarg
;
488 version
= strtos32_or_err(optarg
, _("parsing version number failed"));
489 if (version
!= SWAP_VERSION
)
491 _("swapspace version %d is not supported"), version
);
497 warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"),
498 program_invocation_short_name
);
502 print_version(EXIT_SUCCESS
);
509 ctl
.lockmode
= optarg
;
515 errtryhelp(EXIT_FAILURE
);
520 ctl
.devname
= argv
[optind
++];
522 block_count
= argv
[optind
++];
523 if (optind
!= argc
) {
524 warnx(_("only one device argument is currently supported"));
525 errtryhelp(EXIT_FAILURE
);
530 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
531 errx(EXIT_FAILURE
, _("error: parsing UUID failed"));
533 uuid_generate(uuid_dat
);
537 init_signature_page(&ctl
); /* get pagesize and allocate signature page */
540 warnx(_("error: Nowhere to set up swap on?"));
541 errtryhelp(EXIT_FAILURE
);
544 /* this silly user specified the number of blocks explicitly */
545 uint64_t blks
= strtou64_or_err(block_count
,
546 _("invalid block count argument"));
547 ctl
.npages
= blks
/ (ctl
.pagesize
/ 1024);
553 else if (ctl
.npages
> sz
&& !ctl
.force
)
556 "size %llu KiB is larger than device size %"PRIu64
" KiB"),
557 ctl
.npages
* (ctl
.pagesize
/ 1024), sz
* (ctl
.pagesize
/ 1024));
559 if (ctl
.npages
< MIN_GOODPAGES
)
561 _("error: swap area needs to be at least %ld KiB"),
562 (long)(MIN_GOODPAGES
* ctl
.pagesize
/ 1024));
563 if (ctl
.npages
> UINT32_MAX
) {
564 /* true when swap is bigger than 17.59 terabytes */
565 ctl
.npages
= UINT32_MAX
;
566 warnx(_("warning: truncating swap area to %llu KiB"),
567 ctl
.npages
* ctl
.pagesize
/ 1024);
570 if (is_mounted(ctl
.devname
))
571 errx(EXIT_FAILURE
, _("error: "
572 "%s is mounted; will not make swapspace"),
576 permMask
= S_ISBLK(ctl
.devstat
.st_mode
) ? 07007 : 07077;
577 if ((ctl
.devstat
.st_mode
& permMask
) != 0)
578 warnx(_("%s: insecure permissions %04o, %04o suggested."),
579 ctl
.devname
, ctl
.devstat
.st_mode
& 07777,
581 if (getuid() == 0 && S_ISREG(ctl
.devstat
.st_mode
) && ctl
.devstat
.st_uid
!= 0)
582 warnx(_("%s: insecure file owner %d, 0 (root) suggested."),
583 ctl
.devname
, ctl
.devstat
.st_uid
);
588 #ifdef HAVE_LINUX_FIEMAP_H
589 if (S_ISREG(ctl
.devstat
.st_mode
))
596 ctl
.hdr
->version
= version
;
597 ctl
.hdr
->last_page
= ctl
.npages
- 1;
598 ctl
.hdr
->nr_badpages
= ctl
.nbadpages
;
600 if ((ctl
.npages
- MIN_GOODPAGES
) < ctl
.nbadpages
)
601 errx(EXIT_FAILURE
, _("Unable to set up swap-space: unreadable"));
603 sz
= (ctl
.npages
- ctl
.nbadpages
- 1) * ctl
.pagesize
;
604 strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
| SIZE_SUFFIX_3LETTER
, sz
);
606 printf(_("Setting up swapspace version %d, size = %s (%"PRIu64
" bytes)\n"),
611 set_uuid_and_label(&ctl
);
613 write_header_to_device(&ctl
);
615 deinit_signature_page(&ctl
);
617 #ifdef HAVE_LIBSELINUX
618 if (S_ISREG(ctl
.devstat
.st_mode
) && is_selinux_enabled() > 0) {
619 security_context_t context_string
;
620 security_context_t oldcontext
;
621 context_t newcontext
;
623 if (fgetfilecon(ctl
.fd
, &oldcontext
) < 0) {
624 if (errno
!= ENODATA
)
626 _("%s: unable to obtain selinux file label"),
628 if (matchpathcon(ctl
.devname
, ctl
.devstat
.st_mode
, &oldcontext
))
629 errx(EXIT_FAILURE
, _("unable to matchpathcon()"));
631 if (!(newcontext
= context_new(oldcontext
)))
632 errx(EXIT_FAILURE
, _("unable to create new selinux context"));
633 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
634 errx(EXIT_FAILURE
, _("couldn't compute selinux context"));
636 context_string
= context_str(newcontext
);
638 if (strcmp(context_string
, oldcontext
)!=0) {
639 if (fsetfilecon(ctl
.fd
, context_string
) && errno
!= ENOTSUP
)
640 err(EXIT_FAILURE
, _("unable to relabel %s to %s"),
641 ctl
.devname
, context_string
);
643 context_free(newcontext
);
648 * A subsequent swapon() will fail if the signature
649 * is not actually on disk. (This is a kernel bug.)
650 * The fsync() in close_fd() will take care of writing.
652 if (close_fd(ctl
.fd
) != 0)
653 err(EXIT_FAILURE
, _("write failed"));