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/ioctl.h> /* for _IO */
42 #include <sys/utsname.h>
45 #ifdef HAVE_LIBSELINUX
46 #include <selinux/selinux.h>
47 #include <selinux/context.h>
50 #include "linux_version.h"
51 #include "swapheader.h"
55 #include "pathnames.h"
58 #include <uuid/uuid.h>
61 static char * program_name
= "mkswap";
62 static char * device_name
= NULL
;
64 static unsigned long long PAGES
= 0;
65 static unsigned long badpages
= 0;
68 #define SELINUX_SWAPFILE_TYPE "swapfile_t"
72 # define is_sparc64() 1
78 static int sparc64
= -1;
80 if (sparc64
!= -1) return sparc64
;
83 if (uname(&un
) < 0) return 0;
84 if (! strcmp(un
.machine
, "sparc64")) {
88 if (strcmp(un
.machine
, "sparc"))
89 return 0; /* Should not happen */
91 #ifdef HAVE_PERSONALITY
93 extern int personality(unsigned long);
95 #define PERS_LINUX 0x00000000
96 #define PERS_LINUX_32BIT 0x00800000
97 #define PERS_LINUX32 0x00000008
99 oldpers
= personality(PERS_LINUX_32BIT
);
101 if (personality(PERS_LINUX
) != -1) {
103 if (! strcmp(un
.machine
, "sparc64")) {
105 oldpers
= PERS_LINUX32
;
108 personality(oldpers
);
115 # define is_be64() is_sparc64()
116 # endif /* sparc32 */
122 * The definition of the union swap_header uses the kernel constant PAGE_SIZE.
123 * Unfortunately, on some architectures this depends on the hardware model, and
124 * can only be found at run time -- we use getpagesize(), so that we do not
125 * need separate binaries e.g. for sun4, sun4c/d/m and sun4u.
127 * Even more unfortunately, getpagesize() does not always return the right
128 * information. For example, libc4, libc5 and glibc 2.0 do not use the system
129 * call but invent a value themselves (EXEC_PAGESIZE or NBPG * CLSIZE or NBPC),
130 * and thus it may happen that e.g. on a sparc kernel PAGE_SIZE=4096 and
131 * getpagesize() returns 8192.
133 * What to do? Let us allow the user to specify the pagesize explicitly.
136 static int user_pagesize
;
138 static unsigned long *signature_page
;
139 struct swap_header_v1
*p
;
142 init_signature_page(void) {
144 int kernel_pagesize
= pagesize
= getpagesize();
147 if ((user_pagesize
& (user_pagesize
-1)) ||
148 user_pagesize
< 1024) {
149 fprintf(stderr
, _("Bad user-specified page size %d\n"),
153 pagesize
= user_pagesize
;
156 if (user_pagesize
&& user_pagesize
!= kernel_pagesize
)
157 fprintf(stderr
, _("Using user-specified page size %d, "
158 "instead of the system value %d\n"),
159 pagesize
, kernel_pagesize
);
161 signature_page
= (unsigned long *) malloc(pagesize
);
162 memset(signature_page
, 0, pagesize
);
163 p
= (struct swap_header_v1
*) signature_page
;
167 write_signature(char *sig
) {
168 char *sp
= (char *) signature_page
;
170 strncpy(sp
+pagesize
-10, sig
, 10);
174 write_uuid_and_label(unsigned char *uuid
, char *volume_name
) {
175 struct swap_header_v1_2
*h
;
178 if (sizeof(struct swap_header_v1
) !=
179 sizeof(struct swap_header_v1_2
)) {
181 _("Bad swap header size, no label written.\n"));
185 h
= (struct swap_header_v1_2
*) signature_page
;
187 memcpy(h
->uuid
, uuid
, sizeof(h
->uuid
));
189 xstrncpy(h
->volume_name
, volume_name
, sizeof(h
->volume_name
));
190 if (strlen(volume_name
) > strlen(h
->volume_name
))
191 fprintf(stderr
, _("Label was truncated.\n"));
193 if (uuid
|| volume_name
) {
195 printf("LABEL=%s, ", h
->volume_name
);
197 printf(_("no label, "));
200 char uuid_string
[37];
201 uuid_unparse(uuid
, uuid_string
);
202 printf("UUID=%s\n", uuid_string
);
205 printf(_("no uuid\n"));
210 * Find out what the maximum amount of swap space is that the kernel will
211 * handle. This wouldn't matter if the kernel just used as much of the
212 * swap space as it can handle, but until 2.3.4 it would return an error
213 * to swapon() if the swapspace was too large.
215 /* Before 2.2.0pre9 */
216 #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
217 /* Since 2.2.0pre9, before 2.3.4:
218 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
220 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
221 #define SWP_OFFSET(entry) ((entry) >> 8)
222 on the various architectures. Below the result - yuk.
224 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
225 i386 2^12 o<<8 e>>8 1<<24 1<<19
226 mips 2^12 o<<15 e>>15 1<<17 1<<19
227 alpha 2^13 o<<40 e>>40 1<<24 1<<18
228 m68k 2^12 o<<12 e>>12 1<<20 1<<19
229 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
230 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
231 ppc 2^12 o<<8 e>>8 1<<24 1<<19
232 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
233 armv 2^12 o<<9 e>>9 1<<23 1<<19
235 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
237 The bad part is that we need to know this since the kernel will
238 refuse a swap space if it is too large.
240 /* patch from jj - why does this differ from the above? */
241 /* 32bit kernels have a second limitation of 2GB, sparc64 is limited by
242 the size of virtual address space allocation for vmalloc */
243 #if defined(__alpha__)
244 #define V1_MAX_PAGES ((1 << 24) - 1)
245 #elif defined(__mips__)
246 #define V1_MAX_PAGES ((1 << 17) - 1)
247 #elif defined(__sparc__)
248 #define V1_MAX_PAGES (is_sparc64() ? ((3 << 29) - 1) : ((1 << 18) - 1))
249 #elif defined(__ia64__)
251 * The actual size will depend on the amount of virtual address space
252 * available to vmalloc the swap map.
254 #define V1_MAX_PAGES ((1UL << 54) - 1)
256 #define V1_MAX_PAGES V1_OLD_MAX_PAGES
258 /* man page now says:
259 The maximum useful size of a swap area now depends on the architecture.
260 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
261 128GB on alpha and 3TB on sparc64.
264 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
265 #define MIN_GOODPAGES 10
270 _("Usage: %s [-c] [-pPAGESZ] [-L label] [-U UUID] /dev/name [blocks]\n"),
276 die(const char *str
) {
277 fprintf(stderr
, "%s: %s\n", program_name
, str
);
283 if (badpages
== MAX_BADPAGES
)
284 die(_("too many bad pages"));
285 p
->badpages
[badpages
] = page
;
291 unsigned int current_page
;
295 buffer
= malloc(pagesize
);
297 die(_("Out of memory"));
299 while (current_page
< PAGES
) {
302 if (do_seek
&& lseek(DEV
,current_page
*pagesize
,SEEK_SET
) !=
303 current_page
*pagesize
)
304 die(_("seek failed in check_blocks"));
305 if ((do_seek
= (pagesize
!= read(DEV
, buffer
, pagesize
)))) {
306 page_bad(current_page
++);
311 printf(_("one bad page\n"));
312 else if (badpages
> 1)
313 printf(_("%lu bad pages\n"), badpages
);
316 /* return size in pages */
317 static unsigned long long
318 get_size(const char *file
) {
320 unsigned long long size
;
322 fd
= open(file
, O_RDONLY
);
327 if (blkdev_get_size(fd
, &size
) == 0)
330 size
= blkdev_find_size(fd
) / pagesize
;
338 return (c
>= '1' && c
<= '9');
343 * Check to make certain that our new filesystem won't be created on
344 * an already mounted partition. Code adapted from mke2fs, Copyright
345 * (C) 1994 Theodore Ts'o. Also licensed under GPL.
346 * (C) 2006 Karel Zak -- port to mkswap
353 if ((f
= setmntent (_PATH_MOUNTED
, "r")) == NULL
)
355 while ((mnt
= getmntent (f
)) != NULL
)
356 if (strcmp (device_name
, mnt
->mnt_fsname
) == 0)
366 write_all(int fd
, const void *buf
, size_t count
) {
371 tmp
= write(fd
, buf
, count
);
376 } else if (errno
!= EINTR
&& errno
!= EAGAIN
)
383 main(int argc
, char ** argv
) {
386 unsigned long long maxpages
;
387 unsigned long long goodpages
;
388 unsigned long long sz
;
392 char *block_count
= 0;
394 char *opt_label
= NULL
;
395 unsigned char *uuid
= NULL
;
397 const char *opt_uuid
= NULL
;
401 program_name
= (argc
&& *argv
) ? argv
[0] : "mkswap";
402 if ((pp
= strrchr(program_name
, '/')) != NULL
)
405 setlocale(LC_ALL
, "");
406 bindtextdomain(PACKAGE
, LOCALEDIR
);
410 (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))) {
411 printf(_("%s (%s)\n"), program_name
, PACKAGE_STRING
);
415 for (i
=1; i
<argc
; i
++) {
416 if (argv
[i
][0] == '-') {
417 switch (argv
[i
][1]) {
426 if (!*pp
&& i
+1 < argc
)
429 user_pagesize
= atoi(pp
);
435 if (!*pp
&& i
+1 < argc
)
440 version
= atoi(argv
[i
]+2);
444 opt_uuid
= argv
[i
]+2;
445 if (!*opt_uuid
&& i
+1 < argc
)
446 opt_uuid
= argv
[++i
];
448 fprintf(stderr
, _("%1$s: warning: ignore -U (UUIDs are unsupported by %1$s)\n"),
455 } else if (!device_name
) {
456 device_name
= argv
[i
];
457 } else if (!block_count
) {
458 block_count
= argv
[i
];
464 fprintf(stderr
, _("%s: does not support swapspace version %d.\n"),
465 program_name
, version
);
471 if (uuid_parse(opt_uuid
, uuid_dat
) != 0)
472 die(_("error: UUID parsing failed"));
474 uuid_generate(uuid_dat
);
478 init_signature_page(); /* get pagesize */
482 _("%s: error: Nowhere to set up swap on?\n"),
487 /* this silly user specified the number of blocks
490 int blocks_per_page
= pagesize
/1024;
491 PAGES
= strtoull(block_count
,&tmp
,0)/blocks_per_page
;
495 sz
= get_size(device_name
);
498 } else if (PAGES
> sz
&& !force
) {
501 "size %llu KiB is larger than device size %llu KiB\n"),
503 PAGES
*(pagesize
/1024), sz
*(pagesize
/1024));
507 if (PAGES
< MIN_GOODPAGES
) {
509 _("%s: error: swap area needs to be at least %ld KiB\n"),
510 program_name
, (long)(MIN_GOODPAGES
* pagesize
/1024));
515 if (get_linux_version() >= KERNEL_VERSION(2,3,4))
516 maxpages
= UINT_MAX
+ 1ULL;
517 else if (get_linux_version() >= KERNEL_VERSION(2,2,1))
518 maxpages
= V1_MAX_PAGES
;
521 maxpages
= V1_OLD_MAX_PAGES
;
523 if (PAGES
> maxpages
) {
526 _("%s: warning: truncating swap area to %llu KiB\n"),
527 program_name
, PAGES
* pagesize
/ 1024);
530 if (stat(device_name
, &statbuf
) < 0) {
534 if (S_ISBLK(statbuf
.st_mode
))
535 DEV
= open(device_name
, O_RDWR
| O_EXCL
);
537 DEV
= open(device_name
, O_RDWR
);
544 /* Want a block device. Probably not /dev/hda or /dev/hdb. */
545 if (!S_ISBLK(statbuf
.st_mode
))
547 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340) {
550 "will not try to make swapdevice on '%s'\n"),
551 program_name
, device_name
);
553 } else if (check_mount()) {
556 "%s is mounted; will not make swapspace.\n"),
557 program_name
, device_name
);
565 p
->last_page
= PAGES
-1;
566 p
->nr_badpages
= badpages
;
568 if (badpages
> PAGES
- MIN_GOODPAGES
)
569 die(_("Unable to set up swap-space: unreadable"));
571 goodpages
= PAGES
- badpages
- 1;
572 printf(_("Setting up swapspace version 1, size = %llu KiB\n"),
573 goodpages
* pagesize
/ 1024);
575 write_signature("SWAPSPACE2");
576 write_uuid_and_label(uuid
, opt_label
);
579 if (lseek(DEV
, offset
, SEEK_SET
) != offset
)
580 die(_("unable to rewind swap-device"));
581 if (write_all(DEV
, (char *) signature_page
+ offset
,
582 pagesize
- offset
) == -1) {
583 fprintf(stderr
, _("%s: %s: unable to write signature page: %s"),
584 program_name
, device_name
, strerror(errno
));
589 * A subsequent swapon() will fail if the signature
590 * is not actually on disk. (This is a kernel bug.)
594 die(_("fsync failed"));
597 #ifdef HAVE_LIBSELINUX
598 if (S_ISREG(statbuf
.st_mode
) && is_selinux_enabled() > 0) {
599 security_context_t context_string
;
600 security_context_t oldcontext
;
601 context_t newcontext
;
603 if (fgetfilecon(DEV
, &oldcontext
) < 0) {
604 if (errno
!= ENODATA
) {
605 fprintf(stderr
, _("%s: %s: unable to obtain selinux file label: %s\n"),
606 program_name
, device_name
,
610 if (matchpathcon(device_name
, statbuf
.st_mode
, &oldcontext
))
611 die(_("unable to matchpathcon()"));
613 if (!(newcontext
= context_new(oldcontext
)))
614 die(_("unable to create new selinux context"));
615 if (context_type_set(newcontext
, SELINUX_SWAPFILE_TYPE
))
616 die(_("couldn't compute selinux context"));
618 context_string
= context_str(newcontext
);
620 if (strcmp(context_string
, oldcontext
)!=0) {
621 if (fsetfilecon(DEV
, context_string
)) {
622 fprintf(stderr
, _("%s: unable to relabel %s to %s: %s\n"),
623 program_name
, device_name
,
629 context_free(newcontext
);