source: trunk/mindi-busybox/util-linux/mkswap.c @ 929

Last change on this file since 929 was 821, checked in by bruno, 13 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.