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 struct stat devstat
; /* stat() result */
57 int fd
; /* swap file descriptor */
59 unsigned long long npages
; /* number of pages */
60 unsigned long nbadpages
; /* number of bad pages */
62 int user_pagesize
; /* --pagesize */
63 int pagesize
; /* final pagesize used for the header */
65 char *opt_label
; /* LABEL as specified on command line */
66 unsigned char *uuid
; /* UUID parsed by libbuuid */
68 unsigned int check
:1, /* --check */
69 force
:1; /* --force */
72 static void init_signature_page(struct mkswap_control
*ctl
)
74 const int kernel_pagesize
= getpagesize();
76 if (ctl
->user_pagesize
) {
77 if (ctl
->user_pagesize
< 0 || !is_power_of_2(ctl
->user_pagesize
) ||
78 (size_t) ctl
->user_pagesize
< sizeof(struct swap_header_v1_2
) + 10)
80 _("Bad user-specified page size %u"),
82 if (ctl
->user_pagesize
!= kernel_pagesize
)
83 warnx(_("Using user-specified page size %d, "
84 "instead of the system value %d"),
85 ctl
->user_pagesize
, kernel_pagesize
);
86 ctl
->pagesize
= ctl
->user_pagesize
;
88 ctl
->pagesize
= kernel_pagesize
;
90 ctl
->signature_page
= xcalloc(1, ctl
->pagesize
);
91 ctl
->hdr
= (struct swap_header_v1_2
*) ctl
->signature_page
;
94 static void deinit_signature_page(struct mkswap_control
*ctl
)
96 free(ctl
->signature_page
);
99 ctl
->signature_page
= NULL
;
102 static void set_signature(const struct mkswap_control
*ctl
)
104 char *sp
= (char *) ctl
->signature_page
;
107 memcpy(sp
+ ctl
->pagesize
- SWAP_SIGNATURE_SZ
, SWAP_SIGNATURE
, SWAP_SIGNATURE_SZ
);
110 static void set_uuid_and_label(const struct mkswap_control
*ctl
)
117 memcpy(ctl
->hdr
->uuid
, ctl
->uuid
, sizeof(ctl
->hdr
->uuid
));
120 if (ctl
->opt_label
) {
121 xstrncpy(ctl
->hdr
->volume_name
,
122 ctl
->opt_label
, sizeof(ctl
->hdr
->volume_name
));
123 if (strlen(ctl
->opt_label
) > strlen(ctl
->hdr
->volume_name
))
124 warnx(_("Label was truncated."));
128 if (ctl
->uuid
|| ctl
->opt_label
) {
130 printf("LABEL=%s, ", ctl
->hdr
->volume_name
);
132 printf(_("no label, "));
135 char uuid_string
[UUID_STR_LEN
];
136 uuid_unparse(ctl
->uuid
, uuid_string
);
137 printf("UUID=%s\n", uuid_string
);
140 printf(_("no uuid\n"));
144 static void __attribute__((__noreturn__
)) usage(void)
149 " %s [options] device [size]\n"),
150 program_invocation_short_name
);
152 fputs(USAGE_SEPARATOR
, out
);
153 fputs(_("Set up a Linux swap area.\n"), out
);
157 " -c, --check check bad blocks before creating the swap area\n"
158 " -f, --force allow swap size area be larger than device\n"
159 " -p, --pagesize SIZE specify page size in bytes\n"
160 " -L, --label LABEL specify label\n"
161 " -v, --swapversion NUM specify swap-space version number\n"
162 " -U, --uuid UUID specify the uuid to use\n"
164 printf(USAGE_HELP_OPTIONS(27));
166 printf(USAGE_MAN_TAIL("mkswap(8)"));
170 static void page_bad(struct mkswap_control
*ctl
, unsigned int page
)
172 const unsigned long max_badpages
=
173 (ctl
->pagesize
- 1024 - 128 * sizeof(int) - 10) / sizeof(int);
175 if (ctl
->nbadpages
== max_badpages
)
176 errx(EXIT_FAILURE
, _("too many bad pages: %lu"), max_badpages
);
178 ctl
->hdr
->badpages
[ctl
->nbadpages
] = page
;
182 static void check_blocks(struct mkswap_control
*ctl
)
184 unsigned int current_page
= 0;
189 assert(ctl
->fd
> -1);
191 buffer
= xmalloc(ctl
->pagesize
);
192 while (current_page
< ctl
->npages
) {
194 off_t offset
= (off_t
) current_page
* ctl
->pagesize
;
196 if (do_seek
&& lseek(ctl
->fd
, offset
, SEEK_SET
) != offset
)
197 errx(EXIT_FAILURE
, _("seek failed in check_blocks"));
199 rc
= read(ctl
->fd
, buffer
, ctl
->pagesize
);
200 do_seek
= (rc
< 0 || rc
!= ctl
->pagesize
);
202 page_bad(ctl
, current_page
);
205 printf(P_("%lu bad page\n", "%lu bad pages\n", ctl
->nbadpages
), ctl
->nbadpages
);
209 /* return size in pages */
210 static unsigned long long get_size(const struct mkswap_control
*ctl
)
213 unsigned long long size
;
215 fd
= open(ctl
->devname
, O_RDONLY
);
217 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
218 if (blkdev_get_size(fd
, &size
) == 0)
219 size
/= ctl
->pagesize
;
226 static blkid_probe
new_prober(const struct mkswap_control
*ctl
)
228 blkid_probe pr
= blkid_new_probe();
230 errx(EXIT_FAILURE
, _("unable to alloc new libblkid probe"));
231 if (blkid_probe_set_device(pr
, ctl
->fd
, 0, 0))
232 errx(EXIT_FAILURE
, _("unable to assign device to libblkid probe"));
237 static void open_device(struct mkswap_control
*ctl
)
240 assert(ctl
->devname
);
242 if (stat(ctl
->devname
, &ctl
->devstat
) < 0)
243 err(EXIT_FAILURE
, _("stat of %s failed"), ctl
->devname
);
244 ctl
->fd
= open_blkdev_or_file(&ctl
->devstat
, ctl
->devname
, O_RDWR
);
246 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
247 if (ctl
->check
&& S_ISREG(ctl
->devstat
.st_mode
)) {
249 warnx(_("warning: checking bad blocks from swap file is not supported: %s"),
254 static void wipe_device(struct mkswap_control
*ctl
)
259 blkid_probe pr
= NULL
;
262 const char *v
= NULL
;
264 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
265 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
268 pr
= new_prober(ctl
);
269 blkid_probe_enable_partitions(pr
, 1);
270 blkid_probe_enable_superblocks(pr
, 0);
272 if (blkid_do_fullprobe(pr
) == 0 &&
273 blkid_probe_lookup_value(pr
, "PTTYPE", &v
, NULL
) == 0 && v
) {
278 /* don't zap if compiled without libblkid */
287 char buf
[1024] = { '\0' };
289 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
290 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
292 if (write_all(ctl
->fd
, buf
, sizeof(buf
)))
293 errx(EXIT_FAILURE
, _("unable to erase bootbits sectors"));
296 * Wipe rest of the device
299 pr
= new_prober(ctl
);
301 blkid_probe_enable_superblocks(pr
, 1);
302 blkid_probe_enable_partitions(pr
, 0);
303 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_MAGIC
|BLKID_SUBLKS_TYPE
);
305 while (blkid_do_probe(pr
) == 0) {
306 const char *data
= NULL
;
308 if (blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
) == 0 && data
)
309 warnx(_("%s: warning: wiping old %s signature."), ctl
->devname
, data
);
310 blkid_do_wipe(pr
, 0);
314 warnx(_("%s: warning: don't erase bootbits sectors"),
317 fprintf(stderr
, _(" (%s partition table detected). "), type
);
319 fprintf(stderr
, _(" (compiled without libblkid). "));
320 fprintf(stderr
, _("Use -f to force.\n"));
324 blkid_free_probe(pr
);
328 #define SIGNATURE_OFFSET 1024
330 static void write_header_to_device(struct mkswap_control
*ctl
)
333 assert(ctl
->fd
> -1);
334 assert(ctl
->signature_page
);
336 if (lseek(ctl
->fd
, SIGNATURE_OFFSET
, SEEK_SET
) != SIGNATURE_OFFSET
)
337 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
339 if (write_all(ctl
->fd
, (char *) ctl
->signature_page
+ SIGNATURE_OFFSET
,
340 ctl
->pagesize
- SIGNATURE_OFFSET
) == -1)
342 _("%s: unable to write signature page"),
346 int main(int argc
, char **argv
)
348 struct mkswap_control ctl
= { .fd
= -1 };
351 int version
= SWAP_VERSION
;
352 char *block_count
= NULL
, *strsz
= NULL
;
354 const char *opt_uuid
= NULL
;
357 static const struct option longopts
[] = {
358 { "check", no_argument
, NULL
, 'c' },
359 { "force", no_argument
, NULL
, 'f' },
360 { "pagesize", required_argument
, NULL
, 'p' },
361 { "label", required_argument
, NULL
, 'L' },
362 { "swapversion", required_argument
, NULL
, 'v' },
363 { "uuid", required_argument
, NULL
, 'U' },
364 { "version", no_argument
, NULL
, 'V' },
365 { "help", no_argument
, NULL
, 'h' },
369 setlocale(LC_ALL
, "");
370 bindtextdomain(PACKAGE
, LOCALEDIR
);
372 close_stdout_atexit();
374 while((c
= getopt_long(argc
, argv
, "cfp:L:v:U:Vh", longopts
, NULL
)) != -1) {
383 ctl
.user_pagesize
= strtou32_or_err(optarg
, _("parsing page size failed"));
386 ctl
.opt_label
= optarg
;
389 version
= strtos32_or_err(optarg
, _("parsing version number failed"));
390 if (version
!= SWAP_VERSION
)
392 _("swapspace version %d is not supported"), version
);
398 warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"),
399 program_invocation_short_name
);
403 print_version(EXIT_SUCCESS
);
407 errtryhelp(EXIT_FAILURE
);
412 ctl
.devname
= argv
[optind
++];
414 block_count
= argv
[optind
++];
415 if (optind
!= argc
) {
416 warnx(_("only one device argument is currently supported"));
417 errtryhelp(EXIT_FAILURE
);
422 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
423 errx(EXIT_FAILURE
, _("error: parsing UUID failed"));
425 uuid_generate(uuid_dat
);
429 init_signature_page(&ctl
); /* get pagesize and allocate signature page */
432 warnx(_("error: Nowhere to set up swap on?"));
433 errtryhelp(EXIT_FAILURE
);
436 /* this silly user specified the number of blocks explicitly */
437 uint64_t blks
= strtou64_or_err(block_count
,
438 _("invalid block count argument"));
439 ctl
.npages
= blks
/ (ctl
.pagesize
/ 1024);
445 else if (ctl
.npages
> sz
&& !ctl
.force
)
448 "size %llu KiB is larger than device size %"PRIu64
" KiB"),
449 ctl
.npages
* (ctl
.pagesize
/ 1024), sz
* (ctl
.pagesize
/ 1024));
451 if (ctl
.npages
< MIN_GOODPAGES
)
453 _("error: swap area needs to be at least %ld KiB"),
454 (long)(MIN_GOODPAGES
* ctl
.pagesize
/ 1024));
455 if (ctl
.npages
> UINT32_MAX
) {
456 /* true when swap is bigger than 17.59 terabytes */
457 ctl
.npages
= UINT32_MAX
;
458 warnx(_("warning: truncating swap area to %llu KiB"),
459 ctl
.npages
* ctl
.pagesize
/ 1024);
462 if (is_mounted(ctl
.devname
))
463 errx(EXIT_FAILURE
, _("error: "
464 "%s is mounted; will not make swapspace"),
468 permMask
= S_ISBLK(ctl
.devstat
.st_mode
) ? 07007 : 07077;
469 if ((ctl
.devstat
.st_mode
& permMask
) != 0)
470 warnx(_("%s: insecure permissions %04o, %04o suggested."),
471 ctl
.devname
, ctl
.devstat
.st_mode
& 07777,
473 if (getuid() == 0 && S_ISREG(ctl
.devstat
.st_mode
) && ctl
.devstat
.st_uid
!= 0)
474 warnx(_("%s: insecure file owner %d, 0 (root) suggested."),
475 ctl
.devname
, ctl
.devstat
.st_uid
);
484 ctl
.hdr
->version
= version
;
485 ctl
.hdr
->last_page
= ctl
.npages
- 1;
486 ctl
.hdr
->nr_badpages
= ctl
.nbadpages
;
488 if ((ctl
.npages
- MIN_GOODPAGES
) < ctl
.nbadpages
)
489 errx(EXIT_FAILURE
, _("Unable to set up swap-space: unreadable"));
491 sz
= (ctl
.npages
- ctl
.nbadpages
- 1) * ctl
.pagesize
;
492 strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
| SIZE_SUFFIX_3LETTER
, sz
);
494 printf(_("Setting up swapspace version %d, size = %s (%"PRIu64
" bytes)\n"),
499 set_uuid_and_label(&ctl
);
501 write_header_to_device(&ctl
);
503 deinit_signature_page(&ctl
);
505 #ifdef HAVE_LIBSELINUX
506 if (S_ISREG(ctl
.devstat
.st_mode
) && is_selinux_enabled() > 0) {
507 security_context_t context_string
;
508 security_context_t oldcontext
;
509 context_t newcontext
;
511 if (fgetfilecon(ctl
.fd
, &oldcontext
) < 0) {
512 if (errno
!= ENODATA
)
514 _("%s: unable to obtain selinux file label"),
516 if (matchpathcon(ctl
.devname
, ctl
.devstat
.st_mode
, &oldcontext
))
517 errx(EXIT_FAILURE
, _("unable to matchpathcon()"));
519 if (!(newcontext
= context_new(oldcontext
)))
520 errx(EXIT_FAILURE
, _("unable to create new selinux context"));
521 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
522 errx(EXIT_FAILURE
, _("couldn't compute selinux context"));
524 context_string
= context_str(newcontext
);
526 if (strcmp(context_string
, oldcontext
)!=0) {
527 if (fsetfilecon(ctl
.fd
, context_string
) && errno
!= ENOTSUP
)
528 err(EXIT_FAILURE
, _("unable to relabel %s to %s"),
529 ctl
.devname
, context_string
);
531 context_free(newcontext
);
536 * A subsequent swapon() will fail if the signature
537 * is not actually on disk. (This is a kernel bug.)
538 * The fsync() in close_fd() will take care of writing.
540 if (close_fd(ctl
.fd
) != 0)
541 err(EXIT_FAILURE
, _("write failed"));