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