Test applets containing numbers in their name. Thanks to Larry Doolittle.
[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 static const int 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 static void die(const char *str)
177 {
178         error_msg("%s\n", str);
179         exit(EXIT_FAILURE);
180 }
181
182 static void page_ok(int page)
183 {
184         if (version == 0)
185                 bit_set(signature_page, page);
186 }
187
188 static 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 static 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         if ((fd = open(file, O_RDONLY)) < 0)
264                 perror_msg_and_die("%s", file);
265         if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
266                 int sectors_per_page = pagesize / 512;
267
268                 size /= sectors_per_page;
269         } else {
270                 size = find_size(fd) / pagesize;
271         }
272         close(fd);
273         return size;
274 }
275
276 int mkswap_main(int argc, char **argv)
277 {
278         char *tmp;
279         struct stat statbuf;
280         int sz;
281         int maxpages;
282         int goodpages;
283         int offset;
284         int force = 0;
285
286         init_signature_page();          /* get pagesize */
287
288         while (argc-- > 1) {
289                 argv++;
290                 if (argv[0][0] != '-') {
291                         if (device_name) {
292                                 int blocks_per_page = pagesize / 1024;
293
294                                 PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page;
295                                 if (*tmp)
296                                         usage(mkswap_usage);
297                         } else
298                                 device_name = argv[0];
299                 } else {
300                         switch (argv[0][1]) {
301                         case 'c':
302                                 check = 1;
303                                 break;
304                         case 'f':
305                                 force = 1;
306                                 break;
307                         case 'v':
308                                 version = atoi(argv[0] + 2);
309                                 break;
310                         default:
311                                 usage(mkswap_usage);
312                         }
313                 }
314         }
315         if (!device_name) {
316                 error_msg("error: Nowhere to set up swap on?\n");
317                 usage(mkswap_usage);
318         }
319         sz = get_size(device_name);
320         if (!PAGES) {
321                 PAGES = sz;
322         } else if (PAGES > sz && !force) {
323                 error_msg("error: size %ld is larger than device size %d\n",
324                                 PAGES * (pagesize / 1024), sz * (pagesize / 1024));
325                 return EXIT_FAILURE;
326         }
327
328         if (version == -1) {
329                 if (PAGES <= V0_MAX_PAGES)
330                         version = 0;
331                 else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117))
332                         version = 0;
333                 else if (pagesize < 2048)
334                         version = 0;
335                 else
336                         version = 1;
337         }
338         if (version != 0 && version != 1) {
339                 error_msg("error: unknown version %d\n", version);
340                 usage(mkswap_usage);
341         }
342         if (PAGES < 10) {
343                 error_msg("error: swap area needs to be at least %ldkB\n",
344                                 (long) (10 * pagesize / 1024));
345                 usage(mkswap_usage);
346         }
347 #if 0
348         maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES);
349 #else
350         if (!version)
351                 maxpages = V0_MAX_PAGES;
352         else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1))
353                 maxpages = V1_MAX_PAGES;
354         else {
355                 maxpages = V1_OLD_MAX_PAGES;
356                 if (maxpages > V1_MAX_PAGES)
357                         maxpages = V1_MAX_PAGES;
358         }
359 #endif
360         if (PAGES > maxpages) {
361                 PAGES = maxpages;
362                 error_msg("warning: truncating swap area to %ldkB\n",
363                                 PAGES * pagesize / 1024);
364         }
365
366         DEV = open(device_name, O_RDWR);
367         if (DEV < 0 || fstat(DEV, &statbuf) < 0)
368                 perror_msg_and_die("%s", device_name);
369         if (!S_ISBLK(statbuf.st_mode))
370                 check = 0;
371         else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
372                 die("Will not try to make swapdevice on '%s'");
373
374 #ifdef __sparc__
375         if (!force && version == 0) {
376                 /* Don't overwrite partition table unless forced */
377                 unsigned char *buffer = (unsigned char *) signature_page;
378                 unsigned short *q, sum;
379
380                 if (read(DEV, buffer, 512) != 512)
381                         die("fatal: first page unreadable");
382                 if (buffer[508] == 0xDA && buffer[509] == 0xBE) {
383                         q = (unsigned short *) (buffer + 510);
384                         for (sum = 0; q >= (unsigned short *) buffer;)
385                                 sum ^= *q--;
386                         if (!sum) {
387                                 error_msg("Device '%s' contains a valid Sun disklabel.\n"
388 "This probably means creating v0 swap would destroy your partition table\n"
389 "No swap created. If you really want to create swap v0 on that device, use\n"
390 "the -f option to force it.\n", device_name);
391                                 return EXIT_FAILURE;
392                         }
393                 }
394         }
395 #endif
396
397         if (version == 0 || check)
398                 check_blocks();
399         if (version == 0 && !bit_test_and_clear(signature_page, 0))
400                 die("fatal: first page unreadable");
401         if (version == 1) {
402                 p->version = version;
403                 p->last_page = PAGES - 1;
404                 p->nr_badpages = badpages;
405         }
406
407         goodpages = PAGES - badpages - 1;
408         if (goodpages <= 0)
409                 die("Unable to set up swap-space: unreadable");
410         printf("Setting up swapspace version %d, size = %ld bytes\n",
411                    version, (long) (goodpages * pagesize));
412         write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2");
413
414         offset = ((version == 0) ? 0 : 1024);
415         if (lseek(DEV, offset, SEEK_SET) != offset)
416                 die("unable to rewind swap-device");
417         if (write(DEV, (char *) signature_page + offset, pagesize - offset)
418                 != pagesize - offset)
419                 die("unable to write signature page");
420
421         /*
422          * A subsequent swapon() will fail if the signature
423          * is not actually on disk. (This is a kernel bug.)
424          */
425         if (fsync(DEV))
426                 die("fsync failed");
427         return EXIT_SUCCESS;
428 }