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>
44 #ifdef HAVE_LIBSELINUX
45 #include <selinux/selinux.h>
46 #include <selinux/context.h>
49 #include "linux_version.h"
50 #include "swapheader.h"
54 #include "pathnames.h"
55 #include "wholedisk.h"
58 # ifdef HAVE_UUID_UUID_H
59 # include <uuid/uuid.h>
65 #ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS
69 static char * program_name
= "mkswap";
70 static char * device_name
= NULL
;
72 static unsigned long long PAGES
= 0;
73 static unsigned long badpages
= 0;
76 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
80 # define is_sparc64() 1
86 static int sparc64
= -1;
88 if (sparc64
!= -1) return sparc64
;
91 if (uname(&un
) < 0) return 0;
92 if (! strcmp(un
.machine
, "sparc64")) {
96 if (strcmp(un
.machine
, "sparc"))
97 return 0; /* Should not happen */
99 #ifdef HAVE_PERSONALITY
101 extern int personality(unsigned long);
103 #define PERS_LINUX 0x00000000
104 #define PERS_LINUX_32BIT 0x00800000
105 #define PERS_LINUX32 0x00000008
107 oldpers
= personality(PERS_LINUX_32BIT
);
109 if (personality(PERS_LINUX
) != -1) {
111 if (! strcmp(un
.machine
, "sparc64")) {
113 oldpers
= PERS_LINUX32
;
116 personality(oldpers
);
123 # define is_be64() is_sparc64()
124 # endif /* sparc32 */
130 * The definition of the union swap_header uses the kernel constant PAGE_SIZE.
131 * Unfortunately, on some architectures this depends on the hardware model, and
132 * can only be found at run time -- we use getpagesize(), so that we do not
133 * need separate binaries e.g. for sun4, sun4c/d/m and sun4u.
135 * Even more unfortunately, getpagesize() does not always return the right
136 * information. For example, libc4, libc5 and glibc 2.0 do not use the system
137 * call but invent a value themselves (EXEC_PAGESIZE or NBPG * CLSIZE or NBPC),
138 * and thus it may happen that e.g. on a sparc kernel PAGE_SIZE=4096 and
139 * getpagesize() returns 8192.
141 * What to do? Let us allow the user to specify the pagesize explicitly.
144 static int user_pagesize
;
146 static unsigned long *signature_page
= NULL
;
147 struct swap_header_v1
*p
;
150 init_signature_page(void) {
152 int kernel_pagesize
= pagesize
= getpagesize();
155 if ((user_pagesize
& (user_pagesize
-1)) ||
156 user_pagesize
< 1024) {
157 fprintf(stderr
, _("Bad user-specified page size %d\n"),
161 pagesize
= user_pagesize
;
164 if (user_pagesize
&& user_pagesize
!= kernel_pagesize
)
165 fprintf(stderr
, _("Using user-specified page size %d, "
166 "instead of the system value %d\n"),
167 pagesize
, kernel_pagesize
);
169 signature_page
= (unsigned long *) malloc(pagesize
);
170 memset(signature_page
, 0, pagesize
);
171 p
= (struct swap_header_v1
*) signature_page
;
175 deinit_signature_page(void) {
176 free(signature_page
);
180 write_signature(char *sig
) {
181 char *sp
= (char *) signature_page
;
183 strncpy(sp
+pagesize
-10, sig
, 10);
187 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
)) {
194 _("Bad swap header size, no label written.\n"));
198 h
= (struct swap_header_v1_2
*) signature_page
;
200 memcpy(h
->uuid
, uuid
, sizeof(h
->uuid
));
202 xstrncpy(h
->volume_name
, volume_name
, sizeof(h
->volume_name
));
203 if (strlen(volume_name
) > strlen(h
->volume_name
))
204 fprintf(stderr
, _("Label was truncated.\n"));
206 if (uuid
|| volume_name
) {
208 printf("LABEL=%s, ", h
->volume_name
);
210 printf(_("no label, "));
213 char uuid_string
[37];
214 uuid_unparse(uuid
, uuid_string
);
215 printf("UUID=%s\n", uuid_string
);
218 printf(_("no uuid\n"));
223 * Find out what the maximum amount of swap space is that the kernel will
224 * handle. This wouldn't matter if the kernel just used as much of the
225 * swap space as it can handle, but until 2.3.4 it would return an error
226 * to swapon() if the swapspace was too large.
228 /* Before 2.2.0pre9 */
229 #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
230 /* Since 2.2.0pre9, before 2.3.4:
231 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
233 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
234 #define SWP_OFFSET(entry) ((entry) >> 8)
235 on the various architectures. Below the result - yuk.
237 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
238 i386 2^12 o<<8 e>>8 1<<24 1<<19
239 mips 2^12 o<<15 e>>15 1<<17 1<<19
240 alpha 2^13 o<<40 e>>40 1<<24 1<<18
241 m68k 2^12 o<<12 e>>12 1<<20 1<<19
242 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
243 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
244 ppc 2^12 o<<8 e>>8 1<<24 1<<19
245 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
246 armv 2^12 o<<9 e>>9 1<<23 1<<19
248 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
250 The bad part is that we need to know this since the kernel will
251 refuse a swap space if it is too large.
253 /* patch from jj - why does this differ from the above? */
254 /* 32bit kernels have a second limitation of 2GB, sparc64 is limited by
255 the size of virtual address space allocation for vmalloc */
256 #if defined(__alpha__)
257 #define V1_MAX_PAGES ((1 << 24) - 1)
258 #elif defined(__mips__)
259 #define V1_MAX_PAGES ((1 << 17) - 1)
260 #elif defined(__sparc__)
261 #define V1_MAX_PAGES (is_sparc64() ? ((3 << 29) - 1) : ((1 << 18) - 1))
262 #elif defined(__ia64__)
264 * The actual size will depend on the amount of virtual address space
265 * available to vmalloc the swap map.
267 #define V1_MAX_PAGES ((1UL << 54) - 1)
269 #define V1_MAX_PAGES V1_OLD_MAX_PAGES
271 /* man page now says:
272 The maximum useful size of a swap area now depends on the architecture.
273 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
274 128GB on alpha and 3TB on sparc64.
277 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
278 #define MIN_GOODPAGES 10
283 _("Usage: %s [-c] [-pPAGESZ] [-L label] [-U UUID] /dev/name [blocks]\n"),
289 die(const char *str
) {
290 fprintf(stderr
, "%s: %s\n", program_name
, str
);
296 if (badpages
== MAX_BADPAGES
)
297 die(_("too many bad pages"));
298 p
->badpages
[badpages
] = page
;
304 unsigned int current_page
;
308 buffer
= malloc(pagesize
);
310 die(_("Out of memory"));
312 while (current_page
< PAGES
) {
313 if (do_seek
&& lseek(DEV
,current_page
*pagesize
,SEEK_SET
) !=
314 current_page
*pagesize
)
315 die(_("seek failed in check_blocks"));
316 if ((do_seek
= (pagesize
!= read(DEV
, buffer
, pagesize
))))
317 page_bad(current_page
);
321 printf(_("one bad page\n"));
322 else if (badpages
> 1)
323 printf(_("%lu bad pages\n"), badpages
);
327 /* return size in pages */
328 static unsigned long long
329 get_size(const char *file
) {
331 unsigned long long size
;
333 fd
= open(file
, O_RDONLY
);
338 if (blkdev_get_size(fd
, &size
) == 0)
341 size
= blkdev_find_size(fd
) / pagesize
;
349 return (c
>= '1' && c
<= '9');
354 * Check to make certain that our new filesystem won't be created on
355 * an already mounted partition. Code adapted from mke2fs, Copyright
356 * (C) 1994 Theodore Ts'o. Also licensed under GPL.
357 * (C) 2006 Karel Zak -- port to mkswap
364 if ((f
= setmntent (_PATH_MOUNTED
, "r")) == NULL
)
366 while ((mnt
= getmntent (f
)) != NULL
)
367 if (strcmp (device_name
, mnt
->mnt_fsname
) == 0)
377 write_all(int fd
, const void *buf
, size_t count
) {
382 tmp
= write(fd
, buf
, count
);
387 } else if (errno
!= EINTR
&& errno
!= EAGAIN
)
394 zap_bootbits(int fd
, const char *devname
, int force
)
401 if (lseek(fd
, 0, SEEK_SET
) != 0)
402 die(_("unable to rewind swap-device"));
404 if (is_whole_disk_fd(fd
, devname
)) {
405 /* don't zap bootbits on whole disk -- we know nothing
406 * about bootloaders on the device */
410 #ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS
411 blkid_probe pr
= blkid_new_probe();
413 die(_("unable to alloc new libblkid probe"));
414 if (blkid_probe_set_device(pr
, fd
, 0, 0))
415 die(_("unable to assign device to liblkid probe"));
417 blkid_probe_enable_partitions(pr
, 1);
418 blkid_probe_enable_superblocks(pr
, 0);
420 if (blkid_do_fullprobe(pr
) == 0)
421 blkid_probe_lookup_value(pr
, "PTTYPE",
422 (const char **) &type
, NULL
);
427 blkid_free_probe(pr
);
429 /* don't zap if compiled without libblkid */
438 if (lseek(fd
, 0, SEEK_SET
) != 0)
439 die(_("unable to rewind swap-device"));
441 memset(buf
, 0, sizeof(buf
));
442 if (write_all(fd
, buf
, sizeof(buf
)))
443 die(_("unable to erase bootbits sectors"));
447 fprintf(stderr
, _("%s: %s: warning: don't erase bootbits sectors\n"),
448 program_name
, devname
);
450 fprintf(stderr
, _(" (%s partition table detected). "), type
);
452 fprintf(stderr
, _(" on whole disk. "));
454 fprintf(stderr
, _(" (compiled without libblkid). "));
455 fprintf(stderr
, "Use -f to force.\n");
459 main(int argc
, char ** argv
) {
462 unsigned long long maxpages
;
463 unsigned long long goodpages
;
464 unsigned long long sz
;
468 char *block_count
= 0;
470 char *opt_label
= NULL
;
471 unsigned char *uuid
= NULL
;
473 const char *opt_uuid
= NULL
;
477 program_name
= (argc
&& *argv
) ? argv
[0] : "mkswap";
478 if ((pp
= strrchr(program_name
, '/')) != NULL
)
481 setlocale(LC_ALL
, "");
482 bindtextdomain(PACKAGE
, LOCALEDIR
);
486 (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))) {
487 printf(_("%s (%s)\n"), program_name
, PACKAGE_STRING
);
491 for (i
=1; i
<argc
; i
++) {
492 if (argv
[i
][0] == '-') {
493 switch (argv
[i
][1]) {
502 if (!*pp
&& i
+1 < argc
)
505 user_pagesize
= atoi(pp
);
511 if (!*pp
&& i
+1 < argc
)
516 version
= atoi(argv
[i
]+2);
520 opt_uuid
= argv
[i
]+2;
521 if (!*opt_uuid
&& i
+1 < argc
)
522 opt_uuid
= argv
[++i
];
524 fprintf(stderr
, _("%1$s: warning: ignore -U (UUIDs are unsupported by %1$s)\n"),
531 } else if (!device_name
) {
532 device_name
= argv
[i
];
533 } else if (!block_count
) {
534 block_count
= argv
[i
];
540 fprintf(stderr
, _("%s: does not support swapspace version %d.\n"),
541 program_name
, version
);
547 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
548 die(_("error: UUID parsing failed"));
550 uuid_generate(uuid_dat
);
554 init_signature_page(); /* get pagesize */
555 atexit(deinit_signature_page
);
559 _("%s: error: Nowhere to set up swap on?\n"),
564 /* this silly user specified the number of blocks
567 int blocks_per_page
= pagesize
/1024;
568 PAGES
= strtoull(block_count
,&tmp
,0)/blocks_per_page
;
572 sz
= get_size(device_name
);
575 } else if (PAGES
> sz
&& !force
) {
578 "size %llu KiB is larger than device size %llu KiB\n"),
580 PAGES
*(pagesize
/1024), sz
*(pagesize
/1024));
584 if (PAGES
< MIN_GOODPAGES
) {
586 _("%s: error: swap area needs to be at least %ld KiB\n"),
587 program_name
, (long)(MIN_GOODPAGES
* pagesize
/1024));
592 if (get_linux_version() >= KERNEL_VERSION(2,3,4))
593 maxpages
= UINT_MAX
+ 1ULL;
594 else if (get_linux_version() >= KERNEL_VERSION(2,2,1))
595 maxpages
= V1_MAX_PAGES
;
598 maxpages
= V1_OLD_MAX_PAGES
;
600 if (PAGES
> maxpages
) {
603 _("%s: warning: truncating swap area to %llu KiB\n"),
604 program_name
, PAGES
* pagesize
/ 1024);
607 if (stat(device_name
, &statbuf
) < 0) {
611 if (S_ISBLK(statbuf
.st_mode
))
612 DEV
= open(device_name
, O_RDWR
| O_EXCL
);
614 DEV
= open(device_name
, O_RDWR
);
621 /* Want a block device. Probably not /dev/hda or /dev/hdb. */
622 if (!S_ISBLK(statbuf
.st_mode
))
624 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340) {
627 "will not try to make swapdevice on '%s'\n"),
628 program_name
, device_name
);
630 } else if (check_mount()) {
633 "%s is mounted; will not make swapspace.\n"),
634 program_name
, device_name
);
641 zap_bootbits(DEV
, device_name
, force
);
644 p
->last_page
= PAGES
-1;
645 p
->nr_badpages
= badpages
;
647 if (badpages
> PAGES
- MIN_GOODPAGES
)
648 die(_("Unable to set up swap-space: unreadable"));
650 goodpages
= PAGES
- badpages
- 1;
651 printf(_("Setting up swapspace version 1, size = %llu KiB\n"),
652 goodpages
* pagesize
/ 1024);
654 write_signature("SWAPSPACE2");
655 write_uuid_and_label(uuid
, opt_label
);
658 if (lseek(DEV
, offset
, SEEK_SET
) != offset
)
659 die(_("unable to rewind swap-device"));
660 if (write_all(DEV
, (char *) signature_page
+ offset
,
661 pagesize
- offset
) == -1) {
662 fprintf(stderr
, _("%s: %s: unable to write signature page: %s"),
663 program_name
, device_name
, strerror(errno
));
668 * A subsequent swapon() will fail if the signature
669 * is not actually on disk. (This is a kernel bug.)
673 die(_("fsync failed"));
676 #ifdef HAVE_LIBSELINUX
677 if (S_ISREG(statbuf
.st_mode
) && is_selinux_enabled() > 0) {
678 security_context_t context_string
;
679 security_context_t oldcontext
;
680 context_t newcontext
;
682 if (fgetfilecon(DEV
, &oldcontext
) < 0) {
683 if (errno
!= ENODATA
) {
684 fprintf(stderr
, _("%s: %s: unable to obtain selinux file label: %s\n"),
685 program_name
, device_name
,
689 if (matchpathcon(device_name
, statbuf
.st_mode
, &oldcontext
))
690 die(_("unable to matchpathcon()"));
692 if (!(newcontext
= context_new(oldcontext
)))
693 die(_("unable to create new selinux context"));
694 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
695 die(_("couldn't compute selinux context"));
697 context_string
= context_str(newcontext
);
699 if (strcmp(context_string
, oldcontext
)!=0) {
700 if (fsetfilecon(DEV
, context_string
)) {
701 fprintf(stderr
, _("%s: unable to relabel %s to %s: %s\n"),
702 program_name
, device_name
,
708 context_free(newcontext
);