]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/mkswap.c
Imported from util-linux-2.11x tarball.
[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 <sys/ioctl.h> /* for _IO */
40 #include <sys/utsname.h>
41 #include <sys/stat.h>
42 #include "nls.h"
43
44 /* Try to get PAGE_SIZE from libc or kernel includes */
45 #ifdef HAVE_sys_user_h
46 /* Note: <sys/user.h> says: for gdb only */
47 #include <sys/user.h> /* for PAGE_SIZE and PAGE_SHIFT */
48 #else
49 #ifdef HAVE_asm_page_h
50 #include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
51 /* we also get PAGE_SIZE via getpagesize() */
52 #endif
53 #endif
54
55 #ifndef _IO
56 /* pre-1.3.45 */
57 #define BLKGETSIZE 0x1260
58 #else
59 /* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
60 #define BLKGETSIZE _IO(0x12,96)
61 #endif
62
63 static char * program_name = "mkswap";
64 static char * device_name = NULL;
65 static int DEV = -1;
66 static long PAGES = 0;
67 static int check = 0;
68 static int badpages = 0;
69 static int version = -1;
70
71 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
72
73 static int
74 linux_version_code(void) {
75 struct utsname my_utsname;
76 int p, q, r;
77
78 if (uname(&my_utsname) == 0) {
79 p = atoi(strtok(my_utsname.release, "."));
80 q = atoi(strtok(NULL, "."));
81 r = atoi(strtok(NULL, "."));
82 return MAKE_VERSION(p,q,r);
83 }
84 return 0;
85 }
86
87 #ifdef __sparc__
88 # ifdef __arch64__
89 # define is_sparc64() 1
90 # define is_be64() 1
91 # else /* sparc32 */
92 static int
93 is_sparc64(void) {
94 struct utsname un;
95 static int sparc64 = -1;
96
97 if (sparc64 != -1) return sparc64;
98 sparc64 = 0;
99
100 if (uname(&un) < 0) return 0;
101 if (! strcmp(un.machine, "sparc64")) {
102 sparc64 = 1;
103 return 1;
104 }
105 if (strcmp(un.machine, "sparc"))
106 return 0; /* Should not happen */
107
108 #ifdef HAVE_personality
109 {
110 extern int personality(unsigned long);
111 int oldpers;
112 #define PERS_LINUX 0x00000000
113 #define PERS_LINUX_32BIT 0x00800000
114 #define PERS_LINUX32 0x00000008
115
116 oldpers = personality(PERS_LINUX_32BIT);
117 if (oldpers != -1) {
118 if (personality(PERS_LINUX) != -1) {
119 uname(&un);
120 if (! strcmp(un.machine, "sparc64")) {
121 sparc64 = 1;
122 oldpers = PERS_LINUX32;
123 }
124 }
125 personality(oldpers);
126 }
127 }
128 #endif
129
130 return sparc64;
131 }
132 # define is_be64() is_sparc64()
133 # endif /* sparc32 */
134 #else /* !sparc */
135 # define is_be64() 0
136 #endif
137
138 /*
139 * The definition of the union swap_header uses the constant PAGE_SIZE.
140 * Unfortunately, on some architectures this depends on the hardware model,
141 * and can only be found at run time -- we use getpagesize(), so that
142 * we do not need separate binaries e.g. for sun4, sun4c/d/m and sun4u.
143 *
144 * Even more unfortunately, getpagesize() does not always return
145 * the right information. For example, libc4 and libc5 do not use
146 * the system call but invent a value themselves
147 * (EXEC_PAGESIZE or NBPG * CLSIZE or NBPC), and thus it may happen
148 * that e.g. on a sparc PAGE_SIZE=4096 and getpagesize() returns 8192.
149 * What to do? Let us allow the user to specify the pagesize explicitly.
150 */
151
152 static int user_pagesize = 0;
153 static int kernel_pagesize; /* obtained via getpagesize(); */
154 static int defined_pagesize = 0; /* PAGE_SIZE, when that exists */
155 static int pagesize;
156 static long *signature_page;
157
158 struct swap_header_v1 {
159 char bootbits[1024]; /* Space for disklabel etc. */
160 unsigned int version;
161 unsigned int last_page;
162 unsigned int nr_badpages;
163 unsigned int padding[125];
164 unsigned int badpages[1];
165 } *p;
166
167 static void
168 init_signature_page(void) {
169 #ifdef PAGE_SIZE
170 defined_pagesize = PAGE_SIZE;
171 #endif
172 kernel_pagesize = getpagesize();
173 pagesize = kernel_pagesize;
174
175 if (user_pagesize) {
176 if ((user_pagesize & (user_pagesize-1)) ||
177 user_pagesize < 1024) {
178 fprintf(stderr, _("Bad user-specified page size %d\n"),
179 user_pagesize);
180 exit(1);
181 }
182 pagesize = user_pagesize;
183 }
184
185 if (user_pagesize && user_pagesize != kernel_pagesize &&
186 user_pagesize != defined_pagesize)
187 fprintf(stderr, _("Using user-specified page size %d, "
188 "instead of the system values %d/%d\n"),
189 pagesize, kernel_pagesize, defined_pagesize);
190 else if (defined_pagesize && pagesize != defined_pagesize)
191 fprintf(stderr, _("Assuming pages of size %d (not %d)\n"),
192 pagesize, defined_pagesize);
193
194 signature_page = (long *) malloc(pagesize);
195 memset(signature_page,0,pagesize);
196 p = (struct swap_header_v1 *) signature_page;
197 }
198
199 static void
200 write_signature(char *sig) {
201 char *sp = (char *) signature_page;
202
203 strncpy(sp+pagesize-10, sig, 10);
204 }
205
206 /*
207 * Find out what the maximum amount of swap space is that the kernel will
208 * handle. This wouldn't matter if the kernel just used as much of the
209 * swap space as it can handle, but until 2.3.4 it would return an error
210 * to swapon() if the swapspace was too large.
211 */
212 #define V0_MAX_PAGES (8 * (pagesize - 10))
213 /* Before 2.2.0pre9 */
214 #define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
215 /* Since 2.2.0pre9, before 2.3.4:
216 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
217 with variations on
218 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
219 #define SWP_OFFSET(entry) ((entry) >> 8)
220 on the various architectures. Below the result - yuk.
221
222 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
223 i386 2^12 o<<8 e>>8 1<<24 1<<19
224 mips 2^12 o<<15 e>>15 1<<17 1<<19
225 alpha 2^13 o<<40 e>>40 1<<24 1<<18
226 m68k 2^12 o<<12 e>>12 1<<20 1<<19
227 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
228 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
229 ppc 2^12 o<<8 e>>8 1<<24 1<<19
230 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
231 armv 2^12 o<<9 e>>9 1<<23 1<<19
232
233 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
234
235 The bad part is that we need to know this since the kernel will
236 refuse a swap space if it is too large.
237 */
238 /* patch from jj - why does this differ from the above? */
239 /* 32bit kernels have a second limitation of 2GB, sparc64 is limited by
240 the size of virtual address space allocation for vmalloc */
241 #if defined(__alpha__)
242 #define V1_MAX_PAGES ((1 << 24) - 1)
243 #elif defined(__mips__)
244 #define V1_MAX_PAGES ((1 << 17) - 1)
245 #elif defined(__sparc__)
246 #define V1_MAX_PAGES (is_sparc64() ? ((3 << 29) - 1) : ((1 << 18) - 1))
247 #elif defined(__ia64__)
248 /*
249 * The actual size will depend on the amount of virtual address space
250 * available to vmalloc the swap map.
251 */
252 #define V1_MAX_PAGES ((1UL << 54) - 1)
253 #else
254 #define V1_MAX_PAGES V1_OLD_MAX_PAGES
255 #endif
256 /* man page now says:
257 The maximum useful size of a swap area now depends on the architecture.
258 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
259 128GB on alpha and 3TB on sparc64.
260 */
261
262 #define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
263
264 /*
265 * One more point of lossage - Linux swapspace really is a mess.
266 * The definition of the bitmap used is architecture dependent,
267 * and requires one to know whether the machine is bigendian,
268 * and if so, whether it will use 32-bit or 64-bit units in
269 * test_bit().
270 * davem writes: "... is based upon an unsigned long type of
271 * the cpu and the native endianness".
272 * So, it seems we can write `unsigned long' below.
273 * However, sparc64 uses 64-bit units in the kernel, while
274 * mkswap may have been translated with 32-bit longs. Thus,
275 * we need an explicit test for version 0 swap on sparc64.
276 */
277
278 static void
279 bit_set (unsigned long *addr, unsigned int nr) {
280 unsigned int r, m;
281
282 if(is_be64()) {
283 unsigned long long *bitmap = (unsigned long long *) addr;
284 unsigned long long bitnum = (unsigned long long) nr;
285 unsigned long long rl, ml;
286
287 bitmap += bitnum / (8 * sizeof(long long));
288 rl = *bitmap;
289 ml = 1ULL << (bitnum & (8ULL * sizeof(long long) - 1ULL));
290 *bitmap = rl | ml;
291 return;
292 }
293
294 addr += nr / (8 * sizeof(unsigned long));
295 r = *addr;
296 m = 1 << (nr & (8 * sizeof(unsigned long) - 1));
297 *addr = r | m;
298 }
299
300 static int
301 bit_test_and_clear (unsigned long *addr, unsigned int nr) {
302 unsigned int r, m;
303
304 if(is_be64()) {
305 unsigned long long *bitmap = (unsigned long long *) addr;
306 unsigned long long bitnum = (unsigned long long) nr;
307 unsigned long long rl, ml;
308
309 bitmap += bitnum / (8 * sizeof(long long));
310 rl = *bitmap;
311 ml = 1ULL << (bitnum & (8ULL * sizeof(long long) - 1ULL));
312 *bitmap = rl & ~ml;
313 return ((rl & ml) != 0ULL);
314 }
315
316 addr += nr / (8 * sizeof(unsigned long));
317 r = *addr;
318 m = 1 << (nr & (8 * sizeof(unsigned long) - 1));
319 *addr = r & ~m;
320 return (r & m) != 0;
321 }
322
323 static void
324 usage(void) {
325 fprintf(stderr,
326 _("Usage: %s [-c] [-v0|-v1] [-pPAGESZ] /dev/name [blocks]\n"),
327 program_name);
328 exit(1);
329 }
330
331 static void
332 die(const char *str) {
333 fprintf(stderr, "%s: %s\n", program_name, str);
334 exit(1);
335 }
336
337 static void
338 page_ok(int page) {
339 if (version==0)
340 bit_set(signature_page, page);
341 }
342
343 static void
344 page_bad(int page) {
345 if (version == 0)
346 bit_test_and_clear(signature_page, page);
347 else {
348 if (badpages == MAX_BADPAGES)
349 die(_("too many bad pages"));
350 p->badpages[badpages] = page;
351 }
352 badpages++;
353 }
354
355 static void
356 check_blocks(void) {
357 unsigned int current_page;
358 int do_seek = 1;
359 char *buffer;
360
361 buffer = malloc(pagesize);
362 if (!buffer)
363 die(_("Out of memory"));
364 current_page = 0;
365 while (current_page < PAGES) {
366 if (!check) {
367 page_ok(current_page++);
368 continue;
369 }
370 if (do_seek && lseek(DEV,current_page*pagesize,SEEK_SET) !=
371 current_page*pagesize)
372 die(_("seek failed in check_blocks"));
373 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
374 page_bad(current_page++);
375 continue;
376 }
377 page_ok(current_page++);
378 }
379 if (badpages == 1)
380 printf(_("one bad page\n"));
381 else if (badpages > 1)
382 printf(_("%d bad pages\n"), badpages);
383 }
384
385 static long
386 valid_offset (int fd, off_t offset) {
387 char ch;
388
389 if (lseek (fd, offset, 0) < 0)
390 return 0;
391 if (read (fd, &ch, 1) < 1)
392 return 0;
393 return 1;
394 }
395
396 static off_t
397 find_size (int fd) {
398 off_t high, low;
399
400 low = 0;
401 for (high = 1; high > 0 && valid_offset (fd, high); high *= 2)
402 low = high;
403 while (low < high - 1) {
404 const off_t mid = (low + high) / 2;
405
406 if (valid_offset (fd, mid))
407 low = mid;
408 else
409 high = mid;
410 }
411 return (low + 1);
412 }
413
414 /* return size in pages, to avoid integer overflow */
415 static long
416 get_size(const char *file) {
417 int fd;
418 long size;
419
420 fd = open(file, O_RDONLY);
421 if (fd < 0) {
422 perror(file);
423 exit(1);
424 }
425 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
426 int sectors_per_page = pagesize/512;
427 size /= sectors_per_page;
428 } else {
429 size = find_size(fd) / pagesize;
430 }
431 close(fd);
432 return size;
433 }
434
435 static int
436 isnzdigit(char c) {
437 return (c >= '1' && c <= '9');
438 }
439
440 int
441 main(int argc, char ** argv) {
442 struct stat statbuf;
443 int i, sz;
444 long maxpages;
445 long goodpages;
446 off_t offset;
447 int force = 0;
448 char *block_count = 0;
449 char *pp;
450
451 program_name = (argc && *argv) ? argv[0] : "fsck.minix";
452 if ((pp = strrchr(program_name, '/')) != NULL)
453 program_name = pp+1;
454
455 setlocale(LC_ALL, "");
456 bindtextdomain(PACKAGE, LOCALEDIR);
457 textdomain(PACKAGE);
458
459 if (argc == 2 &&
460 (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) {
461 printf(_("%s from %s\n"), program_name, util_linux_version);
462 exit(0);
463 }
464
465 for (i=1; i<argc; i++) {
466 if (argv[i][0] == '-') {
467 switch (argv[i][1]) {
468 case 'c':
469 check=1;
470 break;
471 case 'f':
472 force=1;
473 break;
474 case 'p':
475 pp = argv[i]+2;
476 if (!*pp && i+1 < argc)
477 pp = argv[++i];
478 if (isnzdigit(*pp))
479 user_pagesize=atoi(pp);
480 else
481 usage();
482 break;
483 case 'v':
484 version = atoi(argv[i]+2);
485 break;
486 default:
487 usage();
488 }
489 } else if (!device_name) {
490 device_name = argv[i];
491 } else if (!block_count) {
492 block_count = argv[i];
493 } else
494 usage();
495 }
496
497 init_signature_page(); /* get pagesize */
498
499 if (!device_name) {
500 fprintf(stderr,
501 _("%s: error: Nowhere to set up swap on?\n"),
502 program_name);
503 usage();
504 }
505 if (block_count) {
506 /* this silly user specified the number of blocks
507 explicitly */
508 char *tmp;
509 int blocks_per_page = pagesize/1024;
510 PAGES = strtol(block_count,&tmp,0)/blocks_per_page;
511 if (*tmp)
512 usage();
513 }
514 sz = get_size(device_name);
515 if (!PAGES) {
516 PAGES = sz;
517 } else if (PAGES > sz && !force) {
518 fprintf(stderr,
519 _("%s: error: "
520 "size %ld is larger than device size %d\n"),
521 program_name,
522 PAGES*(pagesize/1024), sz*(pagesize/1024));
523 exit(1);
524 }
525
526 if (version == -1) {
527 /* use version 1 as default, if possible */
528 if (PAGES <= V0_MAX_PAGES && PAGES > V1_MAX_PAGES)
529 version = 0;
530 else if (linux_version_code() < MAKE_VERSION(2,1,117))
531 version = 0;
532 else if (pagesize < 2048)
533 version = 0;
534 else
535 version = 1;
536 }
537 if (version != 0 && version != 1) {
538 fprintf(stderr, _("%s: error: unknown version %d\n"),
539 program_name, version);
540 usage();
541 }
542
543 if (PAGES < 10) {
544 fprintf(stderr,
545 _("%s: error: swap area needs to be at least %ldkB\n"),
546 program_name, (long)(10 * pagesize / 1000));
547 usage();
548 }
549
550 if (version == 0)
551 maxpages = V0_MAX_PAGES;
552 else if (linux_version_code() >= MAKE_VERSION(2,3,4))
553 maxpages = PAGES;
554 else if (linux_version_code() >= MAKE_VERSION(2,2,1))
555 maxpages = V1_MAX_PAGES;
556 else
557 maxpages = V1_OLD_MAX_PAGES;
558
559 if (PAGES > maxpages) {
560 PAGES = maxpages;
561 fprintf(stderr,
562 _("%s: warning: truncating swap area to %ldkB\n"),
563 program_name, PAGES * pagesize / 1000);
564 }
565
566 DEV = open(device_name,O_RDWR);
567 if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
568 perror(device_name);
569 exit(1);
570 }
571
572 /* Want a block device. Probably not /dev/hda or /dev/hdb. */
573 if (!S_ISBLK(statbuf.st_mode))
574 check=0;
575 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
576 die(_("Will not try to make swapdevice on '%s'"));
577
578 #ifdef __sparc__
579 if (!force && version == 0) {
580 /* Don't overwrite partition table unless forced */
581 unsigned char *buffer = (unsigned char *)signature_page;
582 unsigned short *q, sum;
583
584 if (read(DEV, buffer, 512) != 512)
585 die(_("fatal: first page unreadable"));
586 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
587 q = (unsigned short *)(buffer + 510);
588 for (sum = 0; q >= (unsigned short *) buffer;)
589 sum ^= *q--;
590 if (!sum) {
591 fprintf(stderr, _("\
592 %s: Device '%s' contains a valid Sun disklabel.\n\
593 This probably means creating v0 swap would destroy your partition table\n\
594 No swap created. If you really want to create swap v0 on that device, use\n\
595 the -f option to force it.\n"),
596 program_name, device_name);
597 exit(1);
598 }
599 }
600 }
601 #endif
602
603 if (version == 0 || check)
604 check_blocks();
605 if (version == 0 && !bit_test_and_clear(signature_page,0))
606 die(_("fatal: first page unreadable"));
607 if (version == 1) {
608 p->version = version;
609 p->last_page = PAGES-1;
610 p->nr_badpages = badpages;
611 }
612
613 goodpages = PAGES - badpages - 1;
614 if (goodpages <= 0)
615 die(_("Unable to set up swap-space: unreadable"));
616 printf(_("Setting up swapspace version %d, size = %llu kB\n"),
617 version, (unsigned long long)goodpages * pagesize / 1000);
618 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
619
620 offset = ((version == 0) ? 0 : 1024);
621 if (lseek(DEV, offset, SEEK_SET) != offset)
622 die(_("unable to rewind swap-device"));
623 if (write(DEV,(char*)signature_page+offset, pagesize-offset)
624 != pagesize-offset)
625 die(_("unable to write signature page"));
626
627 /*
628 * A subsequent swapon() will fail if the signature
629 * is not actually on disk. (This is a kernel bug.)
630 */
631 #ifdef HAVE_fsync
632 if (fsync(DEV))
633 die(_("fsync failed"));
634 #endif
635 return 0;
636 }