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