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>
22 #ifdef HAVE_LIBSELINUX
23 #include <selinux/selinux.h>
24 #include <selinux/context.h>
27 #include "linux_version.h"
28 #include "swapheader.h"
32 #include "pathnames.h"
36 #include "closestream.h"
37 #include "ismounted.h"
47 #define MIN_GOODPAGES 10
49 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
51 struct mkswap_control
{
52 struct swap_header_v1_2
*hdr
; /* swap header */
53 void *signature_page
;/* buffer with swap header */
55 char *devname
; /* device or file name */
56 const char *lockmode
; /* as specified by --lock */
57 struct stat devstat
; /* stat() result */
58 int fd
; /* swap file descriptor */
60 unsigned long long npages
; /* number of pages */
61 unsigned long nbadpages
; /* number of bad pages */
63 int user_pagesize
; /* --pagesize */
64 int pagesize
; /* final pagesize used for the header */
66 char *opt_label
; /* LABEL as specified on command line */
67 unsigned char *uuid
; /* UUID parsed by libbuuid */
69 unsigned int check
:1, /* --check */
70 force
:1; /* --force */
73 static void init_signature_page(struct mkswap_control
*ctl
)
75 const int kernel_pagesize
= getpagesize();
77 if (ctl
->user_pagesize
) {
78 if (ctl
->user_pagesize
< 0 || !is_power_of_2(ctl
->user_pagesize
) ||
79 (size_t) ctl
->user_pagesize
< sizeof(struct swap_header_v1_2
) + 10)
81 _("Bad user-specified page size %u"),
83 if (ctl
->user_pagesize
!= kernel_pagesize
)
84 warnx(_("Using user-specified page size %d, "
85 "instead of the system value %d"),
86 ctl
->user_pagesize
, kernel_pagesize
);
87 ctl
->pagesize
= ctl
->user_pagesize
;
89 ctl
->pagesize
= kernel_pagesize
;
91 ctl
->signature_page
= xcalloc(1, ctl
->pagesize
);
92 ctl
->hdr
= (struct swap_header_v1_2
*) ctl
->signature_page
;
95 static void deinit_signature_page(struct mkswap_control
*ctl
)
97 free(ctl
->signature_page
);
100 ctl
->signature_page
= NULL
;
103 static void set_signature(const struct mkswap_control
*ctl
)
105 char *sp
= (char *) ctl
->signature_page
;
108 memcpy(sp
+ ctl
->pagesize
- SWAP_SIGNATURE_SZ
, SWAP_SIGNATURE
, SWAP_SIGNATURE_SZ
);
111 static void set_uuid_and_label(const struct mkswap_control
*ctl
)
118 memcpy(ctl
->hdr
->uuid
, ctl
->uuid
, sizeof(ctl
->hdr
->uuid
));
121 if (ctl
->opt_label
) {
122 xstrncpy(ctl
->hdr
->volume_name
,
123 ctl
->opt_label
, sizeof(ctl
->hdr
->volume_name
));
124 if (strlen(ctl
->opt_label
) > strlen(ctl
->hdr
->volume_name
))
125 warnx(_("Label was truncated."));
129 if (ctl
->uuid
|| ctl
->opt_label
) {
131 printf("LABEL=%s, ", ctl
->hdr
->volume_name
);
133 printf(_("no label, "));
136 char uuid_string
[UUID_STR_LEN
];
137 uuid_unparse(ctl
->uuid
, uuid_string
);
138 printf("UUID=%s\n", uuid_string
);
141 printf(_("no uuid\n"));
145 static void __attribute__((__noreturn__
)) usage(void)
150 " %s [options] device [size]\n"),
151 program_invocation_short_name
);
153 fputs(USAGE_SEPARATOR
, out
);
154 fputs(_("Set up a Linux swap area.\n"), out
);
158 " -c, --check check bad blocks before creating the swap area\n"
159 " -f, --force allow swap size area be larger than device\n"
160 " -p, --pagesize SIZE specify page size in bytes\n"
161 " -L, --label LABEL specify label\n"
162 " -v, --swapversion NUM specify swap-space version number\n"
163 " -U, --uuid UUID specify the uuid to use\n"
166 _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
167 printf(USAGE_HELP_OPTIONS(27));
169 printf(USAGE_MAN_TAIL("mkswap(8)"));
173 static void page_bad(struct mkswap_control
*ctl
, unsigned int page
)
175 const unsigned long max_badpages
=
176 (ctl
->pagesize
- 1024 - 128 * sizeof(int) - 10) / sizeof(int);
178 if (ctl
->nbadpages
== max_badpages
)
179 errx(EXIT_FAILURE
, _("too many bad pages: %lu"), max_badpages
);
181 ctl
->hdr
->badpages
[ctl
->nbadpages
] = page
;
185 static void check_blocks(struct mkswap_control
*ctl
)
187 unsigned int current_page
= 0;
192 assert(ctl
->fd
> -1);
194 buffer
= xmalloc(ctl
->pagesize
);
195 while (current_page
< ctl
->npages
) {
197 off_t offset
= (off_t
) current_page
* ctl
->pagesize
;
199 if (do_seek
&& lseek(ctl
->fd
, offset
, SEEK_SET
) != offset
)
200 errx(EXIT_FAILURE
, _("seek failed in check_blocks"));
202 rc
= read(ctl
->fd
, buffer
, ctl
->pagesize
);
203 do_seek
= (rc
< 0 || rc
!= ctl
->pagesize
);
205 page_bad(ctl
, current_page
);
208 printf(P_("%lu bad page\n", "%lu bad pages\n", ctl
->nbadpages
), ctl
->nbadpages
);
212 /* return size in pages */
213 static unsigned long long get_size(const struct mkswap_control
*ctl
)
216 unsigned long long size
;
218 fd
= open(ctl
->devname
, O_RDONLY
);
220 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
221 if (blkdev_get_size(fd
, &size
) == 0)
222 size
/= ctl
->pagesize
;
229 static blkid_probe
new_prober(const struct mkswap_control
*ctl
)
231 blkid_probe pr
= blkid_new_probe();
233 errx(EXIT_FAILURE
, _("unable to alloc new libblkid probe"));
234 if (blkid_probe_set_device(pr
, ctl
->fd
, 0, 0))
235 errx(EXIT_FAILURE
, _("unable to assign device to libblkid probe"));
240 static void open_device(struct mkswap_control
*ctl
)
243 assert(ctl
->devname
);
245 if (stat(ctl
->devname
, &ctl
->devstat
) < 0)
246 err(EXIT_FAILURE
, _("stat of %s failed"), ctl
->devname
);
247 ctl
->fd
= open_blkdev_or_file(&ctl
->devstat
, ctl
->devname
, O_RDWR
);
249 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
251 if (blkdev_lock(ctl
->fd
, ctl
->devname
, ctl
->lockmode
) != 0)
254 if (ctl
->check
&& S_ISREG(ctl
->devstat
.st_mode
)) {
256 warnx(_("warning: checking bad blocks from swap file is not supported: %s"),
261 static void wipe_device(struct mkswap_control
*ctl
)
266 blkid_probe pr
= NULL
;
269 const char *v
= NULL
;
271 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
272 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
275 pr
= new_prober(ctl
);
276 blkid_probe_enable_partitions(pr
, 1);
277 blkid_probe_enable_superblocks(pr
, 0);
279 if (blkid_do_fullprobe(pr
) == 0 &&
280 blkid_probe_lookup_value(pr
, "PTTYPE", &v
, NULL
) == 0 && v
) {
285 /* don't zap if compiled without libblkid */
294 char buf
[1024] = { '\0' };
296 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
297 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
299 if (write_all(ctl
->fd
, buf
, sizeof(buf
)))
300 errx(EXIT_FAILURE
, _("unable to erase bootbits sectors"));
303 * Wipe rest of the device
306 pr
= new_prober(ctl
);
308 blkid_probe_enable_superblocks(pr
, 1);
309 blkid_probe_enable_partitions(pr
, 0);
310 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_MAGIC
|BLKID_SUBLKS_TYPE
);
312 while (blkid_do_probe(pr
) == 0) {
313 const char *data
= NULL
;
315 if (blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
) == 0 && data
)
316 warnx(_("%s: warning: wiping old %s signature."), ctl
->devname
, data
);
317 blkid_do_wipe(pr
, 0);
321 warnx(_("%s: warning: don't erase bootbits sectors"),
324 fprintf(stderr
, _(" (%s partition table detected). "), type
);
326 fprintf(stderr
, _(" (compiled without libblkid). "));
327 fprintf(stderr
, _("Use -f to force.\n"));
331 blkid_free_probe(pr
);
335 #define SIGNATURE_OFFSET 1024
337 static void write_header_to_device(struct mkswap_control
*ctl
)
340 assert(ctl
->fd
> -1);
341 assert(ctl
->signature_page
);
343 if (lseek(ctl
->fd
, SIGNATURE_OFFSET
, SEEK_SET
) != SIGNATURE_OFFSET
)
344 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
346 if (write_all(ctl
->fd
, (char *) ctl
->signature_page
+ SIGNATURE_OFFSET
,
347 ctl
->pagesize
- SIGNATURE_OFFSET
) == -1)
349 _("%s: unable to write signature page"),
353 int main(int argc
, char **argv
)
355 struct mkswap_control ctl
= { .fd
= -1 };
358 int version
= SWAP_VERSION
;
359 char *block_count
= NULL
, *strsz
= NULL
;
361 const char *opt_uuid
= NULL
;
365 OPT_LOCK
= CHAR_MAX
+ 1,
367 static const struct option longopts
[] = {
368 { "check", no_argument
, NULL
, 'c' },
369 { "force", no_argument
, NULL
, 'f' },
370 { "pagesize", required_argument
, NULL
, 'p' },
371 { "label", required_argument
, NULL
, 'L' },
372 { "swapversion", required_argument
, NULL
, 'v' },
373 { "uuid", required_argument
, NULL
, 'U' },
374 { "version", no_argument
, NULL
, 'V' },
375 { "help", no_argument
, NULL
, 'h' },
376 { "lock", optional_argument
, NULL
, OPT_LOCK
},
380 setlocale(LC_ALL
, "");
381 bindtextdomain(PACKAGE
, LOCALEDIR
);
383 close_stdout_atexit();
385 while((c
= getopt_long(argc
, argv
, "cfp:L:v:U:Vh", longopts
, NULL
)) != -1) {
394 ctl
.user_pagesize
= strtou32_or_err(optarg
, _("parsing page size failed"));
397 ctl
.opt_label
= optarg
;
400 version
= strtos32_or_err(optarg
, _("parsing version number failed"));
401 if (version
!= SWAP_VERSION
)
403 _("swapspace version %d is not supported"), version
);
409 warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"),
410 program_invocation_short_name
);
414 print_version(EXIT_SUCCESS
);
421 ctl
.lockmode
= optarg
;
427 errtryhelp(EXIT_FAILURE
);
432 ctl
.devname
= argv
[optind
++];
434 block_count
= argv
[optind
++];
435 if (optind
!= argc
) {
436 warnx(_("only one device argument is currently supported"));
437 errtryhelp(EXIT_FAILURE
);
442 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
443 errx(EXIT_FAILURE
, _("error: parsing UUID failed"));
445 uuid_generate(uuid_dat
);
449 init_signature_page(&ctl
); /* get pagesize and allocate signature page */
452 warnx(_("error: Nowhere to set up swap on?"));
453 errtryhelp(EXIT_FAILURE
);
456 /* this silly user specified the number of blocks explicitly */
457 uint64_t blks
= strtou64_or_err(block_count
,
458 _("invalid block count argument"));
459 ctl
.npages
= blks
/ (ctl
.pagesize
/ 1024);
465 else if (ctl
.npages
> sz
&& !ctl
.force
)
468 "size %llu KiB is larger than device size %"PRIu64
" KiB"),
469 ctl
.npages
* (ctl
.pagesize
/ 1024), sz
* (ctl
.pagesize
/ 1024));
471 if (ctl
.npages
< MIN_GOODPAGES
)
473 _("error: swap area needs to be at least %ld KiB"),
474 (long)(MIN_GOODPAGES
* ctl
.pagesize
/ 1024));
475 if (ctl
.npages
> UINT32_MAX
) {
476 /* true when swap is bigger than 17.59 terabytes */
477 ctl
.npages
= UINT32_MAX
;
478 warnx(_("warning: truncating swap area to %llu KiB"),
479 ctl
.npages
* ctl
.pagesize
/ 1024);
482 if (is_mounted(ctl
.devname
))
483 errx(EXIT_FAILURE
, _("error: "
484 "%s is mounted; will not make swapspace"),
488 permMask
= S_ISBLK(ctl
.devstat
.st_mode
) ? 07007 : 07077;
489 if ((ctl
.devstat
.st_mode
& permMask
) != 0)
490 warnx(_("%s: insecure permissions %04o, %04o suggested."),
491 ctl
.devname
, ctl
.devstat
.st_mode
& 07777,
493 if (getuid() == 0 && S_ISREG(ctl
.devstat
.st_mode
) && ctl
.devstat
.st_uid
!= 0)
494 warnx(_("%s: insecure file owner %d, 0 (root) suggested."),
495 ctl
.devname
, ctl
.devstat
.st_uid
);
504 ctl
.hdr
->version
= version
;
505 ctl
.hdr
->last_page
= ctl
.npages
- 1;
506 ctl
.hdr
->nr_badpages
= ctl
.nbadpages
;
508 if ((ctl
.npages
- MIN_GOODPAGES
) < ctl
.nbadpages
)
509 errx(EXIT_FAILURE
, _("Unable to set up swap-space: unreadable"));
511 sz
= (ctl
.npages
- ctl
.nbadpages
- 1) * ctl
.pagesize
;
512 strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
| SIZE_SUFFIX_3LETTER
, sz
);
514 printf(_("Setting up swapspace version %d, size = %s (%"PRIu64
" bytes)\n"),
519 set_uuid_and_label(&ctl
);
521 write_header_to_device(&ctl
);
523 deinit_signature_page(&ctl
);
525 #ifdef HAVE_LIBSELINUX
526 if (S_ISREG(ctl
.devstat
.st_mode
) && is_selinux_enabled() > 0) {
527 security_context_t context_string
;
528 security_context_t oldcontext
;
529 context_t newcontext
;
531 if (fgetfilecon(ctl
.fd
, &oldcontext
) < 0) {
532 if (errno
!= ENODATA
)
534 _("%s: unable to obtain selinux file label"),
536 if (matchpathcon(ctl
.devname
, ctl
.devstat
.st_mode
, &oldcontext
))
537 errx(EXIT_FAILURE
, _("unable to matchpathcon()"));
539 if (!(newcontext
= context_new(oldcontext
)))
540 errx(EXIT_FAILURE
, _("unable to create new selinux context"));
541 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
542 errx(EXIT_FAILURE
, _("couldn't compute selinux context"));
544 context_string
= context_str(newcontext
);
546 if (strcmp(context_string
, oldcontext
)!=0) {
547 if (fsetfilecon(ctl
.fd
, context_string
) && errno
!= ENOTSUP
)
548 err(EXIT_FAILURE
, _("unable to relabel %s to %s"),
549 ctl
.devname
, context_string
);
551 context_free(newcontext
);
556 * A subsequent swapon() will fail if the signature
557 * is not actually on disk. (This is a kernel bug.)
558 * The fsync() in close_fd() will take care of writing.
560 if (close_fd(ctl
.fd
) != 0)
561 err(EXIT_FAILURE
, _("write failed"));