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