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