blob: 44d809a3677015653586c5d0404ec620f05b2740 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
3 * mkswap.c - set up a linux swap device
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 *
Eric Andersene77ae3a1999-10-19 20:03:34 +000012 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
Eric Andersencc8ed391999-10-05 16:24:54 +000013 *
Eric Andersene77ae3a1999-10-19 20:03:34 +000014 * -c for readability checking. (Use it unless you are SURE!)
15 * -vN for swap areas version N. (Only N=0,1 known today.)
16 * -f for forcing swap creation even if it would smash partition table.
Eric Andersencc8ed391999-10-05 16:24:54 +000017 *
Eric Andersene77ae3a1999-10-19 20:03:34 +000018 * The device may be a block device or an image of one, but this isn't
Eric Andersencc8ed391999-10-05 16:24:54 +000019 * enforced (but it's not much fun on a character device :-).
20 *
21 * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the
22 * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995.
Eric Andersene77ae3a1999-10-19 20:03:34 +000023 *
24 * Version 1 swap area code (for kernel 2.1.117), aeb, 981010.
25 *
26 * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb.
27 * V1_MAX_PAGES fixes, jj, 990325.
28 *
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
30 * - added Native Language Support
31 *
32 * from util-linux -- adapted for busybox by
Eric Andersencb81e642003-07-14 21:21:08 +000033 * Erik Andersen <andersen@codepoet.org>. I ripped out Native Language
Eric Andersene77ae3a1999-10-19 20:03:34 +000034 * Support, made some stuff smaller, and fitted for life in busybox.
35 *
Eric Andersencc8ed391999-10-05 16:24:54 +000036 */
37
38#include <stdio.h>
39#include <unistd.h>
40#include <string.h>
41#include <fcntl.h>
42#include <stdlib.h>
Erik Andersene49d5ec2000-02-08 19:58:47 +000043#include <sys/ioctl.h> /* for _IO */
Eric Andersene77ae3a1999-10-19 20:03:34 +000044#include <sys/utsname.h>
Erik Andersene49d5ec2000-02-08 19:58:47 +000045#include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
Eric Andersene77ae3a1999-10-19 20:03:34 +000046 /* we also get PAGE_SIZE via getpagesize() */
Eric Andersencbe31da2001-02-20 06:14:08 +000047#include "busybox.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000048
Eric Andersene77ae3a1999-10-19 20:03:34 +000049#ifndef _IO
50/* pre-1.3.45 */
Rob Landleybc68cd12006-03-10 19:22:06 +000051enum { BLKGETSIZE = 0x1260 };
Eric Andersene77ae3a1999-10-19 20:03:34 +000052#else
53/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
54#define BLKGETSIZE _IO(0x12,96)
Eric Andersencc8ed391999-10-05 16:24:54 +000055#endif
56
Erik Andersene49d5ec2000-02-08 19:58:47 +000057static char *device_name = NULL;
Eric Andersencc8ed391999-10-05 16:24:54 +000058static int DEV = -1;
59static long PAGES = 0;
Eric Andersene77ae3a1999-10-19 20:03:34 +000060static int check = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +000061static int badpages = 0;
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +000062#if ENABLE_FEATURE_MKSWAP_V0
Eric Andersene77ae3a1999-10-19 20:03:34 +000063static int version = -1;
Eric Andersene77ae3a1999-10-19 20:03:34 +000064#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +000065#else
66#define version 1
67/* and make sure that we optimize away anything which would deal with checking
68 * the kernel revision as we have v1 support only anyway.
69 */
70#define MAKE_VERSION(p,q,r) 1
71#define get_kernel_revision() 1
72#endif
Eric Andersencc8ed391999-10-05 16:24:54 +000073
Eric Andersene77ae3a1999-10-19 20:03:34 +000074/*
75 * The definition of the union swap_header uses the constant PAGE_SIZE.
76 * Unfortunately, on some architectures this depends on the hardware model,
77 * and can only be found at run time -- we use getpagesize().
78 */
79
80static int pagesize;
Eric Andersen3496fdc2006-01-30 23:09:20 +000081static unsigned int *signature_page;
Eric Andersene77ae3a1999-10-19 20:03:34 +000082
Eric Andersen3e6ff902001-03-09 21:24:12 +000083static struct swap_header_v1 {
Erik Andersene49d5ec2000-02-08 19:58:47 +000084 char bootbits[1024]; /* Space for disklabel etc. */
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +000085 unsigned int swap_version;
Eric Andersene77ae3a1999-10-19 20:03:34 +000086 unsigned int last_page;
87 unsigned int nr_badpages;
88 unsigned int padding[125];
89 unsigned int badpages[1];
90} *p;
91
Eric Andersenfcffa2c2002-04-06 05:17:57 +000092static inline void init_signature_page(void)
Erik Andersene49d5ec2000-02-08 19:58:47 +000093{
Eric Andersene77ae3a1999-10-19 20:03:34 +000094 pagesize = getpagesize();
95
96#ifdef PAGE_SIZE
97 if (pagesize != PAGE_SIZE)
Manuel Novoa III cad53642003-03-19 09:13:01 +000098 bb_error_msg("Assuming pages of size %d", pagesize);
Eric Andersene77ae3a1999-10-19 20:03:34 +000099#endif
Eric Andersen3496fdc2006-01-30 23:09:20 +0000100 signature_page = (unsigned int *) xmalloc(pagesize);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000101 memset(signature_page, 0, pagesize);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000102 p = (struct swap_header_v1 *) signature_page;
103}
104
Eric Andersenfcffa2c2002-04-06 05:17:57 +0000105static inline void write_signature(char *sig)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000106{
Eric Andersene77ae3a1999-10-19 20:03:34 +0000107 char *sp = (char *) signature_page;
108
Erik Andersene49d5ec2000-02-08 19:58:47 +0000109 strncpy(sp + pagesize - 10, sig, 10);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000110}
111
112#define V0_MAX_PAGES (8 * (pagesize - 10))
113/* Before 2.2.0pre9 */
114#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
115/* Since 2.2.0pre9:
116 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
117 with variations on
118 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
119 #define SWP_OFFSET(entry) ((entry) >> 8)
120 on the various architectures. Below the result - yuk.
121
122 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
123 i386 2^12 o<<8 e>>8 1<<24 1<<19
124 mips 2^12 o<<15 e>>15 1<<17 1<<19
125 alpha 2^13 o<<40 e>>40 1<<24 1<<18
126 m68k 2^12 o<<12 e>>12 1<<20 1<<19
127 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
128 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
129 ppc 2^12 o<<8 e>>8 1<<24 1<<19
130 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
131 armv 2^12 o<<9 e>>9 1<<23 1<<19
132
133 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
134
135 The bad part is that we need to know this since the kernel will
136 refuse a swap space if it is too large.
137*/
138/* patch from jj - why does this differ from the above? */
139#if defined(__alpha__)
140#define V1_MAX_PAGES ((1 << 24) - 1)
141#elif defined(__mips__)
142#define V1_MAX_PAGES ((1 << 17) - 1)
143#elif defined(__sparc_v9__)
144#define V1_MAX_PAGES ((3 << 29) - 1)
145#elif defined(__sparc__)
146#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
147#else
148#define V1_MAX_PAGES V1_OLD_MAX_PAGES
149#endif
150/* man page now says:
151The maximum useful size of a swap area now depends on the architecture.
152It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
153128GB on alpha and 3TB on sparc64.
154*/
155
156#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
157
Eric Andersenfcffa2c2002-04-06 05:17:57 +0000158static inline void bit_set(unsigned int *addr, unsigned int nr)
Eric Andersencc8ed391999-10-05 16:24:54 +0000159{
160 unsigned int r, m;
161
162 addr += nr / (8 * sizeof(int));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000163
Eric Andersencc8ed391999-10-05 16:24:54 +0000164 r = *addr;
165 m = 1 << (nr & (8 * sizeof(int) - 1));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000166
Eric Andersencc8ed391999-10-05 16:24:54 +0000167 *addr = r | m;
Eric Andersencc8ed391999-10-05 16:24:54 +0000168}
169
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
Eric Andersencc8ed391999-10-05 16:24:54 +0000171{
172 unsigned int r, m;
173
174 addr += nr / (8 * sizeof(int));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000175
Eric Andersencc8ed391999-10-05 16:24:54 +0000176 r = *addr;
177 m = 1 << (nr & (8 * sizeof(int) - 1));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000178
Eric Andersencc8ed391999-10-05 16:24:54 +0000179 *addr = r & ~m;
180 return (r & m) != 0;
181}
182
Eric Andersen16fdbe82000-12-20 23:40:57 +0000183static void page_ok(int page)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184{
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000185 if (ENABLE_FEATURE_MKSWAP_V0) {
Eric Andersene77ae3a1999-10-19 20:03:34 +0000186 bit_set(signature_page, page);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000187 }
Eric Andersene77ae3a1999-10-19 20:03:34 +0000188}
189
Eric Andersen16fdbe82000-12-20 23:40:57 +0000190static void check_blocks(void)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000191{
Eric Andersencc8ed391999-10-05 16:24:54 +0000192 unsigned int current_page;
193 int do_seek = 1;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000194 char *buffer;
Eric Andersencc8ed391999-10-05 16:24:54 +0000195
Erik Andersen0d068a22000-03-21 22:32:57 +0000196 buffer = xmalloc(pagesize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000197 current_page = 0;
198 while (current_page < PAGES) {
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000199 if (!check && version == 0) {
Eric Andersene77ae3a1999-10-19 20:03:34 +0000200 page_ok(current_page++);
Eric Andersencc8ed391999-10-05 16:24:54 +0000201 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000202 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
204 current_page * pagesize)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000205 bb_error_msg_and_die("seek failed in check_blocks");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000206 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000207 current_page++;
208 if (version == 0)
209 bit_test_and_clear(signature_page, current_page);
210 else {
211 if (badpages == MAX_BADPAGES)
212 bb_error_msg_and_die("too many bad pages");
213 p->badpages[badpages] = current_page;
214 }
215 badpages++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000216 continue;
217 }
Eric Andersene77ae3a1999-10-19 20:03:34 +0000218 page_ok(current_page++);
Eric Andersencc8ed391999-10-05 16:24:54 +0000219 }
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000220 if (ENABLE_FEATURE_CLEAN_UP)
221 free(buffer);
222 if (badpages > 0)
223 printf("%d bad page%s\n", badpages, (badpages==1)?"":"s");
Eric Andersencc8ed391999-10-05 16:24:54 +0000224}
225
Erik Andersene49d5ec2000-02-08 19:58:47 +0000226static long valid_offset(int fd, int offset)
Eric Andersencc8ed391999-10-05 16:24:54 +0000227{
228 char ch;
229
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230 if (lseek(fd, offset, 0) < 0)
Eric Andersencc8ed391999-10-05 16:24:54 +0000231 return 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000232 if (read(fd, &ch, 1) < 1)
Eric Andersencc8ed391999-10-05 16:24:54 +0000233 return 0;
234 return 1;
235}
236
Erik Andersene49d5ec2000-02-08 19:58:47 +0000237static int find_size(int fd)
Eric Andersencc8ed391999-10-05 16:24:54 +0000238{
Eric Andersene77ae3a1999-10-19 20:03:34 +0000239 unsigned int high, low;
Eric Andersencc8ed391999-10-05 16:24:54 +0000240
241 low = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
Eric Andersencc8ed391999-10-05 16:24:54 +0000243 low = high;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244 while (low < high - 1) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000245 const int mid = (low + high) / 2;
246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 if (valid_offset(fd, mid))
Eric Andersencc8ed391999-10-05 16:24:54 +0000248 low = mid;
249 else
250 high = mid;
251 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000252 return (low + 1);
253}
254
Eric Andersene77ae3a1999-10-19 20:03:34 +0000255/* return size in pages, to avoid integer overflow */
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000256static inline long get_size(const char *file)
Eric Andersencc8ed391999-10-05 16:24:54 +0000257{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000258 int fd;
259 long size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000260
Bernhard Reutner-Fischerc2cb0f32006-04-13 12:45:04 +0000261 fd = bb_xopen3(file, O_RDONLY, 0);
Eric Andersencc8ed391999-10-05 16:24:54 +0000262 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000263 size /= pagesize / 512;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000264 } else {
265 size = find_size(fd) / pagesize;
Eric Andersencc8ed391999-10-05 16:24:54 +0000266 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000267 close(fd);
268 return size;
269}
270
Erik Andersene49d5ec2000-02-08 19:58:47 +0000271int mkswap_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000272{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000273 char *tmp;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000274 struct stat statbuf;
275 int sz;
276 int maxpages;
277 int goodpages;
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000278#ifdef __sparc__
Eric Andersene77ae3a1999-10-19 20:03:34 +0000279 int force = 0;
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000280#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000281
Erik Andersene49d5ec2000-02-08 19:58:47 +0000282 init_signature_page(); /* get pagesize */
Eric Andersene77ae3a1999-10-19 20:03:34 +0000283
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000284 bb_opt_complementally = "?"; /* call bb_show_usage internally */
285 sz = bb_getopt_ulflags(argc, argv, "+cfv:", &tmp);
286 if (sz & 1)
287 check = 1;
288#ifdef __sparc__
289 if (sz & 2)
290 force = 1;
291#endif
292#if ENABLE_FEATURE_MKSWAP_V0
293 if (sz & 4) {
294 version = bb_xgetlarg(tmp, 10, 0, 1);
295 } else {
Glenn L McGrathe64bf402003-10-31 02:04:18 +0000296 if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
Eric Andersene77ae3a1999-10-19 20:03:34 +0000297 version = 0;
298 else
299 version = 1;
300 }
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000301#endif
302
303 argv += optind;
304 argc -= optind;
305
306 goodpages = pagesize / 1024; /* cache division */
307 while (argc--) {
308 if (device_name) {
309 PAGES = bb_xgetlarg(argv[0], 0, 10, sz * goodpages) / goodpages;
310 argc = 0; /* ignore any surplus args.. */
311 } else {
312 device_name = argv[0];
313 sz = get_size(device_name);
314 argv++;
315 }
Eric Andersene77ae3a1999-10-19 20:03:34 +0000316 }
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000317
318 if (!device_name) {
319 bb_error_msg_and_die("error: Nowhere to set up swap on?");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000320 }
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000321 if (!PAGES) {
322 PAGES = sz;
323 }
324
Eric Andersene77ae3a1999-10-19 20:03:34 +0000325#if 0
326 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
327#else
328 if (!version)
329 maxpages = V0_MAX_PAGES;
Eric Andersenef936da2000-10-30 17:22:04 +0000330 else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
Eric Andersene77ae3a1999-10-19 20:03:34 +0000331 maxpages = V1_MAX_PAGES;
332 else {
333 maxpages = V1_OLD_MAX_PAGES;
334 if (maxpages > V1_MAX_PAGES)
335 maxpages = V1_MAX_PAGES;
336 }
337#endif
338 if (PAGES > maxpages) {
339 PAGES = maxpages;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000340 bb_error_msg("warning: truncating swap area to %ldkB",
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000341 PAGES * goodpages);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000342 }
343
Bernhard Reutner-Fischerc2cb0f32006-04-13 12:45:04 +0000344 DEV = bb_xopen3(device_name, O_RDWR, 0);
Bernhard Reutner-Fischerdac7ff12006-04-12 17:55:51 +0000345 if (fstat(DEV, &statbuf) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000346 bb_perror_msg_and_die("%s", device_name);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000347 if (!S_ISBLK(statbuf.st_mode))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000348 check = 0;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000349 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000350 bb_error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000351
352#ifdef __sparc__
353 if (!force && version == 0) {
354 /* Don't overwrite partition table unless forced */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 unsigned char *buffer = (unsigned char *) signature_page;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000356 unsigned short *q, sum;
357
358 if (read(DEV, buffer, 512) != 512)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000359 bb_error_msg_and_die("fatal: first page unreadable");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000360 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000361 q = (unsigned short *) (buffer + 510);
Eric Andersene77ae3a1999-10-19 20:03:34 +0000362 for (sum = 0; q >= (unsigned short *) buffer;)
363 sum ^= *q--;
364 if (!sum) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000365 bb_error_msg("Device '%s' contains a valid Sun disklabel.\n"
Matt Kraaid537a952000-07-14 01:51:25 +0000366"This probably means creating v0 swap would destroy your partition table\n"
367"No swap created. If you really want to create swap v0 on that device, use\n"
Matt Kraaidd19c692001-01-31 19:00:21 +0000368"the -f option to force it.", device_name);
Matt Kraai3e856ce2000-12-01 02:55:13 +0000369 return EXIT_FAILURE;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000370 }
371 }
372 }
373#endif
374
375 if (version == 0 || check)
376 check_blocks();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000377 if (version == 0 && !bit_test_and_clear(signature_page, 0))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000378 bb_error_msg_and_die("fatal: first page unreadable");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000379 if (version == 1) {
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000380 p->swap_version = version;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000381 p->last_page = PAGES - 1;
Eric Andersene77ae3a1999-10-19 20:03:34 +0000382 p->nr_badpages = badpages;
383 }
384
385 goodpages = PAGES - badpages - 1;
386 if (goodpages <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000387 bb_error_msg_and_die("Unable to set up swap-space: unreadable");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000388 printf("Setting up swapspace version %d, size = %ld bytes\n",
Erik Andersene49d5ec2000-02-08 19:58:47 +0000389 version, (long) (goodpages * pagesize));
Eric Andersene77ae3a1999-10-19 20:03:34 +0000390 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
391
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000392 sz = ((version == 0) ? 0 : 1024); /* offset */
393 if (lseek(DEV, sz, SEEK_SET) != sz)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000394 bb_error_msg_and_die("unable to rewind swap-device");
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000395 goodpages = pagesize - sz; /* cache substraction */
396 if (write(DEV, (char *) signature_page + sz, goodpages)
397 != goodpages)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000398 bb_error_msg_and_die("unable to write signature page");
Eric Andersene77ae3a1999-10-19 20:03:34 +0000399
400 /*
401 * A subsequent swapon() will fail if the signature
402 * is not actually on disk. (This is a kernel bug.)
403 */
404 if (fsync(DEV))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000405 bb_error_msg_and_die("fsync failed");
Bernhard Reutner-Fischer56dd0bf2006-03-29 17:32:24 +0000406 if (ENABLE_FEATURE_CLEAN_UP) {
407 close(DEV);
408 free(signature_page);
409 }
Matt Kraai3e856ce2000-12-01 02:55:13 +0000410 return EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +0000411}