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
->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
[37];
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(FILE *out
)
148 " %s [options] device [size]\n"),
149 program_invocation_short_name
);
151 fputs(USAGE_SEPARATOR
, out
);
152 fputs(_("Set up a Linux swap area.\n"), out
);
156 " -c, --check check bad blocks before creating the swap area\n"
157 " -f, --force allow swap size area be larger than device\n"
158 " -p, --pagesize SIZE specify page size in bytes\n"
159 " -L, --label LABEL specify label\n"
160 " -v, --swapversion NUM specify swap-space version number\n"
161 " -U, --uuid UUID specify the uuid to use\n"
162 " -V, --version output version information and exit\n"
163 " -h, --help display this help and exit\n\n"));
165 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
168 static void page_bad(struct mkswap_control
*ctl
, unsigned int page
)
170 const unsigned long max_badpages
=
171 (ctl
->pagesize
- 1024 - 128 * sizeof(int) - 10) / sizeof(int);
173 if (ctl
->nbadpages
== max_badpages
)
174 errx(EXIT_FAILURE
, _("too many bad pages: %lu"), max_badpages
);
176 ctl
->hdr
->badpages
[ctl
->nbadpages
] = page
;
180 static void check_blocks(struct mkswap_control
*ctl
)
182 unsigned int current_page
= 0;
187 assert(ctl
->fd
> -1);
189 buffer
= xmalloc(ctl
->pagesize
);
190 while (current_page
< ctl
->npages
) {
193 if (do_seek
&& lseek(ctl
->fd
, current_page
* ctl
->pagesize
, SEEK_SET
) !=
194 current_page
* ctl
->pagesize
)
195 errx(EXIT_FAILURE
, _("seek failed in check_blocks"));
197 rc
= read(ctl
->fd
, buffer
, ctl
->pagesize
);
198 do_seek
= (rc
< 0 || rc
!= ctl
->pagesize
);
200 page_bad(ctl
, current_page
);
203 printf(P_("%lu bad page\n", "%lu bad pages\n", ctl
->nbadpages
), ctl
->nbadpages
);
207 /* return size in pages */
208 static unsigned long long get_size(const struct mkswap_control
*ctl
)
211 unsigned long long size
;
213 fd
= open(ctl
->devname
, O_RDONLY
);
215 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
216 if (blkdev_get_size(fd
, &size
) == 0)
217 size
/= ctl
->pagesize
;
224 static blkid_probe
new_prober(const struct mkswap_control
*ctl
)
226 blkid_probe pr
= blkid_new_probe();
228 errx(EXIT_FAILURE
, _("unable to alloc new libblkid probe"));
229 if (blkid_probe_set_device(pr
, ctl
->fd
, 0, 0))
230 errx(EXIT_FAILURE
, _("unable to assign device to libblkid probe"));
235 static void open_device(struct mkswap_control
*ctl
)
238 assert(ctl
->devname
);
240 if (stat(ctl
->devname
, &ctl
->devstat
) < 0)
241 err(EXIT_FAILURE
, _("stat of %s failed"), ctl
->devname
);
242 ctl
->fd
= open_blkdev_or_file(&ctl
->devstat
, ctl
->devname
, O_RDWR
);
244 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->devname
);
245 if (ctl
->check
&& S_ISREG(ctl
->devstat
.st_mode
)) {
247 warnx(_("warning: checking bad blocks from swap file is not supported: %s"),
252 static void wipe_device(struct mkswap_control
*ctl
)
257 blkid_probe pr
= NULL
;
260 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
261 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
264 pr
= new_prober(ctl
);
265 blkid_probe_enable_partitions(pr
, 1);
266 blkid_probe_enable_superblocks(pr
, 0);
268 if (blkid_do_fullprobe(pr
) == 0 &&
269 blkid_probe_lookup_value(pr
, "PTTYPE",
270 (const char **) &type
, NULL
) == 0 && type
) {
271 type
= xstrdup(type
);
275 /* don't zap if compiled without libblkid */
284 char buf
[1024] = { '\0' };
286 if (lseek(ctl
->fd
, 0, SEEK_SET
) != 0)
287 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
289 if (write_all(ctl
->fd
, buf
, sizeof(buf
)))
290 errx(EXIT_FAILURE
, _("unable to erase bootbits sectors"));
293 * Wipe rest of the device
296 pr
= new_prober(ctl
);
298 blkid_probe_enable_superblocks(pr
, 1);
299 blkid_probe_enable_partitions(pr
, 0);
300 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_MAGIC
|BLKID_SUBLKS_TYPE
);
302 while (blkid_do_probe(pr
) == 0) {
303 const char *data
= NULL
;
305 if (blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
) == 0 && data
)
306 warnx(_("%s: warning: wiping old %s signature."), ctl
->devname
, data
);
307 blkid_do_wipe(pr
, 0);
311 warnx(_("%s: warning: don't erase bootbits sectors"),
314 fprintf(stderr
, _(" (%s partition table detected). "), type
);
316 fprintf(stderr
, _(" (compiled without libblkid). "));
317 fprintf(stderr
, _("Use -f to force.\n"));
321 blkid_free_probe(pr
);
325 #define SIGNATURE_OFFSET 1024
327 static void write_header_to_device(struct mkswap_control
*ctl
)
330 assert(ctl
->fd
> -1);
331 assert(ctl
->signature_page
);
333 if (lseek(ctl
->fd
, SIGNATURE_OFFSET
, SEEK_SET
) != SIGNATURE_OFFSET
)
334 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
336 if (write_all(ctl
->fd
, (char *) ctl
->signature_page
+ SIGNATURE_OFFSET
,
337 ctl
->pagesize
- SIGNATURE_OFFSET
) == -1)
339 _("%s: unable to write signature page"),
343 int main(int argc
, char **argv
)
345 struct mkswap_control ctl
= { .fd
= -1 };
348 int version
= SWAP_VERSION
;
349 char *block_count
= NULL
, *strsz
= NULL
;
351 const char *opt_uuid
= NULL
;
354 static const struct option longopts
[] = {
355 { "check", no_argument
, NULL
, 'c' },
356 { "force", no_argument
, NULL
, 'f' },
357 { "pagesize", required_argument
, NULL
, 'p' },
358 { "label", required_argument
, NULL
, 'L' },
359 { "swapversion", required_argument
, NULL
, 'v' },
360 { "uuid", required_argument
, NULL
, 'U' },
361 { "version", no_argument
, NULL
, 'V' },
362 { "help", no_argument
, NULL
, 'h' },
366 setlocale(LC_ALL
, "");
367 bindtextdomain(PACKAGE
, LOCALEDIR
);
369 atexit(close_stdout
);
371 while((c
= getopt_long(argc
, argv
, "cfp:L:v:U:Vh", longopts
, NULL
)) != -1) {
380 ctl
.user_pagesize
= strtou32_or_err(optarg
, _("parsing page size failed"));
383 ctl
.opt_label
= optarg
;
386 version
= strtos32_or_err(optarg
, _("parsing version number failed"));
387 if (version
!= SWAP_VERSION
)
389 _("swapspace version %d is not supported"), version
);
395 warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"),
396 program_invocation_short_name
);
400 printf(UTIL_LINUX_VERSION
);
405 errtryhelp(EXIT_FAILURE
);
410 ctl
.devname
= argv
[optind
++];
412 block_count
= argv
[optind
++];
413 if (optind
!= argc
) {
414 warnx(_("only one device argument is currently supported"));
420 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
421 errx(EXIT_FAILURE
, _("error: parsing UUID failed"));
423 uuid_generate(uuid_dat
);
427 init_signature_page(&ctl
); /* get pagesize and allocate signature page */
430 warnx(_("error: Nowhere to set up swap on?"));
434 /* this silly user specified the number of blocks explicitly */
435 uint64_t blks
= strtou64_or_err(block_count
,
436 _("invalid block count argument"));
437 ctl
.npages
= blks
/ (ctl
.pagesize
/ 1024);
443 else if (ctl
.npages
> sz
&& !ctl
.force
)
446 "size %llu KiB is larger than device size %"PRIu64
" KiB"),
447 ctl
.npages
* (ctl
.pagesize
/ 1024), sz
* (ctl
.pagesize
/ 1024));
449 if (ctl
.npages
< MIN_GOODPAGES
)
451 _("error: swap area needs to be at least %ld KiB"),
452 (long)(MIN_GOODPAGES
* ctl
.pagesize
/ 1024));
453 if (ctl
.npages
> UINT32_MAX
) {
454 /* true when swap is bigger than 17.59 terabytes */
455 ctl
.npages
= UINT32_MAX
;
456 warnx(_("warning: truncating swap area to %llu KiB"),
457 ctl
.npages
* ctl
.pagesize
/ 1024);
460 if (is_mounted(ctl
.devname
))
461 errx(EXIT_FAILURE
, _("error: "
462 "%s is mounted; will not make swapspace"),
466 permMask
= S_ISBLK(ctl
.devstat
.st_mode
) ? 07007 : 07077;
467 if ((ctl
.devstat
.st_mode
& permMask
) != 0)
468 warnx(_("%s: insecure permissions %04o, %04o suggested."),
469 ctl
.devname
, ctl
.devstat
.st_mode
& 07777,
471 if (getuid() == 0 && S_ISREG(ctl
.devstat
.st_mode
) && ctl
.devstat
.st_uid
!= 0)
472 warnx(_("%s: insecure file owner %d, 0 (root) suggested."),
473 ctl
.devname
, ctl
.devstat
.st_uid
);
482 ctl
.hdr
->version
= version
;
483 ctl
.hdr
->last_page
= ctl
.npages
- 1;
484 ctl
.hdr
->nr_badpages
= ctl
.nbadpages
;
486 if ((ctl
.npages
- MIN_GOODPAGES
) < ctl
.nbadpages
)
487 errx(EXIT_FAILURE
, _("Unable to set up swap-space: unreadable"));
489 sz
= (ctl
.npages
- ctl
.nbadpages
- 1) * ctl
.pagesize
;
490 strsz
= size_to_human_string(SIZE_SUFFIX_SPACE
| SIZE_SUFFIX_3LETTER
, sz
);
492 printf(_("Setting up swapspace version %d, size = %s (%"PRIu64
" bytes)\n"),
497 set_uuid_and_label(&ctl
);
499 write_header_to_device(&ctl
);
501 deinit_signature_page(&ctl
);
503 #ifdef HAVE_LIBSELINUX
504 if (S_ISREG(ctl
.devstat
.st_mode
) && is_selinux_enabled() > 0) {
505 security_context_t context_string
;
506 security_context_t oldcontext
;
507 context_t newcontext
;
509 if (fgetfilecon(ctl
.fd
, &oldcontext
) < 0) {
510 if (errno
!= ENODATA
)
512 _("%s: unable to obtain selinux file label"),
514 if (matchpathcon(ctl
.devname
, ctl
.devstat
.st_mode
, &oldcontext
))
515 errx(EXIT_FAILURE
, _("unable to matchpathcon()"));
517 if (!(newcontext
= context_new(oldcontext
)))
518 errx(EXIT_FAILURE
, _("unable to create new selinux context"));
519 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
520 errx(EXIT_FAILURE
, _("couldn't compute selinux context"));
522 context_string
= context_str(newcontext
);
524 if (strcmp(context_string
, oldcontext
)!=0) {
525 if (fsetfilecon(ctl
.fd
, context_string
) && errno
!= ENOTSUP
)
526 err(EXIT_FAILURE
, _("unable to relabel %s to %s"),
527 ctl
.devname
, context_string
);
529 context_free(newcontext
);
534 * A subsequent swapon() will fail if the signature
535 * is not actually on disk. (This is a kernel bug.)
536 * The fsync() in close_fd() will take care of writing.
538 if (close_fd(ctl
.fd
) != 0)
539 err(EXIT_FAILURE
, _("write failed"));