]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * mkswap.c - set up a linux swap device | |
3 | * | |
4 | * (C) 1991 Linus Torvalds. This file may be redistributed as per | |
5 | * the Linux copyright. | |
6 | */ | |
7 | ||
8 | /* | |
9 | * 20.12.91 - time began. Got VM working yesterday by doing this by hand. | |
10 | * | |
11 | * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks] | |
12 | * | |
13 | * -c for readability checking. (Use it unless you are SURE!) | |
14 | * -vN for swap areas version N. (Only N=0,1 known today.) | |
15 | * -f for forcing swap creation even if it would smash partition table. | |
16 | * | |
17 | * The device may be a block device or an image of one, but this isn't | |
18 | * enforced (but it's not much fun on a character device :-). | |
19 | * | |
20 | * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the | |
21 | * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. | |
22 | * | |
23 | * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. | |
24 | * | |
25 | * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. | |
26 | * V1_MAX_PAGES fixes, jj, 990325. | |
27 | * sparc64 fixes, jj, 000219. | |
28 | * | |
29 | * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> | |
30 | * - added Native Language Support | |
31 | * | |
32 | */ | |
33 | ||
34 | #include <stdio.h> | |
35 | #include <unistd.h> | |
36 | #include <string.h> | |
37 | #include <fcntl.h> | |
38 | #include <stdlib.h> | |
39 | #include <limits.h> | |
40 | #include <mntent.h> | |
41 | #include <sys/utsname.h> | |
42 | #include <sys/stat.h> | |
43 | #include <errno.h> | |
44 | #include <getopt.h> | |
45 | #ifdef HAVE_LIBSELINUX | |
46 | #include <selinux/selinux.h> | |
47 | #include <selinux/context.h> | |
48 | #endif | |
49 | ||
50 | #include "linux_version.h" | |
51 | #include "swapheader.h" | |
52 | #include "strutils.h" | |
53 | #include "nls.h" | |
54 | #include "blkdev.h" | |
55 | #include "pathnames.h" | |
56 | #include "wholedisk.h" | |
57 | #include "all-io.h" | |
58 | #include "xalloc.h" | |
59 | #include "c.h" | |
60 | #include "closestream.h" | |
61 | #include "ismounted.h" | |
62 | ||
63 | #ifdef HAVE_LIBUUID | |
64 | # include <uuid.h> | |
65 | #endif | |
66 | ||
67 | #ifdef HAVE_LIBBLKID | |
68 | # include <blkid.h> | |
69 | #endif | |
70 | ||
71 | static char *device_name = NULL; | |
72 | static int DEV = -1; | |
73 | static unsigned long long PAGES = 0; | |
74 | static unsigned long badpages = 0; | |
75 | static int check = 0; | |
76 | ||
77 | #define SELINUX_SWAPFILE_TYPE "swapfile_t" | |
78 | ||
79 | #ifdef __sparc__ | |
80 | # ifdef __arch64__ | |
81 | # define is_sparc64() 1 | |
82 | # define is_be64() 1 | |
83 | # else /* sparc32 */ | |
84 | static int | |
85 | is_sparc64(void) | |
86 | { | |
87 | struct utsname un; | |
88 | static int sparc64 = -1; | |
89 | ||
90 | if (sparc64 != -1) | |
91 | return sparc64; | |
92 | sparc64 = 0; | |
93 | ||
94 | if (uname(&un) < 0) | |
95 | return 0; | |
96 | if (! strcmp(un.machine, "sparc64")) { | |
97 | sparc64 = 1; | |
98 | return 1; | |
99 | } | |
100 | if (strcmp(un.machine, "sparc")) | |
101 | return 0; /* Should not happen */ | |
102 | ||
103 | #ifdef HAVE_PERSONALITY | |
104 | { | |
105 | extern int personality(unsigned long); | |
106 | int oldpers; | |
107 | #define PERS_LINUX 0x00000000 | |
108 | #define PERS_LINUX_32BIT 0x00800000 | |
109 | #define PERS_LINUX32 0x00000008 | |
110 | ||
111 | oldpers = personality(PERS_LINUX_32BIT); | |
112 | if (oldpers != -1) { | |
113 | if (personality(PERS_LINUX) != -1) { | |
114 | uname(&un); | |
115 | if (! strcmp(un.machine, "sparc64")) { | |
116 | sparc64 = 1; | |
117 | oldpers = PERS_LINUX32; | |
118 | } | |
119 | } | |
120 | personality(oldpers); | |
121 | } | |
122 | } | |
123 | #endif | |
124 | ||
125 | return sparc64; | |
126 | } | |
127 | # define is_be64() is_sparc64() | |
128 | # endif /* sparc32 */ | |
129 | #else /* !sparc */ | |
130 | # define is_be64() 0 | |
131 | #endif | |
132 | ||
133 | /* | |
134 | * The definition of the union swap_header uses the kernel constant PAGE_SIZE. | |
135 | * Unfortunately, on some architectures this depends on the hardware model, and | |
136 | * can only be found at run time -- we use getpagesize(), so that we do not | |
137 | * need separate binaries e.g. for sun4, sun4c/d/m and sun4u. | |
138 | * | |
139 | * Even more unfortunately, getpagesize() does not always return the right | |
140 | * information. For example, libc4, libc5 and glibc 2.0 do not use the system | |
141 | * call but invent a value themselves (EXEC_PAGESIZE or NBPG * CLSIZE or NBPC), | |
142 | * and thus it may happen that e.g. on a sparc kernel PAGE_SIZE=4096 and | |
143 | * getpagesize() returns 8192. | |
144 | * | |
145 | * What to do? Let us allow the user to specify the pagesize explicitly. | |
146 | * | |
147 | */ | |
148 | static unsigned int user_pagesize; | |
149 | static unsigned int pagesize; | |
150 | static unsigned long *signature_page = NULL; | |
151 | ||
152 | static void | |
153 | init_signature_page(void) | |
154 | { | |
155 | ||
156 | unsigned int kernel_pagesize = pagesize = getpagesize(); | |
157 | ||
158 | if (user_pagesize) { | |
159 | if (!is_power_of_2(user_pagesize) || | |
160 | user_pagesize < sizeof(struct swap_header_v1_2) + 10) | |
161 | errx(EXIT_FAILURE, | |
162 | _("Bad user-specified page size %u"), | |
163 | user_pagesize); | |
164 | pagesize = user_pagesize; | |
165 | } | |
166 | ||
167 | if (user_pagesize && user_pagesize != kernel_pagesize) | |
168 | warnx(_("Using user-specified page size %d, " | |
169 | "instead of the system value %d"), | |
170 | pagesize, kernel_pagesize); | |
171 | ||
172 | signature_page = (unsigned long *) xcalloc(1, pagesize); | |
173 | } | |
174 | ||
175 | static void | |
176 | write_signature(char *sig) | |
177 | { | |
178 | char *sp = (char *) signature_page; | |
179 | ||
180 | strncpy(sp + pagesize - 10, sig, 10); | |
181 | } | |
182 | ||
183 | static void | |
184 | write_uuid_and_label(unsigned char *uuid, char *volume_name) | |
185 | { | |
186 | struct swap_header_v1_2 *h; | |
187 | ||
188 | /* Sanity check */ | |
189 | if (sizeof(struct swap_header_v1) != | |
190 | sizeof(struct swap_header_v1_2)) { | |
191 | warnx(_("Bad swap header size, no label written.")); | |
192 | return; | |
193 | } | |
194 | ||
195 | h = (struct swap_header_v1_2 *) signature_page; | |
196 | if (uuid) | |
197 | memcpy(h->uuid, uuid, sizeof(h->uuid)); | |
198 | if (volume_name) { | |
199 | xstrncpy(h->volume_name, volume_name, sizeof(h->volume_name)); | |
200 | if (strlen(volume_name) > strlen(h->volume_name)) | |
201 | warnx(_("Label was truncated.")); | |
202 | } | |
203 | if (uuid || volume_name) { | |
204 | if (volume_name) | |
205 | printf("LABEL=%s, ", h->volume_name); | |
206 | else | |
207 | printf(_("no label, ")); | |
208 | #ifdef HAVE_LIBUUID | |
209 | if (uuid) { | |
210 | char uuid_string[37]; | |
211 | uuid_unparse(uuid, uuid_string); | |
212 | printf("UUID=%s\n", uuid_string); | |
213 | } else | |
214 | #endif | |
215 | printf(_("no uuid\n")); | |
216 | } | |
217 | } | |
218 | ||
219 | /* | |
220 | * Find out what the maximum amount of swap space is that the kernel will | |
221 | * handle. This wouldn't matter if the kernel just used as much of the | |
222 | * swap space as it can handle, but until 2.3.4 it would return an error | |
223 | * to swapon() if the swapspace was too large. | |
224 | */ | |
225 | /* Before 2.2.0pre9 */ | |
226 | #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1) | |
227 | /* Since 2.2.0pre9, before 2.3.4: | |
228 | error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL)) | |
229 | with variations on | |
230 | #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) | |
231 | #define SWP_OFFSET(entry) ((entry) >> 8) | |
232 | on the various architectures. Below the result - yuk. | |
233 | ||
234 | Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2 | |
235 | i386 2^12 o<<8 e>>8 1<<24 1<<19 | |
236 | mips 2^12 o<<15 e>>15 1<<17 1<<19 | |
237 | alpha 2^13 o<<40 e>>40 1<<24 1<<18 | |
238 | m68k 2^12 o<<12 e>>12 1<<20 1<<19 | |
239 | sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18} | |
240 | sparc64 2^13 o<<13 e>>13 1<<51 1<<18 | |
241 | ppc 2^12 o<<8 e>>8 1<<24 1<<19 | |
242 | armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16} | |
243 | armv 2^12 o<<9 e>>9 1<<23 1<<19 | |
244 | ||
245 | assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere. | |
246 | ||
247 | The bad part is that we need to know this since the kernel will | |
248 | refuse a swap space if it is too large. | |
249 | */ | |
250 | /* patch from jj - why does this differ from the above? */ | |
251 | /* 32bit kernels have a second limitation of 2GB, sparc64 is limited by | |
252 | the size of virtual address space allocation for vmalloc */ | |
253 | #if defined(__alpha__) | |
254 | #define V1_MAX_PAGES ((1 << 24) - 1) | |
255 | #elif defined(__mips__) | |
256 | #define V1_MAX_PAGES ((1 << 17) - 1) | |
257 | #elif defined(__sparc__) | |
258 | #define V1_MAX_PAGES (is_sparc64() ? ((3 << 29) - 1) : ((1 << 18) - 1)) | |
259 | #elif defined(__ia64__) | |
260 | /* | |
261 | * The actual size will depend on the amount of virtual address space | |
262 | * available to vmalloc the swap map. | |
263 | */ | |
264 | #define V1_MAX_PAGES ((1UL << 54) - 1) | |
265 | #else | |
266 | #define V1_MAX_PAGES V1_OLD_MAX_PAGES | |
267 | #endif | |
268 | /* man page now says: | |
269 | The maximum useful size of a swap area now depends on the architecture. | |
270 | It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, | |
271 | 128GB on alpha and 3TB on sparc64. | |
272 | */ | |
273 | ||
274 | #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) | |
275 | #define MIN_GOODPAGES 10 | |
276 | ||
277 | static void __attribute__ ((__noreturn__)) usage(FILE *out) | |
278 | { | |
279 | fprintf(out, | |
280 | _("\nUsage:\n" | |
281 | " %s [options] device [size]\n"), | |
282 | program_invocation_short_name); | |
283 | ||
284 | fprintf(out, _( | |
285 | "\nOptions:\n" | |
286 | " -c, --check check bad blocks before creating the swap area\n" | |
287 | " -f, --force allow swap size area be larger than device\n" | |
288 | " -p, --pagesize SIZE specify page size in bytes\n" | |
289 | " -L, --label LABEL specify label\n" | |
290 | " -v, --swapversion NUM specify swap-space version number\n" | |
291 | " -U, --uuid UUID specify the uuid to use\n" | |
292 | " -V, --version output version information and exit\n" | |
293 | " -h, --help display this help and exit\n\n")); | |
294 | ||
295 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
296 | } | |
297 | ||
298 | static void | |
299 | page_bad(int page) | |
300 | { | |
301 | struct swap_header_v1_2 *p = (struct swap_header_v1_2 *) signature_page; | |
302 | ||
303 | if (badpages == MAX_BADPAGES) | |
304 | errx(EXIT_FAILURE, _("too many bad pages")); | |
305 | p->badpages[badpages] = page; | |
306 | badpages++; | |
307 | } | |
308 | ||
309 | static void | |
310 | check_blocks(void) | |
311 | { | |
312 | unsigned int current_page; | |
313 | int do_seek = 1; | |
314 | char *buffer; | |
315 | ||
316 | buffer = xmalloc(pagesize); | |
317 | current_page = 0; | |
318 | while (current_page < PAGES) { | |
319 | ||
320 | ssize_t rc; | |
321 | ||
322 | if (do_seek && lseek(DEV,current_page*pagesize,SEEK_SET) != | |
323 | current_page*pagesize) | |
324 | errx(EXIT_FAILURE, _("seek failed in check_blocks")); | |
325 | ||
326 | rc = read(DEV, buffer, pagesize); | |
327 | do_seek = (rc < 0 || (size_t) rc != pagesize); | |
328 | if (do_seek) | |
329 | page_bad(current_page); | |
330 | current_page++; | |
331 | } | |
332 | printf(P_("%lu bad page\n", "%lu bad pages\n", badpages), badpages); | |
333 | free(buffer); | |
334 | } | |
335 | ||
336 | /* return size in pages */ | |
337 | static unsigned long long | |
338 | get_size(const char *file) | |
339 | { | |
340 | int fd; | |
341 | unsigned long long size; | |
342 | ||
343 | fd = open(file, O_RDONLY); | |
344 | if (fd < 0) { | |
345 | perror(file); | |
346 | exit(EXIT_FAILURE); | |
347 | } | |
348 | if (blkdev_get_size(fd, &size) == 0) | |
349 | size /= pagesize; | |
350 | ||
351 | close(fd); | |
352 | return size; | |
353 | } | |
354 | ||
355 | #ifdef HAVE_LIBBLKID | |
356 | static blkid_probe | |
357 | new_prober(int fd) | |
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, fd, 0, 0)) | |
363 | errx(EXIT_FAILURE, _("unable to assign device to libblkid probe")); | |
364 | return pr; | |
365 | } | |
366 | #endif | |
367 | ||
368 | static void | |
369 | wipe_device(int fd, const char *devname, int force) | |
370 | { | |
371 | char *type = NULL; | |
372 | int zap = 1; | |
373 | #ifdef HAVE_LIBBLKID | |
374 | blkid_probe pr = NULL; | |
375 | #endif | |
376 | if (!force) { | |
377 | if (lseek(fd, 0, SEEK_SET) != 0) | |
378 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); | |
379 | ||
380 | #ifdef HAVE_LIBBLKID | |
381 | pr = new_prober(fd); | |
382 | blkid_probe_enable_partitions(pr, 1); | |
383 | blkid_probe_enable_superblocks(pr, 0); | |
384 | ||
385 | if (blkid_do_fullprobe(pr) == 0 && | |
386 | blkid_probe_lookup_value(pr, "PTTYPE", | |
387 | (const char **) &type, NULL) == 0 && type) { | |
388 | type = xstrdup(type); | |
389 | zap = 0; | |
390 | } | |
391 | #else | |
392 | /* don't zap if compiled without libblkid */ | |
393 | zap = 0; | |
394 | #endif | |
395 | } | |
396 | ||
397 | if (zap) { | |
398 | /* | |
399 | * Wipe boodbits | |
400 | */ | |
401 | char buf[1024]; | |
402 | const char *data = NULL; | |
403 | ||
404 | if (lseek(fd, 0, SEEK_SET) != 0) | |
405 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); | |
406 | ||
407 | memset(buf, 0, sizeof(buf)); | |
408 | if (write_all(fd, buf, sizeof(buf))) | |
409 | errx(EXIT_FAILURE, _("unable to erase bootbits sectors")); | |
410 | #ifdef HAVE_LIBBLKID | |
411 | /* | |
412 | * Wipe rest of the device | |
413 | */ | |
414 | if (!pr) | |
415 | pr = new_prober(fd); | |
416 | ||
417 | blkid_probe_enable_superblocks(pr, 1); | |
418 | blkid_probe_enable_partitions(pr, 0); | |
419 | blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_TYPE); | |
420 | ||
421 | while (blkid_do_probe(pr) == 0) { | |
422 | if (blkid_probe_lookup_value(pr, "TYPE", &data, NULL) == 0 && data) | |
423 | warnx(_("%s: warning: wiping old %s signature."), devname, data); | |
424 | blkid_do_wipe(pr, 0); | |
425 | } | |
426 | #endif | |
427 | } else { | |
428 | warnx(_("%s: warning: don't erase bootbits sectors"), | |
429 | devname); | |
430 | if (type) | |
431 | fprintf(stderr, _(" (%s partition table detected). "), type); | |
432 | else | |
433 | fprintf(stderr, _(" (compiled without libblkid). ")); | |
434 | fprintf(stderr, _("Use -f to force.\n")); | |
435 | } | |
436 | #ifdef HAVE_LIBBLKID | |
437 | blkid_free_probe(pr); | |
438 | #endif | |
439 | } | |
440 | ||
441 | int | |
442 | main(int argc, char **argv) { | |
443 | struct stat statbuf; | |
444 | struct swap_header_v1_2 *hdr; | |
445 | int c; | |
446 | unsigned long long maxpages; | |
447 | unsigned long long goodpages; | |
448 | unsigned long long sz; | |
449 | off_t offset; | |
450 | int force = 0; | |
451 | int version = 1; | |
452 | char *block_count = 0; | |
453 | char *opt_label = NULL; | |
454 | unsigned char *uuid = NULL; | |
455 | #ifdef HAVE_LIBUUID | |
456 | const char *opt_uuid = NULL; | |
457 | uuid_t uuid_dat; | |
458 | #endif | |
459 | static const struct option longopts[] = { | |
460 | { "check", no_argument, 0, 'c' }, | |
461 | { "force", no_argument, 0, 'f' }, | |
462 | { "pagesize", required_argument, 0, 'p' }, | |
463 | { "label", required_argument, 0, 'L' }, | |
464 | { "swapversion", required_argument, 0, 'v' }, | |
465 | { "uuid", required_argument, 0, 'U' }, | |
466 | { "version", no_argument, 0, 'V' }, | |
467 | { "help", no_argument, 0, 'h' }, | |
468 | { NULL, 0, 0, 0 } | |
469 | }; | |
470 | ||
471 | setlocale(LC_ALL, ""); | |
472 | bindtextdomain(PACKAGE, LOCALEDIR); | |
473 | textdomain(PACKAGE); | |
474 | atexit(close_stdout); | |
475 | ||
476 | while((c = getopt_long(argc, argv, "cfp:L:v:U:Vh", longopts, NULL)) != -1) { | |
477 | switch (c) { | |
478 | case 'c': | |
479 | check=1; | |
480 | break; | |
481 | case 'f': | |
482 | force=1; | |
483 | break; | |
484 | case 'p': | |
485 | user_pagesize = strtou32_or_err(optarg, _("parsing page size failed")); | |
486 | break; | |
487 | case 'L': | |
488 | opt_label = optarg; | |
489 | break; | |
490 | case 'v': | |
491 | version = strtos32_or_err(optarg, _("parsing version number failed")); | |
492 | break; | |
493 | case 'U': | |
494 | #ifdef HAVE_LIBUUID | |
495 | opt_uuid = optarg; | |
496 | #else | |
497 | warnx(_("warning: ignoring -U (UUIDs are unsupported by %s)"), | |
498 | program_invocation_short_name); | |
499 | #endif | |
500 | break; | |
501 | case 'V': | |
502 | printf(UTIL_LINUX_VERSION); | |
503 | exit(EXIT_SUCCESS); | |
504 | case 'h': | |
505 | usage(stdout); | |
506 | default: | |
507 | usage(stderr); | |
508 | } | |
509 | } | |
510 | if (optind < argc) | |
511 | device_name = argv[optind++]; | |
512 | if (optind < argc) | |
513 | block_count = argv[optind++]; | |
514 | if (optind != argc) { | |
515 | warnx(_("only one device argument is currently supported")); | |
516 | usage(stderr); | |
517 | } | |
518 | ||
519 | if (version != 1) | |
520 | errx(EXIT_FAILURE, | |
521 | _("swapspace version %d is not supported"), version); | |
522 | ||
523 | #ifdef HAVE_LIBUUID | |
524 | if(opt_uuid) { | |
525 | if (uuid_parse(opt_uuid, uuid_dat) != 0) | |
526 | errx(EXIT_FAILURE, _("error: parsing UUID failed")); | |
527 | } else | |
528 | uuid_generate(uuid_dat); | |
529 | uuid = uuid_dat; | |
530 | #endif | |
531 | ||
532 | init_signature_page(); /* get pagesize */ | |
533 | ||
534 | if (!device_name) { | |
535 | warnx(_("error: Nowhere to set up swap on?")); | |
536 | usage(stderr); | |
537 | } | |
538 | if (block_count) { | |
539 | /* this silly user specified the number of blocks explicitly */ | |
540 | uint64_t blks = strtou64_or_err(block_count, | |
541 | _("invalid block count argument")); | |
542 | PAGES = blks / (pagesize / 1024); | |
543 | } | |
544 | sz = get_size(device_name); | |
545 | if (!PAGES) | |
546 | PAGES = sz; | |
547 | else if (PAGES > sz && !force) { | |
548 | errx(EXIT_FAILURE, | |
549 | _("error: " | |
550 | "size %llu KiB is larger than device size %llu KiB"), | |
551 | PAGES*(pagesize/1024), sz*(pagesize/1024)); | |
552 | } | |
553 | ||
554 | if (PAGES < MIN_GOODPAGES) { | |
555 | warnx(_("error: swap area needs to be at least %ld KiB"), | |
556 | (long)(MIN_GOODPAGES * pagesize/1024)); | |
557 | usage(stderr); | |
558 | } | |
559 | ||
560 | #ifdef __linux__ | |
561 | if (get_linux_version() >= KERNEL_VERSION(2,3,4)) | |
562 | maxpages = UINT_MAX + 1ULL; | |
563 | else if (get_linux_version() >= KERNEL_VERSION(2,2,1)) | |
564 | maxpages = V1_MAX_PAGES; | |
565 | else | |
566 | #endif | |
567 | maxpages = V1_OLD_MAX_PAGES; | |
568 | ||
569 | if (PAGES > maxpages) { | |
570 | PAGES = maxpages; | |
571 | warnx(_("warning: truncating swap area to %llu KiB"), | |
572 | PAGES * pagesize / 1024); | |
573 | } | |
574 | ||
575 | if (is_mounted(device_name)) | |
576 | errx(EXIT_FAILURE, _("error: " | |
577 | "%s is mounted; will not make swapspace"), | |
578 | device_name); | |
579 | ||
580 | if (stat(device_name, &statbuf) < 0) { | |
581 | perror(device_name); | |
582 | exit(EXIT_FAILURE); | |
583 | } | |
584 | if (S_ISBLK(statbuf.st_mode)) | |
585 | DEV = open(device_name, O_RDWR | O_EXCL); | |
586 | else | |
587 | DEV = open(device_name, O_RDWR); | |
588 | ||
589 | if (DEV < 0) { | |
590 | perror(device_name); | |
591 | exit(EXIT_FAILURE); | |
592 | } | |
593 | ||
594 | if (!S_ISBLK(statbuf.st_mode)) | |
595 | check=0; | |
596 | else if (blkdev_is_misaligned(DEV)) | |
597 | warnx(_("warning: %s is misaligned"), device_name); | |
598 | ||
599 | if (check) | |
600 | check_blocks(); | |
601 | ||
602 | wipe_device(DEV, device_name, force); | |
603 | ||
604 | hdr = (struct swap_header_v1_2 *) signature_page; | |
605 | hdr->version = 1; | |
606 | hdr->last_page = PAGES - 1; | |
607 | hdr->nr_badpages = badpages; | |
608 | ||
609 | if (badpages > PAGES - MIN_GOODPAGES) | |
610 | errx(EXIT_FAILURE, _("Unable to set up swap-space: unreadable")); | |
611 | ||
612 | goodpages = PAGES - badpages - 1; | |
613 | printf(_("Setting up swapspace version 1, size = %llu KiB\n"), | |
614 | goodpages * pagesize / 1024); | |
615 | ||
616 | write_signature("SWAPSPACE2"); | |
617 | write_uuid_and_label(uuid, opt_label); | |
618 | ||
619 | offset = 1024; | |
620 | if (lseek(DEV, offset, SEEK_SET) != offset) | |
621 | errx(EXIT_FAILURE, _("unable to rewind swap-device")); | |
622 | if (write_all(DEV, (char *) signature_page + offset, | |
623 | pagesize - offset) == -1) | |
624 | err(EXIT_FAILURE, | |
625 | _("%s: unable to write signature page"), | |
626 | device_name); | |
627 | ||
628 | #ifdef HAVE_LIBSELINUX | |
629 | if (S_ISREG(statbuf.st_mode) && is_selinux_enabled() > 0) { | |
630 | security_context_t context_string; | |
631 | security_context_t oldcontext; | |
632 | context_t newcontext; | |
633 | ||
634 | if (fgetfilecon(DEV, &oldcontext) < 0) { | |
635 | if (errno != ENODATA) | |
636 | err(EXIT_FAILURE, | |
637 | _("%s: unable to obtain selinux file label"), | |
638 | device_name); | |
639 | if (matchpathcon(device_name, statbuf.st_mode, &oldcontext)) | |
640 | errx(EXIT_FAILURE, _("unable to matchpathcon()")); | |
641 | } | |
642 | if (!(newcontext = context_new(oldcontext))) | |
643 | errx(EXIT_FAILURE, _("unable to create new selinux context")); | |
644 | if (context_type_set(newcontext, SELINUX_SWAPFILE_TYPE)) | |
645 | errx(EXIT_FAILURE, _("couldn't compute selinux context")); | |
646 | ||
647 | context_string = context_str(newcontext); | |
648 | ||
649 | if (strcmp(context_string, oldcontext)!=0) { | |
650 | if (fsetfilecon(DEV, context_string)) | |
651 | err(EXIT_FAILURE, _("unable to relabel %s to %s"), | |
652 | device_name, context_string); | |
653 | } | |
654 | context_free(newcontext); | |
655 | freecon(oldcontext); | |
656 | } | |
657 | #endif | |
658 | /* | |
659 | * A subsequent swapon() will fail if the signature | |
660 | * is not actually on disk. (This is a kernel bug.) | |
661 | * The fsync() in close_fd() will take care of writing. | |
662 | */ | |
663 | if (close_fd(DEV) != 0) | |
664 | err(EXIT_FAILURE, _("write failed")); | |
665 | return EXIT_SUCCESS; | |
666 | } |