]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
1 | /* |
2 | * mkswap.c - set up a linux swap device | |
3 | * | |
8591859c KZ |
4 | * Copyright (C) 1991 Linus Torvalds |
5 | * 20.12.91 - time began. Got VM working yesterday by doing this by hand. | |
3e18b040 | 6 | * |
8591859c KZ |
7 | * Copyright (C) 1999 Jakub Jelinek <jj@ultra.linux.cz> |
8 | * Copyright (C) 2007-2014 Karel Zak <kzak@redhat.com> | |
6dbe3af9 KZ |
9 | */ |
10 | ||
11 | #include <stdio.h> | |
12 | #include <unistd.h> | |
13 | #include <string.h> | |
14 | #include <fcntl.h> | |
15 | #include <stdlib.h> | |
99e6d525 | 16 | #include <limits.h> |
5c36a0eb | 17 | #include <sys/utsname.h> |
6dbe3af9 | 18 | #include <sys/stat.h> |
3e18b040 | 19 | #include <errno.h> |
e079c4e6 | 20 | #include <getopt.h> |
99f78758 | 21 | #include <assert.h> |
3e18b040 KZ |
22 | #ifdef HAVE_LIBSELINUX |
23 | #include <selinux/selinux.h> | |
24 | #include <selinux/context.h> | |
25 | #endif | |
26 | ||
8023c83b | 27 | #include "linux_version.h" |
756bfd01 | 28 | #include "swapheader.h" |
8abcf290 | 29 | #include "strutils.h" |
66ee8158 | 30 | #include "nls.h" |
54e377b3 | 31 | #include "blkdev.h" |
fc68cd49 | 32 | #include "pathnames.h" |
e12c9866 | 33 | #include "all-io.h" |
94a50e28 | 34 | #include "xalloc.h" |
08675263 | 35 | #include "c.h" |
45ca68ec | 36 | #include "closestream.h" |
def478cf | 37 | #include "ismounted.h" |
66ee8158 | 38 | |
766dd757 | 39 | #ifdef HAVE_LIBUUID |
7ee96990 | 40 | # include <uuid.h> |
756bfd01 KZ |
41 | #endif |
42 | ||
64d15476 | 43 | #ifdef HAVE_LIBBLKID |
566f35bc KZ |
44 | # include <blkid.h> |
45 | #endif | |
46 | ||
de3822c3 | 47 | #define MIN_GOODPAGES 10 |
5c36a0eb | 48 | |
3e18b040 KZ |
49 | #define SELINUX_SWAPFILE_TYPE "swapfile_t" |
50 | ||
de3822c3 | 51 | struct mkswap_control { |
99f78758 | 52 | struct swap_header_v1_2 *hdr; /* swap header */ |
8591859c KZ |
53 | void *signature_page;/* buffer with swap header */ |
54 | ||
fabf29f4 KZ |
55 | char *devname; /* device or file name */ |
56 | struct stat devstat; /* stat() result */ | |
57 | int fd; /* swap file descriptor */ | |
8591859c KZ |
58 | |
59 | unsigned long long npages; /* number of pages */ | |
60 | unsigned long nbadpages; /* number of bad pages */ | |
61 | ||
62 | int user_pagesize; /* --pagesize */ | |
63 | int pagesize; /* final pagesize used for the header */ | |
64 | ||
65 | char *opt_label; /* LABEL as specified on command line */ | |
66 | unsigned char *uuid; /* UUID parsed by libbuuid */ | |
67 | ||
68 | unsigned int check:1, /* --check */ | |
69 | force:1; /* --force */ | |
de3822c3 | 70 | }; |
5c36a0eb | 71 | |
99f78758 | 72 | static void init_signature_page(struct mkswap_control *ctl) |
f2704664 | 73 | { |
076ba5a6 | 74 | const int kernel_pagesize = getpagesize(); |
eb63b9b8 | 75 | |
de3822c3 SK |
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) | |
00a7d0d2 | 79 | errx(EXIT_FAILURE, |
076ba5a6 SK |
80 | _("Bad user-specified page size %u"), |
81 | ctl->user_pagesize); | |
82 | if (ctl->user_pagesize != kernel_pagesize) | |
83 | warnx(_("Using user-specified page size %d, " | |
00a7d0d2 | 84 | "instead of the system value %d"), |
de3822c3 | 85 | ctl->pagesize, kernel_pagesize); |
076ba5a6 SK |
86 | ctl->pagesize = ctl->user_pagesize; |
87 | } else | |
88 | ctl->pagesize = kernel_pagesize; | |
99f78758 | 89 | |
fea1cbf7 | 90 | ctl->signature_page = xcalloc(1, ctl->pagesize); |
99f78758 KZ |
91 | ctl->hdr = (struct swap_header_v1_2 *) ctl->signature_page; |
92 | } | |
93 | ||
94 | static void deinit_signature_page(struct mkswap_control *ctl) | |
95 | { | |
96 | free(ctl->signature_page); | |
97 | ||
98 | ctl->hdr = NULL; | |
99 | ctl->signature_page = NULL; | |
5c36a0eb KZ |
100 | } |
101 | ||
3ba01c14 | 102 | static void set_signature(const struct mkswap_control *ctl) |
f2704664 | 103 | { |
de3822c3 | 104 | char *sp = (char *) ctl->signature_page; |
5c36a0eb | 105 | |
fabf29f4 | 106 | assert(sp); |
de3822c3 | 107 | strncpy(sp + ctl->pagesize - SWAP_SIGNATURE_SZ, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ); |
5c36a0eb KZ |
108 | } |
109 | ||
3ba01c14 | 110 | static void set_uuid_and_label(const struct mkswap_control *ctl) |
f2704664 | 111 | { |
99f78758 KZ |
112 | assert(ctl); |
113 | assert(ctl->hdr); | |
756bfd01 | 114 | |
99f78758 | 115 | /* set UUID */ |
de3822c3 | 116 | if (ctl->uuid) |
99f78758 KZ |
117 | memcpy(ctl->hdr->uuid, ctl->uuid, sizeof(ctl->hdr->uuid)); |
118 | ||
119 | /* set LABEL */ | |
de3822c3 | 120 | if (ctl->opt_label) { |
99f78758 KZ |
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)) | |
00a7d0d2 | 124 | warnx(_("Label was truncated.")); |
756bfd01 | 125 | } |
99f78758 | 126 | |
9e930041 | 127 | /* report results */ |
de3822c3 SK |
128 | if (ctl->uuid || ctl->opt_label) { |
129 | if (ctl->opt_label) | |
99f78758 | 130 | printf("LABEL=%s, ", ctl->hdr->volume_name); |
756bfd01 KZ |
131 | else |
132 | printf(_("no label, ")); | |
766dd757 | 133 | #ifdef HAVE_LIBUUID |
de3822c3 | 134 | if (ctl->uuid) { |
756bfd01 | 135 | char uuid_string[37]; |
de3822c3 | 136 | uuid_unparse(ctl->uuid, uuid_string); |
756bfd01 KZ |
137 | printf("UUID=%s\n", uuid_string); |
138 | } else | |
139 | #endif | |
140 | printf(_("no uuid\n")); | |
141 | } | |
142 | } | |
143 | ||
e079c4e6 SK |
144 | static void __attribute__ ((__noreturn__)) usage(FILE *out) |
145 | { | |
146 | fprintf(out, | |
147 | _("\nUsage:\n" | |
148 | " %s [options] device [size]\n"), | |
00a7d0d2 | 149 | program_invocation_short_name); |
e079c4e6 | 150 | |
451dbcfa BS |
151 | fputs(USAGE_SEPARATOR, out); |
152 | fputs(_("Set up a Linux swap area.\n"), out); | |
153 | ||
e079c4e6 SK |
154 | fprintf(out, _( |
155 | "\nOptions:\n" | |
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")); | |
164 | ||
165 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
eb63b9b8 | 166 | } |
6dbe3af9 | 167 | |
99f78758 | 168 | static void page_bad(struct mkswap_control *ctl, unsigned int page) |
f2704664 | 169 | { |
99f78758 KZ |
170 | const unsigned long max_badpages = |
171 | (ctl->pagesize - 1024 - 128 * sizeof(int) - 10) / sizeof(int); | |
3e16599a | 172 | |
8591859c | 173 | if (ctl->nbadpages == max_badpages) |
d68f402c | 174 | errx(EXIT_FAILURE, _("too many bad pages: %lu"), max_badpages); |
99f78758 KZ |
175 | |
176 | ctl->hdr->badpages[ctl->nbadpages] = page; | |
8591859c | 177 | ctl->nbadpages++; |
5c36a0eb KZ |
178 | } |
179 | ||
99f78758 | 180 | static void check_blocks(struct mkswap_control *ctl) |
f2704664 | 181 | { |
d68f402c | 182 | unsigned int current_page = 0; |
6dbe3af9 | 183 | int do_seek = 1; |
5c36a0eb | 184 | char *buffer; |
6dbe3af9 | 185 | |
99f78758 KZ |
186 | assert(ctl); |
187 | assert(ctl->fd > -1); | |
188 | ||
de3822c3 | 189 | buffer = xmalloc(ctl->pagesize); |
8591859c | 190 | while (current_page < ctl->npages) { |
f3b16286 KZ |
191 | ssize_t rc; |
192 | ||
de3822c3 SK |
193 | if (do_seek && lseek(ctl->fd, current_page * ctl->pagesize, SEEK_SET) != |
194 | current_page * ctl->pagesize) | |
00a7d0d2 | 195 | errx(EXIT_FAILURE, _("seek failed in check_blocks")); |
f3b16286 | 196 | |
de3822c3 SK |
197 | rc = read(ctl->fd, buffer, ctl->pagesize); |
198 | do_seek = (rc < 0 || rc != ctl->pagesize); | |
f3b16286 | 199 | if (do_seek) |
de3822c3 | 200 | page_bad(ctl, current_page); |
adda7f7e | 201 | current_page++; |
6dbe3af9 | 202 | } |
8591859c | 203 | printf(P_("%lu bad page\n", "%lu bad pages\n", ctl->nbadpages), ctl->nbadpages); |
3216beb0 | 204 | free(buffer); |
6dbe3af9 KZ |
205 | } |
206 | ||
99e6d525 | 207 | /* return size in pages */ |
fabf29f4 | 208 | static unsigned long long get_size(const struct mkswap_control *ctl) |
f2704664 SK |
209 | { |
210 | int fd; | |
54e377b3 | 211 | unsigned long long size; |
6dbe3af9 | 212 | |
fabf29f4 | 213 | fd = open(ctl->devname, O_RDONLY); |
3d5c8ba1 | 214 | if (fd < 0) |
fabf29f4 | 215 | err(EXIT_FAILURE, _("cannot open %s"), ctl->devname); |
54e377b3 | 216 | if (blkdev_get_size(fd, &size) == 0) |
de3822c3 | 217 | size /= ctl->pagesize; |
54e377b3 | 218 | |
6dbe3af9 KZ |
219 | close(fd); |
220 | return size; | |
221 | } | |
222 | ||
979f1dd5 | 223 | #ifdef HAVE_LIBBLKID |
fabf29f4 | 224 | static blkid_probe new_prober(const struct mkswap_control *ctl) |
979f1dd5 KZ |
225 | { |
226 | blkid_probe pr = blkid_new_probe(); | |
227 | if (!pr) | |
228 | errx(EXIT_FAILURE, _("unable to alloc new libblkid probe")); | |
6af18227 | 229 | if (blkid_probe_set_device(pr, ctl->fd, 0, 0)) |
979f1dd5 KZ |
230 | errx(EXIT_FAILURE, _("unable to assign device to libblkid probe")); |
231 | return pr; | |
232 | } | |
233 | #endif | |
234 | ||
fabf29f4 KZ |
235 | static void open_device(struct mkswap_control *ctl) |
236 | { | |
237 | assert(ctl); | |
238 | assert(ctl->devname); | |
239 | ||
240 | if (stat(ctl->devname, &ctl->devstat) < 0) | |
fc14ceba | 241 | err(EXIT_FAILURE, _("stat of %s failed"), ctl->devname); |
80c320fa | 242 | ctl->fd = open_blkdev_or_file(&ctl->devstat, ctl->devname, O_RDWR); |
fabf29f4 KZ |
243 | if (ctl->fd < 0) |
244 | err(EXIT_FAILURE, _("cannot open %s"), ctl->devname); | |
80c320fa SK |
245 | if (ctl->check && S_ISREG(ctl->devstat.st_mode)) { |
246 | ctl->check = 0; | |
247 | warnx(_("warning: checking bad blocks from swap file is not supported: %s"), | |
248 | ctl->devname); | |
249 | } | |
fabf29f4 KZ |
250 | } |
251 | ||
252 | static void wipe_device(struct mkswap_control *ctl) | |
ff3bed80 | 253 | { |
566f35bc | 254 | char *type = NULL; |
ff3bed80 | 255 | int zap = 1; |
9206b238 | 256 | #ifdef HAVE_LIBBLKID |
979f1dd5 | 257 | blkid_probe pr = NULL; |
9206b238 | 258 | #endif |
6af18227 SK |
259 | if (!ctl->force) { |
260 | if (lseek(ctl->fd, 0, SEEK_SET) != 0) | |
00a7d0d2 | 261 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); |
ff3bed80 | 262 | |
64d15476 | 263 | #ifdef HAVE_LIBBLKID |
6af18227 | 264 | pr = new_prober(ctl); |
c1f1b301 MB |
265 | blkid_probe_enable_partitions(pr, 1); |
266 | blkid_probe_enable_superblocks(pr, 0); | |
267 | ||
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); | |
ff3bed80 | 272 | zap = 0; |
566f35bc | 273 | } |
c1f1b301 MB |
274 | #else |
275 | /* don't zap if compiled without libblkid */ | |
276 | zap = 0; | |
277 | #endif | |
ff3bed80 KZ |
278 | } |
279 | ||
280 | if (zap) { | |
979f1dd5 | 281 | /* |
d68f402c | 282 | * Wipe bootbits |
979f1dd5 | 283 | */ |
d68f402c | 284 | char buf[1024] = { '\0' }; |
ff3bed80 | 285 | |
6af18227 | 286 | if (lseek(ctl->fd, 0, SEEK_SET) != 0) |
00a7d0d2 | 287 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); |
ff3bed80 | 288 | |
6af18227 | 289 | if (write_all(ctl->fd, buf, sizeof(buf))) |
00a7d0d2 | 290 | errx(EXIT_FAILURE, _("unable to erase bootbits sectors")); |
979f1dd5 KZ |
291 | #ifdef HAVE_LIBBLKID |
292 | /* | |
293 | * Wipe rest of the device | |
294 | */ | |
295 | if (!pr) | |
6af18227 | 296 | pr = new_prober(ctl); |
979f1dd5 KZ |
297 | |
298 | blkid_probe_enable_superblocks(pr, 1); | |
299 | blkid_probe_enable_partitions(pr, 0); | |
c1f1b301 | 300 | blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_TYPE); |
979f1dd5 | 301 | |
c1f1b301 | 302 | while (blkid_do_probe(pr) == 0) { |
a0b42dc3 KZ |
303 | const char *data = NULL; |
304 | ||
c1f1b301 | 305 | if (blkid_probe_lookup_value(pr, "TYPE", &data, NULL) == 0 && data) |
fabf29f4 | 306 | warnx(_("%s: warning: wiping old %s signature."), ctl->devname, data); |
979f1dd5 | 307 | blkid_do_wipe(pr, 0); |
c1f1b301 | 308 | } |
979f1dd5 KZ |
309 | #endif |
310 | } else { | |
311 | warnx(_("%s: warning: don't erase bootbits sectors"), | |
fabf29f4 | 312 | ctl->devname); |
979f1dd5 KZ |
313 | if (type) |
314 | fprintf(stderr, _(" (%s partition table detected). "), type); | |
979f1dd5 KZ |
315 | else |
316 | fprintf(stderr, _(" (compiled without libblkid). ")); | |
8c219bf4 | 317 | fprintf(stderr, _("Use -f to force.\n")); |
ff3bed80 | 318 | } |
acec6eec | 319 | free(type); |
979f1dd5 KZ |
320 | #ifdef HAVE_LIBBLKID |
321 | blkid_free_probe(pr); | |
322 | #endif | |
ff3bed80 KZ |
323 | } |
324 | ||
3ba01c14 KZ |
325 | #define SIGNATURE_OFFSET 1024 |
326 | ||
327 | static void write_header_to_device(struct mkswap_control *ctl) | |
328 | { | |
329 | assert(ctl); | |
330 | assert(ctl->fd > -1); | |
331 | assert(ctl->signature_page); | |
332 | ||
333 | if (lseek(ctl->fd, SIGNATURE_OFFSET, SEEK_SET) != SIGNATURE_OFFSET) | |
334 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); | |
335 | ||
336 | if (write_all(ctl->fd, (char *) ctl->signature_page + SIGNATURE_OFFSET, | |
337 | ctl->pagesize - SIGNATURE_OFFSET) == -1) | |
338 | err(EXIT_FAILURE, | |
339 | _("%s: unable to write signature page"), | |
340 | ctl->devname); | |
341 | } | |
342 | ||
9a83b03c KZ |
343 | int main(int argc, char **argv) |
344 | { | |
99f78758 | 345 | struct mkswap_control ctl = { .fd = -1 }; |
cc706d9f | 346 | int c, permMask; |
9a83b03c | 347 | uint64_t sz; |
8a101b14 | 348 | int version = SWAP_VERSION; |
9a83b03c | 349 | char *block_count = NULL, *strsz = NULL; |
766dd757 | 350 | #ifdef HAVE_LIBUUID |
7b241808 | 351 | const char *opt_uuid = NULL; |
756bfd01 KZ |
352 | uuid_t uuid_dat; |
353 | #endif | |
6c7d5ae9 | 354 | static const struct option longopts[] = { |
e079c4e6 SK |
355 | { "check", no_argument, 0, 'c' }, |
356 | { "force", no_argument, 0, 'f' }, | |
357 | { "pagesize", required_argument, 0, 'p' }, | |
358 | { "label", required_argument, 0, 'L' }, | |
359 | { "swapversion", required_argument, 0, 'v' }, | |
360 | { "uuid", required_argument, 0, 'U' }, | |
361 | { "version", no_argument, 0, 'V' }, | |
362 | { "help", no_argument, 0, 'h' }, | |
363 | { NULL, 0, 0, 0 } | |
364 | }; | |
eb63b9b8 | 365 | |
7eda085c KZ |
366 | setlocale(LC_ALL, ""); |
367 | bindtextdomain(PACKAGE, LOCALEDIR); | |
368 | textdomain(PACKAGE); | |
45ca68ec | 369 | atexit(close_stdout); |
5c36a0eb | 370 | |
e079c4e6 SK |
371 | while((c = getopt_long(argc, argv, "cfp:L:v:U:Vh", longopts, NULL)) != -1) { |
372 | switch (c) { | |
373 | case 'c': | |
de3822c3 | 374 | ctl.check = 1; |
e079c4e6 SK |
375 | break; |
376 | case 'f': | |
de3822c3 | 377 | ctl.force = 1; |
e079c4e6 SK |
378 | break; |
379 | case 'p': | |
de3822c3 | 380 | ctl.user_pagesize = strtou32_or_err(optarg, _("parsing page size failed")); |
e079c4e6 SK |
381 | break; |
382 | case 'L': | |
de3822c3 | 383 | ctl.opt_label = optarg; |
e079c4e6 SK |
384 | break; |
385 | case 'v': | |
8c219bf4 | 386 | version = strtos32_or_err(optarg, _("parsing version number failed")); |
de3822c3 SK |
387 | if (version != SWAP_VERSION) |
388 | errx(EXIT_FAILURE, | |
389 | _("swapspace version %d is not supported"), version); | |
e079c4e6 SK |
390 | break; |
391 | case 'U': | |
93bf0f28 | 392 | #ifdef HAVE_LIBUUID |
e079c4e6 | 393 | opt_uuid = optarg; |
93bf0f28 | 394 | #else |
4e096801 | 395 | warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"), |
e079c4e6 | 396 | program_invocation_short_name); |
93bf0f28 | 397 | #endif |
e079c4e6 SK |
398 | break; |
399 | case 'V': | |
33fb5cfd | 400 | printf(UTIL_LINUX_VERSION); |
e079c4e6 SK |
401 | exit(EXIT_SUCCESS); |
402 | case 'h': | |
403 | usage(stdout); | |
404 | default: | |
677ec86c | 405 | errtryhelp(EXIT_FAILURE); |
e079c4e6 SK |
406 | } |
407 | } | |
3ba01c14 | 408 | |
e079c4e6 | 409 | if (optind < argc) |
fabf29f4 | 410 | ctl.devname = argv[optind++]; |
e079c4e6 SK |
411 | if (optind < argc) |
412 | block_count = argv[optind++]; | |
413 | if (optind != argc) { | |
8c219bf4 | 414 | warnx(_("only one device argument is currently supported")); |
e079c4e6 | 415 | usage(stderr); |
6dbe3af9 | 416 | } |
eb63b9b8 | 417 | |
766dd757 | 418 | #ifdef HAVE_LIBUUID |
93bf0f28 MS |
419 | if(opt_uuid) { |
420 | if (uuid_parse(opt_uuid, uuid_dat) != 0) | |
8c219bf4 | 421 | errx(EXIT_FAILURE, _("error: parsing UUID failed")); |
93bf0f28 MS |
422 | } else |
423 | uuid_generate(uuid_dat); | |
de3822c3 | 424 | ctl.uuid = uuid_dat; |
756bfd01 KZ |
425 | #endif |
426 | ||
de3822c3 | 427 | init_signature_page(&ctl); /* get pagesize and allocate signature page */ |
eb63b9b8 | 428 | |
fabf29f4 | 429 | if (!ctl.devname) { |
00a7d0d2 | 430 | warnx(_("error: Nowhere to set up swap on?")); |
e079c4e6 | 431 | usage(stderr); |
fd6b7a7f | 432 | } |
eb63b9b8 | 433 | if (block_count) { |
20543e61 | 434 | /* this silly user specified the number of blocks explicitly */ |
33fb5cfd KZ |
435 | uint64_t blks = strtou64_or_err(block_count, |
436 | _("invalid block count argument")); | |
8591859c | 437 | ctl.npages = blks / (ctl.pagesize / 1024); |
eb63b9b8 | 438 | } |
3ba01c14 | 439 | |
de3822c3 | 440 | sz = get_size(&ctl); |
8591859c KZ |
441 | if (!ctl.npages) |
442 | ctl.npages = sz; | |
443 | else if (ctl.npages > sz && !ctl.force) | |
00a7d0d2 SK |
444 | errx(EXIT_FAILURE, |
445 | _("error: " | |
fdbd7bb9 | 446 | "size %llu KiB is larger than device size %"PRIu64" KiB"), |
8591859c | 447 | ctl.npages * (ctl.pagesize / 1024), sz * (ctl.pagesize / 1024)); |
5c36a0eb | 448 | |
8591859c | 449 | if (ctl.npages < MIN_GOODPAGES) |
793a05f8 SK |
450 | errx(EXIT_FAILURE, |
451 | _("error: swap area needs to be at least %ld KiB"), | |
de3822c3 | 452 | (long)(MIN_GOODPAGES * ctl.pagesize / 1024)); |
8591859c | 453 | if (ctl.npages > UINT32_MAX) { |
a1466ab2 | 454 | /* true when swap is bigger than 17.59 terabytes */ |
8591859c | 455 | ctl.npages = UINT32_MAX; |
00a7d0d2 | 456 | warnx(_("warning: truncating swap area to %llu KiB"), |
8591859c | 457 | ctl.npages * ctl.pagesize / 1024); |
726f69e2 | 458 | } |
5c36a0eb | 459 | |
fabf29f4 | 460 | if (is_mounted(ctl.devname)) |
dceb1f22 | 461 | errx(EXIT_FAILURE, _("error: " |
4e096801 | 462 | "%s is mounted; will not make swapspace"), |
fabf29f4 KZ |
463 | ctl.devname); |
464 | ||
465 | open_device(&ctl); | |
cc706d9f WR |
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, | |
470 | ~permMask & 0666); | |
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); | |
474 | ||
dceb1f22 | 475 | |
de3822c3 SK |
476 | if (ctl.check) |
477 | check_blocks(&ctl); | |
4c85aa3a | 478 | |
6af18227 | 479 | wipe_device(&ctl); |
ff3bed80 | 480 | |
99f78758 | 481 | assert(ctl.hdr); |
de3822c3 | 482 | ctl.hdr->version = version; |
8591859c KZ |
483 | ctl.hdr->last_page = ctl.npages - 1; |
484 | ctl.hdr->nr_badpages = ctl.nbadpages; | |
5c36a0eb | 485 | |
8591859c | 486 | if ((ctl.npages - MIN_GOODPAGES) < ctl.nbadpages) |
00a7d0d2 | 487 | errx(EXIT_FAILURE, _("Unable to set up swap-space: unreadable")); |
4c85aa3a | 488 | |
9a83b03c KZ |
489 | sz = (ctl.npages - ctl.nbadpages - 1) * ctl.pagesize; |
490 | strsz = size_to_human_string(SIZE_SUFFIX_SPACE | SIZE_SUFFIX_3LETTER, sz); | |
491 | ||
fdbd7bb9 | 492 | printf(_("Setting up swapspace version %d, size = %s (%"PRIu64" bytes)\n"), |
9a83b03c | 493 | version, strsz, sz); |
acec6eec | 494 | free(strsz); |
5c36a0eb | 495 | |
3ba01c14 KZ |
496 | set_signature(&ctl); |
497 | set_uuid_and_label(&ctl); | |
756bfd01 | 498 | |
3ba01c14 | 499 | write_header_to_device(&ctl); |
99f78758 KZ |
500 | |
501 | deinit_signature_page(&ctl); | |
502 | ||
3e18b040 | 503 | #ifdef HAVE_LIBSELINUX |
fabf29f4 | 504 | if (S_ISREG(ctl.devstat.st_mode) && is_selinux_enabled() > 0) { |
3e18b040 KZ |
505 | security_context_t context_string; |
506 | security_context_t oldcontext; | |
507 | context_t newcontext; | |
508 | ||
de3822c3 | 509 | if (fgetfilecon(ctl.fd, &oldcontext) < 0) { |
00a7d0d2 SK |
510 | if (errno != ENODATA) |
511 | err(EXIT_FAILURE, | |
8d1b0fe2 | 512 | _("%s: unable to obtain selinux file label"), |
fabf29f4 KZ |
513 | ctl.devname); |
514 | if (matchpathcon(ctl.devname, ctl.devstat.st_mode, &oldcontext)) | |
00a7d0d2 | 515 | errx(EXIT_FAILURE, _("unable to matchpathcon()")); |
3e18b040 KZ |
516 | } |
517 | if (!(newcontext = context_new(oldcontext))) | |
00a7d0d2 | 518 | errx(EXIT_FAILURE, _("unable to create new selinux context")); |
3e18b040 | 519 | if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE)) |
00a7d0d2 | 520 | errx(EXIT_FAILURE, _("couldn't compute selinux context")); |
3e18b040 KZ |
521 | |
522 | context_string = context_str(newcontext); | |
523 | ||
524 | if (strcmp(context_string, oldcontext)!=0) { | |
d97dc0ee | 525 | if (fsetfilecon(ctl.fd, context_string) && errno != ENOTSUP) |
00a7d0d2 | 526 | err(EXIT_FAILURE, _("unable to relabel %s to %s"), |
fabf29f4 | 527 | ctl.devname, context_string); |
3e18b040 KZ |
528 | } |
529 | context_free(newcontext); | |
530 | freecon(oldcontext); | |
531 | } | |
532 | #endif | |
833b7e0d SK |
533 | /* |
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. | |
537 | */ | |
de3822c3 | 538 | if (close_fd(ctl.fd) != 0) |
833b7e0d | 539 | err(EXIT_FAILURE, _("write failed")); |
a4d3e778 | 540 | return EXIT_SUCCESS; |
6dbe3af9 | 541 | } |