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