]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/mkswap.c
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 * Usuage: 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.
33 #include <sys/ioctl.h> /* for _IO */
34 #include <sys/utsname.h>
36 #include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
40 #define BLKGETSIZE 0x1260
42 /* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
43 #define BLKGETSIZE _IO(0x12,96)
46 static char * program_name
= "mkswap";
47 static char * device_name
= NULL
;
49 static long PAGES
= 0;
51 static int badpages
= 0;
52 static int version
= -1;
54 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
57 linux_version_code(void) {
58 struct utsname my_utsname
;
61 if (uname(&my_utsname
) == 0) {
62 p
= atoi(strtok(my_utsname
.release
, "."));
63 q
= atoi(strtok(NULL
, "."));
64 r
= atoi(strtok(NULL
, "."));
65 return MAKE_VERSION(p
,q
,r
);
71 * The definition of the union swap_header uses the constant PAGE_SIZE.
72 * Unfortunately, on some architectures this depends on the hardware model,
73 * and can only be found at run time -- we use getpagesize().
77 static int *signature_page
;
79 struct swap_header_v1
{
80 char bootbits
[1024]; /* Space for disklabel etc. */
82 unsigned int last_page
;
83 unsigned int nr_badpages
;
84 unsigned int padding
[125];
85 unsigned int badpages
[1];
89 init_signature_page() {
90 pagesize
= getpagesize();
93 if (pagesize
!= PAGE_SIZE
)
94 fprintf(stderr
, "Assuming pages of size %d\n", pagesize
);
96 signature_page
= (int *) malloc(pagesize
);
97 memset(signature_page
,0,pagesize
);
98 p
= (struct swap_header_v1
*) signature_page
;
102 write_signature(char *sig
) {
103 char *sp
= (char *) signature_page
;
105 strncpy(sp
+pagesize
-10, sig
, 10);
108 #define V0_MAX_PAGES (8 * (pagesize - 10))
109 #define V1_MAX_PAGES ((0x7fffffff / pagesize) - 1)
111 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
113 static void bit_set (unsigned int *addr
, unsigned int nr
)
117 addr
+= nr
/ (8 * sizeof(int));
119 m
= 1 << (nr
& (8 * sizeof(int) - 1));
123 static int bit_test_and_clear (unsigned int *addr
, unsigned int nr
)
127 addr
+= nr
/ (8 * sizeof(int));
129 m
= 1 << (nr
& (8 * sizeof(int) - 1));
134 void fatal_error(const char * fmt_string
)
136 fprintf(stderr
,fmt_string
,program_name
,device_name
);
140 #define usage() fatal_error("Usage: %s [-c] [-v0|-v1] /dev/name [blocks]\n")
141 #define die(str) fatal_error("%s: " str "\n")
146 bit_set(signature_page
, page
);
152 bit_test_and_clear(signature_page
, page
);
154 if (badpages
== MAX_BADPAGES
)
155 die("too many bad pages");
156 p
->badpages
[badpages
] = page
;
163 unsigned int current_page
;
167 buffer
= malloc(pagesize
);
169 die("Out of memory");
171 while (current_page
< PAGES
) {
173 page_ok(current_page
++);
176 if (do_seek
&& lseek(DEV
,current_page
*pagesize
,SEEK_SET
) !=
177 current_page
*pagesize
)
178 die("seek failed in check_blocks");
179 if ((do_seek
= (pagesize
!= read(DEV
, buffer
, pagesize
)))) {
180 page_bad(current_page
++);
183 page_ok(current_page
++);
186 printf("%d bad page%s\n",badpages
,(badpages
>1)?"s":"");
189 static long valid_offset (int fd
, int offset
)
193 if (lseek (fd
, offset
, 0) < 0)
195 if (read (fd
, &ch
, 1) < 1)
203 unsigned int high
, low
;
206 for (high
= 1; high
> 0 && valid_offset (fd
, high
); high
*= 2)
208 while (low
< high
- 1)
210 const int mid
= (low
+ high
) / 2;
212 if (valid_offset (fd
, mid
))
220 /* return size in pages, to avoid integer overflow */
222 get_size(const char *file
)
227 fd
= open(file
, O_RDONLY
);
232 if (ioctl(fd
, BLKGETSIZE
, &size
) >= 0) {
233 int sectors_per_page
= pagesize
/512;
234 size
/= sectors_per_page
;
236 size
= find_size(fd
) / pagesize
;
242 int main(int argc
, char ** argv
)
252 program_name
= *argv
;
254 init_signature_page(); /* get pagesize */
258 if (argv
[0][0] != '-') {
260 int blocks_per_page
= pagesize
/1024;
261 PAGES
= strtol(argv
[0],&tmp
,0)/blocks_per_page
;
265 device_name
= argv
[0];
267 switch (argv
[0][1]) {
275 version
=atoi(argv
[0]+2);
284 "%s: error: Nowhere to set up swap on?\n",
289 PAGES
= get_size(device_name
);
293 if (PAGES
<= V0_MAX_PAGES
)
295 else if (linux_version_code() < MAKE_VERSION(2,1,117))
297 else if (pagesize
< 2048)
302 if (version
!= 0 && version
!= 1) {
303 fprintf(stderr
, "%s: error: unknown version %d\n",
304 program_name
, version
);
309 "%s: error: swap area needs to be at least %ldkB\n",
310 program_name
, (long)(10 * pagesize
/ 1024));
313 maxpages
= ((version
== 0) ? V0_MAX_PAGES
: V1_MAX_PAGES
);
314 if (PAGES
> maxpages
) {
316 fprintf(stderr
, "%s: warning: truncating swap area to %ldkB\n",
317 program_name
, PAGES
* pagesize
/ 1024);
320 DEV
= open(device_name
,O_RDWR
);
321 if (DEV
< 0 || fstat(DEV
, &statbuf
) < 0) {
325 if (!S_ISBLK(statbuf
.st_mode
))
327 else if (statbuf
.st_rdev
== 0x0300 || statbuf
.st_rdev
== 0x0340)
328 die("Will not try to make swapdevice on '%s'");
331 if (!force
&& version
== 0) {
332 /* Don't overwrite partition table unless forced */
333 unsigned char *buffer
= (unsigned char *)signature_page
;
334 unsigned short *q
, sum
;
336 if (read(DEV
, buffer
, 512) != 512)
337 die("fatal: first page unreadable");
338 if (buffer
[508] == 0xDA && buffer
[509] == 0xBE) {
339 q
= (unsigned short *)(buffer
+ 510);
340 for (sum
= 0; q
>= (unsigned short *) buffer
;)
344 %s: Device '%s' contains a valid Sun disklabel.\n\
345 This probably means creating v0 swap would destroy your partition table\n\
346 No swap created. If you really want to create swap v0 on that device, use\n\
347 the -f option to force it.\n",
348 program_name
, device_name
);
355 if (version
== 0 || check
)
357 if (version
== 0 && !bit_test_and_clear(signature_page
,0))
358 die("fatal: first page unreadable");
360 p
->version
= version
;
361 p
->last_page
= PAGES
-1;
362 p
->nr_badpages
= badpages
;
365 goodpages
= PAGES
- badpages
- 1;
367 die("Unable to set up swap-space: unreadable");
368 printf("Setting up swapspace version %d, size = %ld bytes\n",
369 version
, (long)(goodpages
*pagesize
));
370 write_signature((version
== 0) ? "SWAP-SPACE" : "SWAPSPACE2");
372 offset
= ((version
== 0) ? 0 : 1024);
373 if (lseek(DEV
, offset
, SEEK_SET
) != offset
)
374 die("unable to rewind swap-device");
375 if (write(DEV
,(char*)signature_page
+offset
, pagesize
-offset
)
377 die("unable to write signature page");
380 * A subsequent swapon() will fail if the signature
381 * is not actually on disk. (This is a kernel bug.)