2 * mkswap.c - set up a linux swap device
4 * (C) 1991 Linus Torvalds. This file may be redistributed as per
9 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
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.
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 :-).
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.
23 * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
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.
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
30 * - added Native Language Support
41 #include <sys/utsname.h>
46 #ifdef HAVE_LIBSELINUX
47 #include <selinux/selinux.h>
48 #include <selinux/context.h>
51 #include "linux_version.h"
52 #include "swapheader.h"
56 #include "pathnames.h"
57 #include "wholedisk.h"
62 # ifdef HAVE_UUID_UUID_H
63 # include <uuid/uuid.h>
69 #ifdef HAVE_LIBBLKID_INTERNAL
73 static char *device_name
= NULL
;
75 static unsigned long long PAGES
= 0;
76 static unsigned long badpages
= 0;
79 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
83 # define is_sparc64() 1
90 static int sparc64
= -1;
98 if (! strcmp(un
.machine
, "sparc64")) {
102 if (strcmp(un
.machine
, "sparc"))
103 return 0; /* Should not happen */
105 #ifdef HAVE_PERSONALITY
107 extern int personality(unsigned long);
109 #define PERS_LINUX 0x00000000
110 #define PERS_LINUX_32BIT 0x00800000
111 #define PERS_LINUX32 0x00000008
113 oldpers
= personality(PERS_LINUX_32BIT
);
115 if (personality(PERS_LINUX
) != -1) {
117 if (! strcmp(un
.machine
, "sparc64")) {
119 oldpers
= PERS_LINUX32
;
122 personality(oldpers
);
129 # define is_be64() is_sparc64()
130 # endif /* sparc32 */
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.
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.
147 * What to do? Let us allow the user to specify the pagesize explicitly.
150 static long user_pagesize
;
152 static unsigned long *signature_page
= NULL
;
155 init_signature_page(void)
158 int kernel_pagesize
= pagesize
= getpagesize();
161 if ((user_pagesize
& (user_pagesize
- 1)) ||
162 user_pagesize
< (long) sizeof(struct swap_header_v1_2
) + 10)
164 _("Bad user-specified page size %lu"),
166 pagesize
= user_pagesize
;
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
);
174 signature_page
= (unsigned long *) xcalloc(1, pagesize
);
178 write_signature(char *sig
)
180 char *sp
= (char *) signature_page
;
182 strncpy(sp
+ pagesize
- 10, sig
, 10);
186 write_uuid_and_label(unsigned char *uuid
, char *volume_name
)
188 struct swap_header_v1_2
*h
;
191 if (sizeof(struct swap_header_v1
) !=
192 sizeof(struct swap_header_v1_2
)) {
193 warnx(_("Bad swap header size, no label written."));
197 h
= (struct swap_header_v1_2
*) signature_page
;
199 memcpy(h
->uuid
, uuid
, sizeof(h
->uuid
));
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."));
205 if (uuid
|| volume_name
) {
207 printf("LABEL=%s, ", h
->volume_name
);
209 printf(_("no label, "));
212 char uuid_string
[37];
213 uuid_unparse(uuid
, uuid_string
);
214 printf("UUID=%s\n", uuid_string
);
217 printf(_("no uuid\n"));
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.
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))
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.
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
247 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
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.
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__)
263 * The actual size will depend on the amount of virtual address space
264 * available to vmalloc the swap map.
266 #define V1_MAX_PAGES ((1UL << 54) - 1)
268 #define V1_MAX_PAGES V1_OLD_MAX_PAGES
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.
276 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
277 #define MIN_GOODPAGES 10
279 static void __attribute__ ((__noreturn__
)) usage(FILE *out
)
283 " %s [options] device [size]\n"),
284 program_invocation_short_name
);
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"));
297 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
303 struct swap_header_v1_2
*p
= (struct swap_header_v1_2
*) signature_page
;
305 if (badpages
== MAX_BADPAGES
)
306 errx(EXIT_FAILURE
, _("too many bad pages"));
307 p
->badpages
[badpages
] = page
;
314 unsigned int current_page
;
318 buffer
= xmalloc(pagesize
);
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
);
329 printf(_("one bad page\n"));
330 else if (badpages
> 1)
331 printf(_("%lu bad pages\n"), badpages
);
335 /* return size in pages */
336 static unsigned long long
337 get_size(const char *file
)
340 unsigned long long size
;
342 fd
= open(file
, O_RDONLY
);
347 if (blkdev_get_size(fd
, &size
) == 0)
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
366 if ((f
= setmntent (_PATH_MOUNTED
, "r")) == NULL
)
368 while ((mnt
= getmntent (f
)) != NULL
)
369 if (strcmp (device_name
, mnt
->mnt_fsname
) == 0)
378 zap_bootbits(int fd
, const char *devname
, int force
, int is_blkdev
)
385 if (lseek(fd
, 0, SEEK_SET
) != 0)
386 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
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 */
394 #ifdef HAVE_LIBBLKID_INTERNAL
395 blkid_probe pr
= blkid_new_probe();
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"));
401 blkid_probe_enable_partitions(pr
, 1);
402 blkid_probe_enable_superblocks(pr
, 0);
404 if (blkid_do_fullprobe(pr
) == 0)
405 blkid_probe_lookup_value(pr
, "PTTYPE",
406 (const char **) &type
, NULL
);
408 type
= xstrdup(type
);
411 blkid_free_probe(pr
);
413 /* don't zap if compiled without libblkid */
422 if (lseek(fd
, 0, SEEK_SET
) != 0)
423 errx(EXIT_FAILURE
, _("unable to rewind swap-device"));
425 memset(buf
, 0, sizeof(buf
));
426 if (write_all(fd
, buf
, sizeof(buf
)))
427 errx(EXIT_FAILURE
, _("unable to erase bootbits sectors"));
431 warnx(_("%s: warning: don't erase bootbits sectors"),
434 fprintf(stderr
, _(" (%s partition table detected). "), type
);
436 fprintf(stderr
, _(" on whole disk. "));
438 fprintf(stderr
, _(" (compiled without libblkid). "));
439 fprintf(stderr
, "Use -f to force.\n");
443 main(int argc
, char **argv
) {
445 struct swap_header_v1_2
*hdr
;
447 unsigned long long maxpages
;
448 unsigned long long goodpages
;
449 unsigned long long sz
;
453 char *block_count
= 0;
454 char *opt_label
= NULL
;
455 unsigned char *uuid
= NULL
;
457 const char *opt_uuid
= NULL
;
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' },
472 setlocale(LC_ALL
, "");
473 bindtextdomain(PACKAGE
, LOCALEDIR
);
476 while((c
= getopt_long(argc
, argv
, "cfp:L:v:U:Vh", longopts
, NULL
)) != -1) {
485 user_pagesize
= strtol_or_err(optarg
, _("parse page size failed"));
491 version
= strtol_or_err(optarg
, _("parse version number failed"));
497 warnx(_("warning: ignore -U (UUIDs are unsupported by %s)"),
498 program_invocation_short_name
);
502 printf(_("%s from %s\n"), program_invocation_short_name
,
512 device_name
= argv
[optind
++];
514 block_count
= argv
[optind
++];
515 if (optind
!= argc
) {
516 warnx(("only one device as argument is currently supported."));
522 _("does not support swapspace version %lu."),
527 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
528 errx(EXIT_FAILURE
, _("error: UUID parsing failed"));
530 uuid_generate(uuid_dat
);
534 init_signature_page(); /* get pagesize */
537 warnx(_("error: Nowhere to set up swap on?"));
541 /* this silly user specified the number of blocks explicitly */
544 blks
= strtoll_or_err(block_count
, "parse block count failed");
548 PAGES
= blks
/ (pagesize
/ 1024);
550 sz
= get_size(device_name
);
553 else if (PAGES
> sz
&& !force
) {
556 "size %llu KiB is larger than device size %llu KiB"),
557 PAGES
*(pagesize
/1024), sz
*(pagesize
/1024));
560 if (PAGES
< MIN_GOODPAGES
) {
561 warnx(_("error: swap area needs to be at least %ld KiB"),
562 (long)(MIN_GOODPAGES
* pagesize
/1024));
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
;
573 maxpages
= V1_OLD_MAX_PAGES
;
575 if (PAGES
> maxpages
) {
577 warnx(_("warning: truncating swap area to %llu KiB"),
578 PAGES
* pagesize
/ 1024);
581 if (stat(device_name
, &statbuf
) < 0) {
585 if (S_ISBLK(statbuf
.st_mode
))
586 DEV
= open(device_name
, O_RDWR
| O_EXCL
);
588 DEV
= open(device_name
, O_RDWR
);
595 /* Want a block device. Probably not /dev/hda or /dev/hdb. */
596 if (!S_ISBLK(statbuf
.st_mode
))
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'"),
602 else if (check_mount())
603 errx(EXIT_FAILURE
, _("error: "
604 "%s is mounted; will not make swapspace."),
610 zap_bootbits(DEV
, device_name
, force
, S_ISBLK(statbuf
.st_mode
));
612 hdr
= (struct swap_header_v1_2
*) signature_page
;
614 hdr
->last_page
= PAGES
- 1;
615 hdr
->nr_badpages
= badpages
;
617 if (badpages
> PAGES
- MIN_GOODPAGES
)
618 errx(EXIT_FAILURE
, _("Unable to set up swap-space: unreadable"));
620 goodpages
= PAGES
- badpages
- 1;
621 printf(_("Setting up swapspace version 1, size = %llu KiB\n"),
622 goodpages
* pagesize
/ 1024);
624 write_signature("SWAPSPACE2");
625 write_uuid_and_label(uuid
, opt_label
);
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)
633 _("%s: unable to write signature page"),
637 * A subsequent swapon() will fail if the signature
638 * is not actually on disk. (This is a kernel bug.)
642 errx(EXIT_FAILURE
, _("fsync failed"));
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
;
651 if (fgetfilecon(DEV
, &oldcontext
) < 0) {
652 if (errno
!= ENODATA
)
654 _("%s: unable to obtain selinux file label"),
656 if (matchpathcon(device_name
, statbuf
.st_mode
, &oldcontext
))
657 errx(EXIT_FAILURE
, _("unable to matchpathcon()"));
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"));
664 context_string
= context_str(newcontext
);
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
);
671 context_free(newcontext
);