Patch from Matt Kraai to enable proxy support.
[oweals/busybox.git] / mkswap.c
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 <andersee@debian.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 <stdio.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <fcntl.h>
43 #include <stdlib.h>
44 #include <sys/ioctl.h>                  /* for _IO */
45 #include <sys/utsname.h>
46 #include <asm/page.h>                   /* for PAGE_SIZE and PAGE_SHIFT */
47                                 /* we also get PAGE_SIZE via getpagesize() */
48
49 #ifndef _IO
50 /* pre-1.3.45 */
51 #define BLKGETSIZE 0x1260
52 #else
53 /* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
54 #define BLKGETSIZE _IO(0x12,96)
55 #endif
56
57 static char *device_name = NULL;
58 static int DEV = -1;
59 static long PAGES = 0;
60 static int check = 0;
61 static int badpages = 0;
62 static int version = -1;
63
64 #define MAKE_VERSION(p,q,r)     (65536*(p) + 256*(q) + (r))
65
66 /*
67  * The definition of the union swap_header uses the constant PAGE_SIZE.
68  * Unfortunately, on some architectures this depends on the hardware model,
69  * and can only be found at run time -- we use getpagesize().
70  */
71
72 static int pagesize;
73 static int *signature_page;
74
75 struct swap_header_v1 {
76         char bootbits[1024];            /* Space for disklabel etc. */
77         unsigned int version;
78         unsigned int last_page;
79         unsigned int nr_badpages;
80         unsigned int padding[125];
81         unsigned int badpages[1];
82 } *p;
83
84 static void init_signature_page()
85 {
86         pagesize = getpagesize();
87
88 #ifdef PAGE_SIZE
89         if (pagesize != PAGE_SIZE)
90                 error_msg("Assuming pages of size %d\n", pagesize);
91 #endif
92         signature_page = (int *) xmalloc(pagesize);
93         memset(signature_page, 0, pagesize);
94         p = (struct swap_header_v1 *) signature_page;
95 }
96
97 static void write_signature(char *sig)
98 {
99         char *sp = (char *) signature_page;
100
101         strncpy(sp + pagesize - 10, sig, 10);
102 }
103
104 #define V0_MAX_PAGES    (8 * (pagesize - 10))
105 /* Before 2.2.0pre9 */
106 #define V1_OLD_MAX_PAGES        ((0x7fffffff / pagesize) - 1)
107 /* Since 2.2.0pre9:
108    error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL))
109    with variations on
110         #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
111         #define SWP_OFFSET(entry) ((entry) >> 8)
112    on the various architectures. Below the result - yuk.
113
114    Machine      pagesize        SWP_ENTRY       SWP_OFFSET      bound+1 oldbound+2
115    i386         2^12            o<<8            e>>8            1<<24   1<<19
116    mips         2^12            o<<15           e>>15           1<<17   1<<19
117    alpha        2^13            o<<40           e>>40           1<<24   1<<18
118    m68k         2^12            o<<12           e>>12           1<<20   1<<19
119    sparc        2^{12,13}       (o&0x3ffff)<<9  (e>>9)&0x3ffff  1<<18   1<<{19,18}
120    sparc64      2^13            o<<13           e>>13           1<<51   1<<18
121    ppc          2^12            o<<8            e>>8            1<<24   1<<19
122    armo         2^{13,14,15}    o<<8            e>>8            1<<24   1<<{18,17,16}
123    armv         2^12            o<<9            e>>9            1<<23   1<<19
124
125    assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere.
126
127    The bad part is that we need to know this since the kernel will
128    refuse a swap space if it is too large.
129 */
130 /* patch from jj - why does this differ from the above? */
131 #if defined(__alpha__)
132 #define V1_MAX_PAGES           ((1 << 24) - 1)
133 #elif defined(__mips__)
134 #define V1_MAX_PAGES           ((1 << 17) - 1)
135 #elif defined(__sparc_v9__)
136 #define V1_MAX_PAGES           ((3 << 29) - 1)
137 #elif defined(__sparc__)
138 #define V1_MAX_PAGES           (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1))
139 #else
140 #define V1_MAX_PAGES           V1_OLD_MAX_PAGES
141 #endif
142 /* man page now says:
143 The maximum useful size of a swap area now depends on the architecture.
144 It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips,
145 128GB on alpha and 3TB on sparc64.
146 */
147
148 #define MAX_BADPAGES    ((pagesize-1024-128*sizeof(int)-10)/sizeof(int))
149
150 static void bit_set(unsigned int *addr, unsigned int nr)
151 {
152         unsigned int r, m;
153
154         addr += nr / (8 * sizeof(int));
155
156         r = *addr;
157         m = 1 << (nr & (8 * sizeof(int) - 1));
158
159         *addr = r | m;
160 }
161
162 static int bit_test_and_clear(unsigned int *addr, unsigned int nr)
163 {
164         unsigned int r, m;
165
166         addr += nr / (8 * sizeof(int));
167
168         r = *addr;
169         m = 1 << (nr & (8 * sizeof(int) - 1));
170
171         *addr = r & ~m;
172         return (r & m) != 0;
173 }
174
175
176 void die(const char *str)
177 {
178         error_msg("%s\n", str);
179         exit(EXIT_FAILURE);
180 }
181
182 void page_ok(int page)
183 {
184         if (version == 0)
185                 bit_set(signature_page, page);
186 }
187
188 void page_bad(int page)
189 {
190         if (version == 0)
191                 bit_test_and_clear(signature_page, page);
192         else {
193                 if (badpages == MAX_BADPAGES)
194                         die("too many bad pages");
195                 p->badpages[badpages] = page;
196         }
197         badpages++;
198 }
199
200 void check_blocks(void)
201 {
202         unsigned int current_page;
203         int do_seek = 1;
204         char *buffer;
205
206         buffer = xmalloc(pagesize);
207         current_page = 0;
208         while (current_page < PAGES) {
209                 if (!check) {
210                         page_ok(current_page++);
211                         continue;
212                 }
213                 if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) !=
214                         current_page * pagesize)
215                         die("seek failed in check_blocks");
216                 if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) {
217                         page_bad(current_page++);
218                         continue;
219                 }
220                 page_ok(current_page++);
221         }
222         if (badpages == 1)
223                 printf("one bad page\n");
224         else if (badpages > 1)
225                 printf("%d bad pages\n", badpages);
226 }
227
228 static long valid_offset(int fd, int offset)
229 {
230         char ch;
231
232         if (lseek(fd, offset, 0) < 0)
233                 return 0;
234         if (read(fd, &ch, 1) < 1)
235                 return 0;
236         return 1;
237 }
238
239 static int find_size(int fd)
240 {
241         unsigned int high, low;
242
243         low = 0;
244         for (high = 1; high > 0 && valid_offset(fd, high); high *= 2)
245                 low = high;
246         while (low < high - 1) {
247                 const int mid = (low + high) / 2;
248
249                 if (valid_offset(fd, mid))
250                         low = mid;
251                 else
252                         high = mid;
253         }
254         return (low + 1);
255 }
256
257 /* return size in pages, to avoid integer overflow */
258 static long get_size(const char *file)
259 {
260         int fd;
261         long size;
262
263         fd = open(file, O_RDONLY);
264         if (fd < 0) {
265                 perror(file);
266                 exit(1);
267         }
268         if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
269                 int sectors_per_page = pagesize / 512;
270
271                 size /= sectors_per_page;
272         } else {
273                 size = find_size(fd) / pagesize;
274         }
275         close(fd);
276         return size;
277 }
278
279 int mkswap_main(int argc, char **argv)
280 {
281         char *tmp;
282         struct stat statbuf;
283         int sz;
284         int maxpages;
285         int goodpages;
286         int offset;
287         int force = 0;
288
289         init_signature_page();          /* get pagesize */
290
291         while (argc-- > 1) {
292                 argv++;
293                 if (argv[0][0] != '-') {
294                         if (device_name) {
295                                 int blocks_per_page = pagesize / 1024;
296
297                                 PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
298                                 if (*tmp)
299                                         usage(mkswap_usage);
300                         } else
301                                 device_name = argv[0];
302                 } else {
303                         switch (argv[0][1]) {
304                         case 'c':
305                                 check = 1;
306                                 break;
307                         case 'f':
308                                 force = 1;
309                                 break;
310                         case 'v':
311                                 version = atoi(argv[0] + 2);
312                                 break;
313                         default:
314                                 usage(mkswap_usage);
315                         }
316                 }
317         }
318         if (!device_name) {
319                 error_msg("error: Nowhere to set up swap on?\n");
320                 usage(mkswap_usage);
321         }
322         sz = get_size(device_name);
323         if (!PAGES) {
324                 PAGES = sz;
325         } else if (PAGES > sz && !force) {
326                 error_msg("error: size %ld is larger than device size %d\n",
327                                 PAGES * (pagesize / 1024), sz * (pagesize / 1024));
328                 return EXIT_FAILURE;
329         }
330
331         if (version == -1) {
332                 if (PAGES <= V0_MAX_PAGES)
333                         version = 0;
334                 else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
335                         version = 0;
336                 else if (pagesize < 2048)
337                         version = 0;
338                 else
339                         version = 1;
340         }
341         if (version != 0 && version != 1) {
342                 error_msg("error: unknown version %d\n", version);
343                 usage(mkswap_usage);
344         }
345         if (PAGES < 10) {
346                 error_msg("error: swap area needs to be at least %ldkB\n",
347                                 (long) (10 * pagesize / 1024));
348                 usage(mkswap_usage);
349         }
350 #if 0
351         maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
352 #else
353         if (!version)
354                 maxpages = V0_MAX_PAGES;
355         else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
356                 maxpages = V1_MAX_PAGES;
357         else {
358                 maxpages = V1_OLD_MAX_PAGES;
359                 if (maxpages > V1_MAX_PAGES)
360                         maxpages = V1_MAX_PAGES;
361         }
362 #endif
363         if (PAGES > maxpages) {
364                 PAGES = maxpages;
365                 error_msg("warning: truncating swap area to %ldkB\n",
366                                 PAGES * pagesize / 1024);
367         }
368
369         DEV = open(device_name, O_RDWR);
370         if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
371                 perror(device_name);
372                 return EXIT_FAILURE;
373         }
374         if (!S_ISBLK(statbuf.st_mode))
375                 check = 0;
376         else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
377                 die("Will not try to make swapdevice on '%s'");
378
379 #ifdef __sparc__
380         if (!force && version == 0) {
381                 /* Don't overwrite partition table unless forced */
382                 unsigned char *buffer = (unsigned char *) signature_page;
383                 unsigned short *q, sum;
384
385                 if (read(DEV, buffer, 512) != 512)
386                         die("fatal: first page unreadable");
387                 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
388                         q = (unsigned short *) (buffer + 510);
389                         for (sum = 0; q >= (unsigned short *) buffer;)
390                                 sum ^= *q--;
391                         if (!sum) {
392                                 error_msg("Device '%s' contains a valid Sun disklabel.\n"
393 "This probably means creating v0 swap would destroy your partition table\n"
394 "No swap created. If you really want to create swap v0 on that device, use\n"
395 "the -f option to force it.\n", device_name);
396                                 return EXIT_FAILURE;
397                         }
398                 }
399         }
400 #endif
401
402         if (version == 0 || check)
403                 check_blocks();
404         if (version == 0 && !bit_test_and_clear(signature_page, 0))
405                 die("fatal: first page unreadable");
406         if (version == 1) {
407                 p->version = version;
408                 p->last_page = PAGES - 1;
409                 p->nr_badpages = badpages;
410         }
411
412         goodpages = PAGES - badpages - 1;
413         if (goodpages <= 0)
414                 die("Unable to set up swap-space: unreadable");
415         printf("Setting up swapspace version %d, size = %ld bytes\n",
416                    version, (long) (goodpages * pagesize));
417         write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
418
419         offset = ((version == 0) ? 0 : 1024);
420         if (lseek(DEV, offset, SEEK_SET) != offset)
421                 die("unable to rewind swap-device");
422         if (write(DEV, (char *) signature_page + offset, pagesize - offset)
423                 != pagesize - offset)
424                 die("unable to write signature page");
425
426         /*
427          * A subsequent swapon() will fail if the signature
428          * is not actually on disk. (This is a kernel bug.)
429          */
430         if (fsync(DEV))
431                 die("fsync failed");
432         return EXIT_SUCCESS;
433 }