]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/mkswap.c
cfdisk: ask y/n before wipe
[thirdparty/util-linux.git] / disk-utils / mkswap.c
1 /*
2 * mkswap.c - set up a linux swap device
3 *
4 * Copyright (C) 1991 Linus Torvalds
5 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
6 *
7 * Copyright (C) 1999 Jakub Jelinek <jj@ultra.linux.cz>
8 * Copyright (C) 2007-2014 Karel Zak <kzak@redhat.com>
9 */
10
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <limits.h>
17 #include <sys/utsname.h>
18 #include <sys/stat.h>
19 #include <sys/ioctl.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <assert.h>
23 #ifdef HAVE_LIBSELINUX
24 # include <selinux/selinux.h>
25 # include <selinux/context.h>
26 # include "selinux-utils.h"
27 #endif
28 #ifdef HAVE_LINUX_FIEMAP_H
29 # include <linux/fs.h>
30 # include <linux/fiemap.h>
31 #endif
32
33 #include "linux_version.h"
34 #include "swapheader.h"
35 #include "strutils.h"
36 #include "nls.h"
37 #include "blkdev.h"
38 #include "pathnames.h"
39 #include "all-io.h"
40 #include "xalloc.h"
41 #include "c.h"
42 #include "closestream.h"
43 #include "ismounted.h"
44 #include "optutils.h"
45 #include "bitops.h"
46
47 #ifdef HAVE_LIBUUID
48 # include <uuid.h>
49 #endif
50
51 #ifdef HAVE_LIBBLKID
52 # include <blkid.h>
53 #endif
54
55 #define MIN_GOODPAGES 10
56
57 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
58
59 enum ENDIANNESS {
60 ENDIANNESS_NATIVE,
61 ENDIANNESS_LITTLE,
62 ENDIANNESS_BIG,
63 };
64
65 struct mkswap_control {
66 struct swap_header_v1_2 *hdr; /* swap header */
67 void *signature_page;/* buffer with swap header */
68
69 char *devname; /* device or file name */
70 const char *lockmode; /* as specified by --lock */
71 struct stat devstat; /* stat() result */
72 int fd; /* swap file descriptor */
73
74 unsigned long long npages; /* number of pages */
75 unsigned long nbadpages; /* number of bad pages */
76
77 int user_pagesize; /* --pagesize */
78 int pagesize; /* final pagesize used for the header */
79
80 char *opt_label; /* LABEL as specified on command line */
81 unsigned char *uuid; /* UUID parsed by libbuuid */
82
83 size_t nbad_extents;
84
85 enum ENDIANNESS endianness;
86
87 unsigned int check:1, /* --check */
88 verbose:1, /* --verbose */
89 quiet:1, /* --quiet */
90 force:1; /* --force */
91 };
92
93 static uint32_t cpu32_to_endianness(uint32_t v, enum ENDIANNESS e)
94 {
95 switch (e) {
96 case ENDIANNESS_NATIVE: return v;
97 case ENDIANNESS_LITTLE: return cpu_to_le32(v);
98 case ENDIANNESS_BIG: return cpu_to_be32(v);
99 }
100 abort();
101 }
102
103 static void init_signature_page(struct mkswap_control *ctl)
104 {
105 const int kernel_pagesize = getpagesize();
106
107 if (ctl->user_pagesize) {
108 if (ctl->user_pagesize < 0 || !is_power_of_2(ctl->user_pagesize) ||
109 (size_t) ctl->user_pagesize < sizeof(struct swap_header_v1_2) + 10)
110 errx(EXIT_FAILURE,
111 _("Bad user-specified page size %u"),
112 ctl->user_pagesize);
113 if (!ctl->quiet && ctl->user_pagesize != kernel_pagesize)
114 warnx(_("Using user-specified page size %d, "
115 "instead of the system value %d"),
116 ctl->user_pagesize, kernel_pagesize);
117 ctl->pagesize = ctl->user_pagesize;
118 } else
119 ctl->pagesize = kernel_pagesize;
120
121 ctl->signature_page = xcalloc(1, ctl->pagesize);
122 ctl->hdr = (struct swap_header_v1_2 *) ctl->signature_page;
123 }
124
125 static void deinit_signature_page(struct mkswap_control *ctl)
126 {
127 free(ctl->signature_page);
128
129 ctl->hdr = NULL;
130 ctl->signature_page = NULL;
131 }
132
133 static void set_signature(const struct mkswap_control *ctl)
134 {
135 char *sp = (char *) ctl->signature_page;
136
137 assert(sp);
138 memcpy(sp + ctl->pagesize - SWAP_SIGNATURE_SZ, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ);
139 }
140
141 static void set_uuid_and_label(const struct mkswap_control *ctl)
142 {
143 assert(ctl);
144 assert(ctl->hdr);
145
146 /* set UUID */
147 if (ctl->uuid)
148 memcpy(ctl->hdr->uuid, ctl->uuid, sizeof(ctl->hdr->uuid));
149
150 /* set LABEL */
151 if (ctl->opt_label) {
152 xstrncpy(ctl->hdr->volume_name,
153 ctl->opt_label, sizeof(ctl->hdr->volume_name));
154 if (!ctl->quiet
155 && strlen(ctl->opt_label) > strlen(ctl->hdr->volume_name))
156 warnx(_("Label was truncated."));
157 }
158
159 /* report results */
160 if (!ctl->quiet && (ctl->uuid || ctl->opt_label)) {
161 if (ctl->opt_label)
162 printf("LABEL=%s, ", ctl->hdr->volume_name);
163 else
164 printf(_("no label, "));
165 #ifdef HAVE_LIBUUID
166 if (ctl->uuid) {
167 char uuid_string[UUID_STR_LEN];
168 uuid_unparse(ctl->uuid, uuid_string);
169 printf("UUID=%s\n", uuid_string);
170 } else
171 #endif
172 printf(_("no uuid\n"));
173 }
174 }
175
176 static void __attribute__((__noreturn__)) usage(void)
177 {
178 FILE *out = stdout;
179
180 fputs(USAGE_HEADER, out);
181 fprintf(out, _(" %s [options] device [size]\n"), program_invocation_short_name);
182
183 fputs(USAGE_SEPARATOR, out);
184 fputs(_("Set up a Linux swap area.\n"), out);
185
186 fputs(USAGE_OPTIONS, out);
187 fputs(_(" -c, --check check bad blocks before creating the swap area\n"), out);
188 fputs(_(" -f, --force allow swap size area be larger than device\n"), out);
189 fputs(_(" -q, --quiet suppress output and warning messages\n"), out);
190 fputs(_(" -p, --pagesize SIZE specify page size in bytes\n"), out);
191 fputs(_(" -L, --label LABEL specify label\n"), out);
192 fputs(_(" -v, --swapversion NUM specify swap-space version number\n"), out);
193 fputs(_(" -U, --uuid UUID specify the uuid to use\n"), out);
194 fprintf(out,
195 _(" -e, --endianness=<value> specify the endianness to use "
196 "(%s, %s or %s)\n"), "native", "little", "big");
197 fputs(_(" --verbose verbose output\n"), out);
198
199 fprintf(out,
200 _(" --lock[=<mode>] use exclusive device lock (%s, %s or %s)\n"), "yes", "no", "nonblock");
201
202 printf(USAGE_HELP_OPTIONS(27));
203
204 printf(USAGE_MAN_TAIL("mkswap(8)"));
205 exit(EXIT_SUCCESS);
206 }
207
208 static void page_bad(struct mkswap_control *ctl, unsigned int page)
209 {
210 const unsigned long max_badpages =
211 (ctl->pagesize - 1024 - 128 * sizeof(int) - 10) / sizeof(int);
212
213 if (ctl->nbadpages == max_badpages)
214 errx(EXIT_FAILURE, _("too many bad pages: %lu"), max_badpages);
215
216 ctl->hdr->badpages[ctl->nbadpages] = page;
217 ctl->nbadpages++;
218 }
219
220 static void check_blocks(struct mkswap_control *ctl)
221 {
222 unsigned int current_page = 0;
223 int do_seek = 1;
224 char *buffer;
225
226 assert(ctl);
227 assert(ctl->fd > -1);
228
229 buffer = xmalloc(ctl->pagesize);
230 while (current_page < ctl->npages) {
231 ssize_t rc;
232 off_t offset = (off_t) current_page * ctl->pagesize;
233
234 if (do_seek && lseek(ctl->fd, offset, SEEK_SET) != offset)
235 errx(EXIT_FAILURE, _("seek failed in check_blocks"));
236
237 rc = read(ctl->fd, buffer, ctl->pagesize);
238 do_seek = (rc < 0 || rc != ctl->pagesize);
239 if (do_seek)
240 page_bad(ctl, current_page);
241 current_page++;
242 }
243
244 if (!ctl->quiet)
245 printf(P_("%lu bad page\n", "%lu bad pages\n", ctl->nbadpages), ctl->nbadpages);
246 free(buffer);
247 }
248
249
250 #ifdef HAVE_LINUX_FIEMAP_H
251 static void warn_extent(struct mkswap_control *ctl, const char *msg, uint64_t off)
252 {
253 if (ctl->nbad_extents == 0) {
254 fputc('\n', stderr);
255 fprintf(stderr, _(
256
257 "mkswap: %s contains holes or other unsupported extents.\n"
258 " This swap file can be rejected by kernel on swap activation!\n"),
259 ctl->devname);
260
261 if (ctl->verbose)
262 fputc('\n', stderr);
263 else
264 fprintf(stderr, _(
265 " Use --verbose for more details.\n"));
266
267 }
268 if (ctl->verbose) {
269 fputs(" - ", stderr);
270 fprintf(stderr, msg, off);
271 fputc('\n', stderr);
272 }
273 ctl->nbad_extents++;
274 }
275
276 static void check_extents(struct mkswap_control *ctl)
277 {
278 char buf[BUFSIZ] = { 0 };
279 struct fiemap *fiemap = (struct fiemap *) buf;
280 int last = 0;
281 uint64_t last_logical = 0;
282
283 memset(fiemap, 0, sizeof(struct fiemap));
284
285 do {
286 int rc;
287 size_t n, i;
288
289 fiemap->fm_length = ~0ULL;
290 fiemap->fm_flags = FIEMAP_FLAG_SYNC;
291 fiemap->fm_extent_count =
292 (sizeof(buf) - sizeof(*fiemap)) / sizeof(struct fiemap_extent);
293
294 rc = ioctl(ctl->fd, FS_IOC_FIEMAP, (unsigned long) fiemap);
295 if (rc < 0)
296 return;
297
298 n = fiemap->fm_mapped_extents;
299 if (n == 0)
300 break;
301
302 for (i = 0; i < n; i++) {
303 struct fiemap_extent *e = &fiemap->fm_extents[i];
304
305 if (e->fe_logical > last_logical)
306 warn_extent(ctl, _("hole detected at offset %ju"),
307 (uintmax_t) last_logical);
308
309 last_logical = (e->fe_logical + e->fe_length);
310
311 if (e->fe_flags & FIEMAP_EXTENT_LAST)
312 last = 1;
313 if (e->fe_flags & FIEMAP_EXTENT_DATA_INLINE)
314 warn_extent(ctl, _("data inline extent at offset %ju"),
315 (uintmax_t) e->fe_logical);
316 if (e->fe_flags & FIEMAP_EXTENT_SHARED)
317 warn_extent(ctl, _("shared extent at offset %ju"),
318 (uintmax_t) e->fe_logical);
319 if (e->fe_flags & FIEMAP_EXTENT_DELALLOC)
320 warn_extent(ctl, _("unallocated extent at offset %ju"),
321 (uintmax_t) e->fe_logical);
322
323 if (!ctl->verbose && ctl->nbad_extents)
324 goto done;
325 }
326 fiemap->fm_start = fiemap->fm_extents[n - 1].fe_logical
327 + fiemap->fm_extents[n - 1].fe_length;
328 } while (last == 0);
329
330 if (last_logical < (uint64_t) ctl->devstat.st_size)
331 warn_extent(ctl, _("hole detected at offset %ju"),
332 (uintmax_t) last_logical);
333 done:
334 if (ctl->nbad_extents)
335 fputc('\n', stderr);
336 }
337 #endif /* HAVE_LINUX_FIEMAP_H */
338
339 /* return size in pages */
340 static unsigned long long get_size(const struct mkswap_control *ctl)
341 {
342 int fd;
343 unsigned long long size;
344
345 fd = open(ctl->devname, O_RDONLY);
346 if (fd < 0)
347 err(EXIT_FAILURE, _("cannot open %s"), ctl->devname);
348 if (blkdev_get_size(fd, &size) < 0)
349 err(EXIT_FAILURE, _("cannot determine size of %s"), ctl->devname);
350 size /= ctl->pagesize;
351
352 close(fd);
353 return size;
354 }
355
356 #ifdef HAVE_LIBBLKID
357 static blkid_probe new_prober(const struct mkswap_control *ctl)
358 {
359 blkid_probe pr = blkid_new_probe();
360 if (!pr)
361 errx(EXIT_FAILURE, _("unable to alloc new libblkid probe"));
362 if (blkid_probe_set_device(pr, ctl->fd, 0, 0))
363 errx(EXIT_FAILURE, _("unable to assign device to libblkid probe"));
364 return pr;
365 }
366 #endif
367
368 static void open_device(struct mkswap_control *ctl)
369 {
370 assert(ctl);
371 assert(ctl->devname);
372
373 if (stat(ctl->devname, &ctl->devstat) < 0)
374 err(EXIT_FAILURE, _("stat of %s failed"), ctl->devname);
375 ctl->fd = open_blkdev_or_file(&ctl->devstat, ctl->devname, O_RDWR);
376 if (ctl->fd < 0)
377 err(EXIT_FAILURE, _("cannot open %s"), ctl->devname);
378
379 if (blkdev_lock(ctl->fd, ctl->devname, ctl->lockmode) != 0)
380 exit(EXIT_FAILURE);
381
382 if (ctl->check && S_ISREG(ctl->devstat.st_mode)) {
383 ctl->check = 0;
384 if (!ctl->quiet)
385 warnx(_("warning: checking bad blocks from swap file is not supported: %s"),
386 ctl->devname);
387 }
388 }
389
390 static void wipe_device(struct mkswap_control *ctl)
391 {
392 char *type = NULL;
393 int zap = 1;
394 #ifdef HAVE_LIBBLKID
395 blkid_probe pr = NULL;
396 const char *v = NULL;
397 #endif
398 if (!ctl->force) {
399 if (lseek(ctl->fd, 0, SEEK_SET) != 0)
400 errx(EXIT_FAILURE, _("unable to rewind swap-device"));
401
402 #ifdef HAVE_LIBBLKID
403 pr = new_prober(ctl);
404 blkid_probe_enable_partitions(pr, 1);
405 blkid_probe_enable_superblocks(pr, 0);
406
407 if (blkid_do_fullprobe(pr) == 0 &&
408 blkid_probe_lookup_value(pr, "PTTYPE", &v, NULL) == 0 && v) {
409 type = xstrdup(v);
410 zap = 0;
411 }
412 #else
413 /* don't zap if compiled without libblkid */
414 zap = 0;
415 #endif
416 }
417
418 if (zap) {
419 /*
420 * Wipe bootbits
421 */
422 char buf[1024] = { '\0' };
423
424 if (lseek(ctl->fd, 0, SEEK_SET) != 0)
425 errx(EXIT_FAILURE, _("unable to rewind swap-device"));
426
427 if (write_all(ctl->fd, buf, sizeof(buf)))
428 errx(EXIT_FAILURE, _("unable to erase bootbits sectors"));
429 #ifdef HAVE_LIBBLKID
430 /*
431 * Wipe rest of the device
432 */
433 if (!pr)
434 pr = new_prober(ctl);
435
436 blkid_probe_enable_superblocks(pr, 1);
437 blkid_probe_enable_partitions(pr, 0);
438 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_TYPE);
439
440 while (blkid_do_probe(pr) == 0) {
441 const char *data = NULL;
442
443 if (!ctl->quiet
444 && blkid_probe_lookup_value(pr, "TYPE", &data, NULL) == 0 && data)
445 warnx(_("%s: warning: wiping old %s signature."), ctl->devname, data);
446 blkid_do_wipe(pr, 0);
447 }
448 #endif
449 } else if (!ctl->quiet) {
450 warnx(_("%s: warning: don't erase bootbits sectors"),
451 ctl->devname);
452 if (type)
453 fprintf(stderr, _(" (%s partition table detected). "), type);
454 else
455 fprintf(stderr, _(" (compiled without libblkid). "));
456 fprintf(stderr, _("Use -f to force.\n"));
457 }
458 free(type);
459 #ifdef HAVE_LIBBLKID
460 blkid_free_probe(pr);
461 #endif
462 }
463
464 #define SIGNATURE_OFFSET 1024
465
466 static void write_header_to_device(struct mkswap_control *ctl)
467 {
468 assert(ctl);
469 assert(ctl->fd > -1);
470 assert(ctl->signature_page);
471
472 if (lseek(ctl->fd, SIGNATURE_OFFSET, SEEK_SET) != SIGNATURE_OFFSET)
473 errx(EXIT_FAILURE, _("unable to rewind swap-device"));
474
475 if (write_all(ctl->fd, (char *) ctl->signature_page + SIGNATURE_OFFSET,
476 ctl->pagesize - SIGNATURE_OFFSET) == -1)
477 err(EXIT_FAILURE,
478 _("%s: unable to write signature page"),
479 ctl->devname);
480 }
481
482 int main(int argc, char **argv)
483 {
484 struct mkswap_control ctl = { .fd = -1, .endianness = ENDIANNESS_NATIVE };
485 int c, permMask;
486 uint64_t sz;
487 int version = SWAP_VERSION;
488 char *block_count = NULL, *strsz = NULL;
489 #ifdef HAVE_LIBUUID
490 const char *opt_uuid = NULL;
491 uuid_t uuid_dat;
492 #endif
493 enum {
494 OPT_LOCK = CHAR_MAX + 1,
495 OPT_VERBOSE
496 };
497 static const struct option longopts[] = {
498 { "check", no_argument, NULL, 'c' },
499 { "force", no_argument, NULL, 'f' },
500 { "quiet", no_argument, NULL, 'q' },
501 { "pagesize", required_argument, NULL, 'p' },
502 { "label", required_argument, NULL, 'L' },
503 { "swapversion", required_argument, NULL, 'v' },
504 { "uuid", required_argument, NULL, 'U' },
505 { "endianness", required_argument, NULL, 'e' },
506 { "version", no_argument, NULL, 'V' },
507 { "help", no_argument, NULL, 'h' },
508 { "lock", optional_argument, NULL, OPT_LOCK },
509 { "verbose", no_argument, NULL, OPT_VERBOSE },
510 { NULL, 0, NULL, 0 }
511 };
512
513 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
514 { 'c', 'q' },
515 { 0 }
516 };
517 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
518
519 setlocale(LC_ALL, "");
520 bindtextdomain(PACKAGE, LOCALEDIR);
521 textdomain(PACKAGE);
522 close_stdout_atexit();
523
524 while((c = getopt_long(argc, argv, "cfp:qL:v:U:e:Vh", longopts, NULL)) != -1) {
525
526 err_exclusive_options(c, longopts, excl, excl_st);
527
528 switch (c) {
529 case 'c':
530 ctl.check = 1;
531 break;
532 case 'f':
533 ctl.force = 1;
534 break;
535 case 'p':
536 ctl.user_pagesize = strtou32_or_err(optarg, _("parsing page size failed"));
537 break;
538 case 'q':
539 ctl.quiet = 1;
540 break;
541 case 'L':
542 ctl.opt_label = optarg;
543 break;
544 case 'v':
545 version = strtos32_or_err(optarg, _("parsing version number failed"));
546 if (version != SWAP_VERSION)
547 errx(EXIT_FAILURE,
548 _("swapspace version %d is not supported"), version);
549 break;
550 case 'U':
551 #ifdef HAVE_LIBUUID
552 opt_uuid = optarg;
553 #else
554 warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"),
555 program_invocation_short_name);
556 #endif
557 break;
558 case 'e':
559 if (strcmp(optarg, "native") == 0) {
560 ctl.endianness = ENDIANNESS_NATIVE;
561 } else if (strcmp(optarg, "little") == 0) {
562 ctl.endianness = ENDIANNESS_LITTLE;
563 } else if (strcmp(optarg, "big") == 0) {
564 ctl.endianness = ENDIANNESS_BIG;
565 } else {
566 errx(EXIT_FAILURE,
567 _("invalid endianness %s is not supported"), optarg);
568 }
569 break;
570 case 'V':
571 print_version(EXIT_SUCCESS);
572 break;
573 case OPT_LOCK:
574 ctl.lockmode = "1";
575 if (optarg) {
576 if (*optarg == '=')
577 optarg++;
578 ctl.lockmode = optarg;
579 }
580 break;
581 case OPT_VERBOSE:
582 ctl.verbose = 1;
583 break;
584 case 'h':
585 usage();
586 default:
587 errtryhelp(EXIT_FAILURE);
588 }
589 }
590
591 if (optind < argc)
592 ctl.devname = argv[optind++];
593 if (optind < argc)
594 block_count = argv[optind++];
595 if (optind != argc) {
596 warnx(_("only one device argument is currently supported"));
597 errtryhelp(EXIT_FAILURE);
598 }
599
600 #ifdef HAVE_LIBUUID
601 if(opt_uuid) {
602 if (strcmp(opt_uuid, "clear") == 0)
603 uuid_clear(uuid_dat);
604 else if (strcmp(opt_uuid, "random") == 0)
605 uuid_generate_random(uuid_dat);
606 else if (strcmp(opt_uuid, "time") == 0)
607 uuid_generate_time(uuid_dat);
608 else if (uuid_parse(opt_uuid, uuid_dat) != 0)
609 errx(EXIT_FAILURE, _("error: parsing UUID failed"));
610 } else
611 uuid_generate(uuid_dat);
612 ctl.uuid = uuid_dat;
613 #endif
614
615 init_signature_page(&ctl); /* get pagesize and allocate signature page */
616
617 if (!ctl.devname) {
618 warnx(_("error: Nowhere to set up swap on?"));
619 errtryhelp(EXIT_FAILURE);
620 }
621 if (block_count) {
622 /* this silly user specified the number of blocks explicitly */
623 uint64_t blks = strtou64_or_err(block_count,
624 _("invalid block count argument"));
625 ctl.npages = blks / (ctl.pagesize / 1024);
626 }
627
628 sz = get_size(&ctl);
629 if (!ctl.npages)
630 ctl.npages = sz;
631 else if (ctl.npages > sz && !ctl.force)
632 errx(EXIT_FAILURE,
633 _("error: "
634 "size %llu KiB is larger than device size %"PRIu64" KiB"),
635 ctl.npages * (ctl.pagesize / 1024), sz * (ctl.pagesize / 1024));
636
637 if (ctl.npages < MIN_GOODPAGES)
638 errx(EXIT_FAILURE,
639 _("error: swap area needs to be at least %ld KiB"),
640 (long)(MIN_GOODPAGES * ctl.pagesize / 1024));
641 if (ctl.npages > UINT32_MAX) {
642 /* true when swap is bigger than 17.59 terabytes */
643 ctl.npages = UINT32_MAX;
644 if (!ctl.quiet)
645 warnx(_("warning: truncating swap area to %llu KiB"),
646 ctl.npages * ctl.pagesize / 1024);
647 }
648
649 if (is_mounted(ctl.devname))
650 errx(EXIT_FAILURE, _("error: "
651 "%s is mounted; will not make swapspace"),
652 ctl.devname);
653
654 open_device(&ctl);
655 permMask = S_ISBLK(ctl.devstat.st_mode) ? 07007 : 07077;
656 if (!ctl.quiet && (ctl.devstat.st_mode & permMask) != 0)
657 warnx(_("%s: insecure permissions %04o, fix with: chmod %04o %s"),
658 ctl.devname, ctl.devstat.st_mode & 07777,
659 ~permMask & 0666, ctl.devname);
660 if (!ctl.quiet
661 && getuid() == 0 && S_ISREG(ctl.devstat.st_mode) && ctl.devstat.st_uid != 0)
662 warnx(_("%s: insecure file owner %d, fix with: chown 0:0 %s"),
663 ctl.devname, ctl.devstat.st_uid, ctl.devname);
664
665
666 if (ctl.check)
667 check_blocks(&ctl);
668 #ifdef HAVE_LINUX_FIEMAP_H
669 if (!ctl.quiet && S_ISREG(ctl.devstat.st_mode))
670 check_extents(&ctl);
671 #endif
672
673 wipe_device(&ctl);
674
675 assert(ctl.hdr);
676 ctl.hdr->version = cpu32_to_endianness(version, ctl.endianness);
677 ctl.hdr->last_page = cpu32_to_endianness(ctl.npages - 1, ctl.endianness);
678 ctl.hdr->nr_badpages = cpu32_to_endianness(ctl.nbadpages, ctl.endianness);
679
680 if ((ctl.npages - MIN_GOODPAGES) < ctl.nbadpages)
681 errx(EXIT_FAILURE, _("Unable to set up swap-space: unreadable"));
682
683 sz = (ctl.npages - ctl.nbadpages - 1) * ctl.pagesize;
684 strsz = size_to_human_string(SIZE_SUFFIX_SPACE | SIZE_SUFFIX_3LETTER, sz);
685
686 if (!ctl.quiet)
687 printf(_("Setting up swapspace version %d, size = %s (%"PRIu64" bytes)\n"),
688 version, strsz, sz);
689 free(strsz);
690
691 set_signature(&ctl);
692 set_uuid_and_label(&ctl);
693
694 write_header_to_device(&ctl);
695
696 deinit_signature_page(&ctl);
697
698 #ifdef HAVE_LIBSELINUX
699 if (S_ISREG(ctl.devstat.st_mode) && is_selinux_enabled() > 0) {
700 const char *context_string;
701 char *oldcontext;
702 context_t newcontext;
703
704 if (fgetfilecon(ctl.fd, &oldcontext) < 0) {
705 if (errno != ENODATA)
706 err(EXIT_FAILURE,
707 _("%s: unable to obtain selinux file label"),
708 ctl.devname);
709 if (ul_selinux_get_default_context(ctl.devname,
710 ctl.devstat.st_mode, &oldcontext))
711 errx(EXIT_FAILURE,
712 _("%s: unable to obtain default selinux file label"),
713 ctl.devname);
714 }
715 if (!(newcontext = context_new(oldcontext)))
716 errx(EXIT_FAILURE, _("unable to create new selinux context"));
717 if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE))
718 errx(EXIT_FAILURE, _("couldn't compute selinux context"));
719
720 context_string = context_str(newcontext);
721
722 if (strcmp(context_string, oldcontext)!=0) {
723 if (fsetfilecon(ctl.fd, context_string) && errno != ENOTSUP)
724 err(EXIT_FAILURE, _("unable to relabel %s to %s"),
725 ctl.devname, context_string);
726 }
727 context_free(newcontext);
728 freecon(oldcontext);
729 }
730 #endif
731 /*
732 * A subsequent swapon() will fail if the signature
733 * is not actually on disk. (This is a kernel bug.)
734 * The fsync() in close_fd() will take care of writing.
735 */
736 if (close_fd(ctl.fd) != 0)
737 err(EXIT_FAILURE, _("write failed"));
738 return EXIT_SUCCESS;
739 }