source: MondoRescue/branches/stable/mindi-busybox/util-linux/mkswap.c@ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 10.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
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 *
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 *
32 * from util-linux -- adapted for busybox by
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 */
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
82static inline void init_signature_page(void)
83{
84 pagesize = getpagesize();
85
86#ifdef PAGE_SIZE
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{
97 char *sp = (char *) signature_page;
98
99 strncpy(sp + pagesize - 10, sig, 10);
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
125 The bad part is that we need to know this since the kernel will
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
146#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
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
164 addr += nr / (8 * sizeof(int));
165
166 r = *addr;
167 m = 1 << (nr & (8 * sizeof(int) - 1));
168
169 *addr = r & ~m;
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 0
316 maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
317#else
318 if (!version)
319 maxpages = V0_MAX_PAGES;
320 else if (get_linux_version_code() >= KERNEL_VERSION(2,2,1))
321 maxpages = V1_MAX_PAGES;
322 else {
323 maxpages = V1_OLD_MAX_PAGES;
324 if (maxpages > V1_MAX_PAGES)
325 maxpages = V1_MAX_PAGES;
326 }
327#endif
328 if (PAGES > maxpages) {
329 PAGES = maxpages;
330 bb_error_msg("warning: truncating swap area to %ldkB",
331 PAGES * goodpages);
332 }
333
334 DEV = bb_xopen3(device_name, O_RDWR, 0);
335 if (fstat(DEV, &statbuf) < 0)
336 bb_perror_msg_and_die("%s", device_name);
337 if (!S_ISBLK(statbuf.st_mode))
338 check = 0;
339 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
340 bb_error_msg_and_die("Will not try to make swapdevice on '%s'", device_name);
341
342#ifdef __sparc__
343 if (!force && version == 0) {
344 /* Don't overwrite partition table unless forced */
345 unsigned char *buffer = (unsigned char *) signature_page;
346 unsigned short *q, sum;
347
348 if (read(DEV, buffer, 512) != 512)
349 bb_error_msg_and_die("fatal: first page unreadable");
350 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
351 q = (unsigned short *) (buffer + 510);
352 for (sum = 0; q >= (unsigned short *) buffer;)
353 sum ^= *q--;
354 if (!sum) {
355 bb_error_msg("Device '%s' contains a valid Sun disklabel.\n"
356"This probably means creating v0 swap would destroy your partition table\n"
357"No swap created. If you really want to create swap v0 on that device, use\n"
358"the -f option to force it.", device_name);
359 return EXIT_FAILURE;
360 }
361 }
362 }
363#endif
364
365 if (version == 0 || check)
366 check_blocks();
367 if (version == 0 && !bit_test_and_clear(signature_page, 0))
368 bb_error_msg_and_die("fatal: first page unreadable");
369 if (version == 1) {
370 p->swap_version = version;
371 p->last_page = PAGES - 1;
372 p->nr_badpages = badpages;
373 }
374
375 goodpages = PAGES - badpages - 1;
376 if (goodpages <= 0)
377 bb_error_msg_and_die("Unable to set up swap-space: unreadable");
378 printf("Setting up swapspace version %d, size = %ld bytes\n",
379 version, (long) (goodpages * pagesize));
380 write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
381
382 sz = ((version == 0) ? 0 : 1024); /* offset */
383 if (lseek(DEV, sz, SEEK_SET) != sz)
384 bb_error_msg_and_die("unable to rewind swap-device");
385 goodpages = pagesize - sz; /* cache substraction */
386 if (write(DEV, (char *) signature_page + sz, goodpages)
387 != goodpages)
388 bb_error_msg_and_die("unable to write signature page");
389
390 /*
391 * A subsequent swapon() will fail if the signature
392 * is not actually on disk. (This is a kernel bug.)
393 */
394 if (fsync(DEV))
395 bb_error_msg_and_die("fsync failed");
396 if (ENABLE_FEATURE_CLEAN_UP) {
397 close(DEV);
398 free(signature_page);
399 }
400 return EXIT_SUCCESS;
401}
Note: See TracBrowser for help on using the repository browser.