aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mkswap.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-07-16 08:17:03 +0000
committerRob Landley <rob@landley.net>2006-07-16 08:17:03 +0000
commitd893b120bae5a9bdef4cfda2df5e62867d6b1cd0 (patch)
treedf39b0abfc8e7575d3a445529f531408098f007f /util-linux/mkswap.c
parent534374755d618c9c36c9940c82756241c4b25a67 (diff)
downloadbusybox-w32-d893b120bae5a9bdef4cfda2df5e62867d6b1cd0.tar.gz
busybox-w32-d893b120bae5a9bdef4cfda2df5e62867d6b1cd0.tar.bz2
busybox-w32-d893b120bae5a9bdef4cfda2df5e62867d6b1cd0.zip
New mkswap. Small and simple. Might even work. :)
Diffstat (limited to 'util-linux/mkswap.c')
-rw-r--r--util-linux/mkswap.c409
1 files changed, 29 insertions, 380 deletions
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c
index 986472e92..9b1e2b5c3 100644
--- a/util-linux/mkswap.c
+++ b/util-linux/mkswap.c
@@ -1,397 +1,46 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/* mkswap.c - format swap device (Linux v1 only)
3 * mkswap.c - set up a linux swap device
4 * 3 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per 4 * Copyright 2006 Rob Landley <rob@landley.net>
6 * the Linux copyright.
7 */
8
9/*
10 * 20.12.91 - time began. Got VM working yesterday by doing this by hand.
11 *
12 * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks]
13 *
14 * -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.
17 *
18 * The device may be a block device or an image of one, but this isn't
19 * 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.
23 *
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 * 5 *
32 * from util-linux -- adapted for busybox by 6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
33 * Erik Andersen <andersen@codepoet.org>. I ripped out Native Language
34 * Support, made some stuff smaller, and fitted for life in busybox.
35 *
36 */
37
38#include "busybox.h"
39#include <unistd.h>
40#include <string.h>
41#include <fcntl.h>
42#include <sys/ioctl.h> /* for _IO */
43#include <sys/utsname.h>
44#include <asm/page.h> /* for PAGE_SIZE and PAGE_SHIFT */
45 /* we also get PAGE_SIZE via getpagesize() */
46
47static char *device_name = NULL;
48static int DEV = -1;
49static long PAGES = 0;
50static int check = 0;
51static int badpages = 0;
52#if ENABLE_FEATURE_MKSWAP_V0
53static int version = -1;
54#else
55#define version 1
56/* and make sure that we optimize away anything which would deal with checking
57 * the kernel revision as we have v1 support only anyway.
58 */ 7 */
59#undef KERNEL_VERSION
60#define KERNEL_VERSION(p,q,r) 1
61#define get_linux_version_code() 1
62#endif
63
64/*
65 * The definition of the union swap_header uses the constant PAGE_SIZE.
66 * Unfortunately, on some architectures this depends on the hardware model,
67 * and can only be found at run time -- we use getpagesize().
68 */
69
70static int pagesize;
71static unsigned int *signature_page;
72
73static struct swap_header_v1 {
74 char bootbits[1024]; /* Space for disklabel etc. */
75 unsigned int swap_version;
76 unsigned int last_page;
77 unsigned int nr_badpages;
78 unsigned int padding[125];
79 unsigned int badpages[1];
80} *p;
81 8
82static inline void init_signature_page(void) 9#include <busybox.h>
83{
84 pagesize = getpagesize();
85 10
86#ifdef PAGE_SIZE 11int mkswap_main(int argc, char *argv[])
87 if (pagesize != PAGE_SIZE)
88 bb_error_msg("Assuming pages of size %d", pagesize);
89#endif
90 signature_page = (unsigned int *) xmalloc(pagesize);
91 memset(signature_page, 0, pagesize);
92 p = (struct swap_header_v1 *) signature_page;
93}
94
95static inline void write_signature(char *sig)
96{ 12{
97 char *sp = (char *) signature_page; 13 int fd, pagesize;
98 14 off_t len;
99 strncpy(sp + pagesize - 10, sig, 10); 15 unsigned int hdr[129];
100}
101
102#define V0_MAX_PAGES (8 * (pagesize - 10))
103/* Before 2.2.0pre9 */
104#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1)
105/* Since 2.2.0pre9:
106 error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
107 with variations on
108 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
109 #define SWP_OFFSET(entry) ((entry) >> 8)
110 on the various architectures. Below the result - yuk.
111
112 Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2
113 i386 2^12 o<<8 e>>8 1<<24 1<<19
114 mips 2^12 o<<15 e>>15 1<<17 1<<19
115 alpha 2^13 o<<40 e>>40 1<<24 1<<18
116 m68k 2^12 o<<12 e>>12 1<<20 1<<19
117 sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18}
118 sparc64 2^13 o<<13 e>>13 1<<51 1<<18
119 ppc 2^12 o<<8 e>>8 1<<24 1<<19
120 armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16}
121 armv 2^12 o<<9 e>>9 1<<23 1<<19
122
123 assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
124 16
125 The bad part is that we need to know this since the kernel will 17 // No options supported.
126 refuse a swap space if it is too large.
127*/
128/* patch from jj - why does this differ from the above? */
129#if defined(__alpha__)
130#define V1_MAX_PAGES ((1 << 24) - 1)
131#elif defined(__mips__)
132#define V1_MAX_PAGES ((1 << 17) - 1)
133#elif defined(__sparc_v9__)
134#define V1_MAX_PAGES ((3 << 29) - 1)
135#elif defined(__sparc__)
136#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
137#else
138#define V1_MAX_PAGES V1_OLD_MAX_PAGES
139#endif
140/* man page now says:
141The maximum useful size of a swap area now depends on the architecture.
142It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
143128GB on alpha and 3TB on sparc64.
144*/
145 18
146#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) 19 if (argc!=2) bb_show_usage();
147
148static inline void bit_set(unsigned int *addr, unsigned int nr)
149{
150 unsigned int r, m;
151
152 addr += nr / (8 * sizeof(int));
153
154 r = *addr;
155 m = 1 << (nr & (8 * sizeof(int) - 1));
156
157 *addr = r | m;
158}
159
160static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
161{
162 unsigned int r, m;
163 20
164 addr += nr / (8 * sizeof(int)); 21 // Figure out how big the device is and announce our intentions.
165 22
166 r = *addr; 23 fd = bb_xopen(argv[1],O_RDWR);
167 m = 1 << (nr & (8 * sizeof(int) - 1)); 24 len = fdlength(fd);
168 25 pagesize = getpagesize();
169 *addr = r & ~m; 26 printf("Setting up swapspace version 1, size = %ld bytes\n", (long)(len-pagesize));
170 return (r & m) != 0;
171}
172
173static void page_ok(int page)
174{
175 if (ENABLE_FEATURE_MKSWAP_V0) {
176 bit_set(signature_page, page);
177 }
178}
179
180static void check_blocks(void)
181{
182 unsigned int current_page;
183 int do_seek = 1;
184 char *buffer;
185
186 buffer = xmalloc(pagesize);
187 current_page = 0;
188 while (current_page < PAGES) {
189 if (!check && version == 0) {
190 page_ok(current_page++);
191 continue;
192 }
193 if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
194 current_page * pagesize)
195 bb_error_msg_and_die("seek failed in check_blocks");
196 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
197 current_page++;
198 if (version == 0)
199 bit_test_and_clear(signature_page, current_page);
200 else {
201 if (badpages == MAX_BADPAGES)
202 bb_error_msg_and_die("too many bad pages");
203 p->badpages[badpages] = current_page;
204 }
205 badpages++;
206 continue;
207 }
208 page_ok(current_page++);
209 }
210 if (ENABLE_FEATURE_CLEAN_UP)
211 free(buffer);
212 if (badpages > 0)
213 printf("%d bad page%s\n", badpages, (badpages==1)?"":"s");
214}
215
216static long valid_offset(int fd, int offset)
217{
218 char ch;
219
220 if (lseek(fd, offset, 0) < 0)
221 return 0;
222 if (read(fd, &ch, 1) < 1)
223 return 0;
224 return 1;
225}
226
227static int find_size(int fd)
228{
229 unsigned int high, low;
230
231 low = 0;
232 for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
233 low = high;
234 while (low < high - 1) {
235 const int mid = (low + high) / 2;
236
237 if (valid_offset(fd, mid))
238 low = mid;
239 else
240 high = mid;
241 }
242 return (low + 1);
243}
244
245/* return size in pages, to avoid integer overflow */
246static inline long get_size(const char *file)
247{
248 int fd;
249 long size;
250
251 fd = bb_xopen3(file, O_RDONLY, 0);
252 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
253 size /= pagesize / 512;
254 } else {
255 size = find_size(fd) / pagesize;
256 }
257 close(fd);
258 return size;
259}
260
261int mkswap_main(int argc, char **argv)
262{
263 char *tmp;
264 struct stat statbuf;
265 int sz;
266 int maxpages;
267 int goodpages;
268#ifdef __sparc__
269 int force = 0;
270#endif
271
272 init_signature_page(); /* get pagesize */
273
274 bb_opt_complementally = "?"; /* call bb_show_usage internally */
275 sz = bb_getopt_ulflags(argc, argv, "+cfv:", &tmp);
276 if (sz & 1)
277 check = 1;
278#ifdef __sparc__
279 if (sz & 2)
280 force = 1;
281#endif
282#if ENABLE_FEATURE_MKSWAP_V0
283 if (sz & 4) {
284 version = bb_xgetlarg(tmp, 10, 0, 1);
285 } else {
286 if (get_linux_version_code() < KERNEL_VERSION(2, 1, 117))
287 version = 0;
288 else
289 version = 1;
290 }
291#endif
292
293 argv += optind;
294 argc -= optind;
295
296 goodpages = pagesize / 1024; /* cache division */
297 while (argc--) {
298 if (device_name) {
299 PAGES = bb_xgetlarg(argv[0], 0, 10, sz * goodpages) / goodpages;
300 argc = 0; /* ignore any surplus args.. */
301 } else {
302 device_name = argv[0];
303 sz = get_size(device_name);
304 argv++;
305 }
306 }
307
308 if (!device_name) {
309 bb_error_msg_and_die("error: Nowhere to set up swap on?");
310 }
311 if (!PAGES) {
312 PAGES = sz;
313 }
314
315 if (!version)
316 maxpages = V0_MAX_PAGES;
317 else if (get_linux_version_code() >= KERNEL_VERSION(2,2,1))
318 maxpages = V1_MAX_PAGES;
319 else {
320 maxpages = V1_OLD_MAX_PAGES;
321 if (maxpages > V1_MAX_PAGES)
322 maxpages = V1_MAX_PAGES;
323 }
324 if (PAGES > maxpages) {
325 PAGES = maxpages;
326 bb_error_msg("warning: truncating swap area to %ldkB",
327 PAGES * goodpages);
328 }
329
330 DEV = bb_xopen3(device_name, O_RDWR, 0);
331 if (fstat(DEV, &statbuf) < 0)
332 bb_perror_msg_and_die("%s", device_name);
333 if (!S_ISBLK(statbuf.st_mode))
334 check = 0;
335 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
336 bb_error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
337 27
338#ifdef __sparc__ 28 // Make a header.
339 if (!force && version == 0) {
340 /* Don't overwrite partition table unless forced */
341 unsigned char *buffer = (unsigned char *) signature_page;
342 unsigned short *q, sum;
343 29
344 if (read(DEV, buffer, 512) != 512) 30 memset(hdr, 0, 129 * sizeof(unsigned int));
345 bb_error_msg_and_die("fatal: first page unreadable"); 31 hdr[0] = 1;
346 if (buffer[508] == 0xDA && buffer[509] == 0xBE) { 32 hdr[1] = (len / pagesize) - 1;
347 q = (unsigned short *) (buffer + 510);
348 for (sum = 0; q >= (unsigned short *) buffer;)
349 sum ^= *q--;
350 if (!sum) {
351 bb_error_msg("Device '%s' contains a valid Sun disklabel.\n"
352"This probably means creating v0 swap would destroy your partition table\n"
353"No swap created. If you really want to create swap v0 on that device, use\n"
354"the -f option to force it.", device_name);
355 return EXIT_FAILURE;
356 }
357 }
358 }
359#endif
360 33
361 if (version == 0 || check) 34 // Write the header. Sync to disk because some kernel versions check
362 check_blocks(); 35 // signature on disk (not in cache) during swapon.
363 if (version == 0 && !bit_test_and_clear(signature_page, 0))
364 bb_error_msg_and_die("fatal: first page unreadable");
365 if (version == 1) {
366 p->swap_version = version;
367 p->last_page = PAGES - 1;
368 p->nr_badpages = badpages;
369 }
370 36
371 goodpages = PAGES - badpages - 1; 37 xlseek(fd, 1024, SEEK_SET);
372 if (goodpages <= 0) 38 xwrite(fd, hdr, 129 * sizeof(unsigned int));
373 bb_error_msg_and_die("Unable to set up swap-space: unreadable"); 39 xlseek(fd, pagesize-10, SEEK_SET);
374 printf("Setting up swapspace version %d, size = %ld bytes\n", 40 xwrite(fd, "SWAPSPACE2", 10);
375 version, (long) (goodpages * pagesize)); 41 fsync(fd);
376 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
377 42
378 sz = ((version == 0) ? 0 : 1024); /* offset */ 43 if (ENABLE_FEATURE_CLEAN_UP) close(fd);
379 if (lseek(DEV, sz, SEEK_SET) != sz)
380 bb_error_msg_and_die("unable to rewind swap-device");
381 goodpages = pagesize - sz; /* cache substraction */
382 if (write(DEV, (char *) signature_page + sz, goodpages)
383 != goodpages)
384 bb_error_msg_and_die("unable to write signature page");
385 44
386 /* 45 return 0;
387 * A subsequent swapon() will fail if the signature
388 * is not actually on disk. (This is a kernel bug.)
389 */
390 if (fsync(DEV))
391 bb_error_msg_and_die("fsync failed");
392 if (ENABLE_FEATURE_CLEAN_UP) {
393 close(DEV);
394 free(signature_page);
395 }
396 return EXIT_SUCCESS;
397} 46}