diff options
author | Eric Andersen <andersen@codepoet.org> | 1999-10-05 16:24:54 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 1999-10-05 16:24:54 +0000 |
commit | cc8ed39b240180b58810784f844e253263594ac3 (patch) | |
tree | 15feebbb4be9a9168209609f48f0b100f9364420 /mkswap.c | |
download | busybox-w32-0_29alpha2.tar.gz busybox-w32-0_29alpha2.tar.bz2 busybox-w32-0_29alpha2.zip |
Initial revision0_29alpha2
Diffstat (limited to 'mkswap.c')
-rw-r--r-- | mkswap.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/mkswap.c b/mkswap.c new file mode 100644 index 000000000..f797d1395 --- /dev/null +++ b/mkswap.c | |||
@@ -0,0 +1,253 @@ | |||
1 | #include "internal.h" | ||
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] device [size-in-blocks] | ||
13 | * | ||
14 | * -c for readablility checking (use it unless you are SURE!) | ||
15 | * | ||
16 | * The device may be a block device or a image of one, but this isn't | ||
17 | * enforced (but it's not much fun on a character device :-). | ||
18 | * | ||
19 | * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the | ||
20 | * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. | ||
21 | */ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <unistd.h> | ||
25 | #include <string.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <sys/stat.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | |||
31 | #include <asm/page.h> | ||
32 | #include <linux/fs.h> | ||
33 | |||
34 | #ifndef __linux__ | ||
35 | # define volatile | ||
36 | #endif | ||
37 | |||
38 | #define TEST_BUFFER_PAGES 8 | ||
39 | |||
40 | const char mkswap_usage[] = "mkswap [-c] partition [block-count]\n" | ||
41 | "\n" | ||
42 | "\tPrepare a disk partition to be used as a swap partition.\n" | ||
43 | "\tThe default block count is the size of the entire partition.\n" | ||
44 | "\n" | ||
45 | "\t-c:\tCheck for read-ability.\n" | ||
46 | "\tblock-count\tUse only this many blocks.\n"; | ||
47 | |||
48 | static const char * program_name = "mkswap"; | ||
49 | static const char * device_name = NULL; | ||
50 | static int DEV = -1; | ||
51 | static long PAGES = 0; | ||
52 | static int do_check = 0; | ||
53 | static int badpages = 0; | ||
54 | |||
55 | |||
56 | static long bit_test_and_set (unsigned int *addr, unsigned int nr) | ||
57 | { | ||
58 | unsigned int r, m; | ||
59 | |||
60 | addr += nr / (8 * sizeof(int)); | ||
61 | r = *addr; | ||
62 | m = 1 << (nr & (8 * sizeof(int) - 1)); | ||
63 | *addr = r | m; | ||
64 | return (r & m) != 0; | ||
65 | } | ||
66 | |||
67 | static int bit_test_and_clear (unsigned int *addr, unsigned int nr) | ||
68 | { | ||
69 | unsigned int r, m; | ||
70 | |||
71 | addr += nr / (8 * sizeof(int)); | ||
72 | r = *addr; | ||
73 | m = 1 << (nr & (8 * sizeof(int) - 1)); | ||
74 | *addr = r & ~m; | ||
75 | return (r & m) != 0; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Volatile to let gcc know that this doesn't return. When trying | ||
80 | * to compile this under minix, volatile gives a warning, as | ||
81 | * exit() isn't defined as volatile under minix. | ||
82 | */ | ||
83 | volatile void fatal_error(const char * fmt_string) | ||
84 | { | ||
85 | fprintf(stderr,fmt_string,program_name,device_name); | ||
86 | exit(1); | ||
87 | } | ||
88 | |||
89 | #define die(str) fatal_error("%s: " str "\n") | ||
90 | |||
91 | static void check_blocks(int * signature_page) | ||
92 | { | ||
93 | unsigned int current_page; | ||
94 | int do_seek = 1; | ||
95 | char buffer[PAGE_SIZE]; | ||
96 | |||
97 | current_page = 0; | ||
98 | while (current_page < PAGES) { | ||
99 | if (!do_check) { | ||
100 | bit_test_and_set(signature_page,current_page++); | ||
101 | continue; | ||
102 | } else { | ||
103 | printf("\r%d", current_page); | ||
104 | } | ||
105 | if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != | ||
106 | current_page*PAGE_SIZE) | ||
107 | die("seek failed in check_blocks"); | ||
108 | if ( (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) ) { | ||
109 | bit_test_and_clear(signature_page,current_page++); | ||
110 | badpages++; | ||
111 | continue; | ||
112 | } | ||
113 | bit_test_and_set(signature_page,current_page++); | ||
114 | } | ||
115 | if (do_check) | ||
116 | printf("\n"); | ||
117 | if (badpages) | ||
118 | printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); | ||
119 | } | ||
120 | |||
121 | static long valid_offset (int fd, int offset) | ||
122 | { | ||
123 | char ch; | ||
124 | |||
125 | if (lseek (fd, offset, 0) < 0) | ||
126 | return 0; | ||
127 | if (read (fd, &ch, 1) < 1) | ||
128 | return 0; | ||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | static int count_blocks (int fd) | ||
133 | { | ||
134 | int high, low; | ||
135 | |||
136 | low = 0; | ||
137 | for (high = 1; valid_offset (fd, high); high *= 2) | ||
138 | low = high; | ||
139 | while (low < high - 1) | ||
140 | { | ||
141 | const int mid = (low + high) / 2; | ||
142 | |||
143 | if (valid_offset (fd, mid)) | ||
144 | low = mid; | ||
145 | else | ||
146 | high = mid; | ||
147 | } | ||
148 | valid_offset (fd, 0); | ||
149 | return (low + 1); | ||
150 | } | ||
151 | |||
152 | static int get_size(const char *file) | ||
153 | { | ||
154 | int fd; | ||
155 | int size; | ||
156 | |||
157 | fd = open(file, O_RDWR); | ||
158 | if (fd < 0) { | ||
159 | perror(file); | ||
160 | exit(1); | ||
161 | } | ||
162 | if (ioctl(fd, BLKGETSIZE, &size) >= 0) { | ||
163 | close(fd); | ||
164 | return (size * 512); | ||
165 | } | ||
166 | |||
167 | size = count_blocks(fd); | ||
168 | close(fd); | ||
169 | return size; | ||
170 | } | ||
171 | |||
172 | int | ||
173 | mkswap(char *device_name, int pages, int check) | ||
174 | { | ||
175 | struct stat statbuf; | ||
176 | int goodpages; | ||
177 | int signature_page[PAGE_SIZE/sizeof(int)]; | ||
178 | |||
179 | PAGES = pages; | ||
180 | do_check = check; | ||
181 | |||
182 | memset(signature_page,0,PAGE_SIZE); | ||
183 | |||
184 | if (device_name && !PAGES) { | ||
185 | PAGES = get_size(device_name) / PAGE_SIZE; | ||
186 | } | ||
187 | if (!device_name || PAGES<10) { | ||
188 | fprintf(stderr, | ||
189 | "%s: error: swap area needs to be at least %ldkB\n", | ||
190 | program_name, 10 * PAGE_SIZE / 1024); | ||
191 | /* usage(mkswap_usage); */ | ||
192 | exit(1); | ||
193 | } | ||
194 | if (PAGES > 8 * (PAGE_SIZE - 10)) { | ||
195 | PAGES = 8 * (PAGE_SIZE - 10); | ||
196 | fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", | ||
197 | program_name, PAGES * PAGE_SIZE / 1024); | ||
198 | } | ||
199 | DEV = open(device_name,O_RDWR); | ||
200 | if (DEV < 0 || fstat(DEV, &statbuf) < 0) { | ||
201 | perror(device_name); | ||
202 | exit(1); | ||
203 | } | ||
204 | if (!S_ISBLK(statbuf.st_mode)) | ||
205 | do_check=0; | ||
206 | else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) | ||
207 | die("Will not try to make swapdevice on '%s'"); | ||
208 | check_blocks(signature_page); | ||
209 | if (!bit_test_and_clear(signature_page,0)) | ||
210 | die("fatal: first page unreadable"); | ||
211 | goodpages = PAGES - badpages - 1; | ||
212 | if (goodpages <= 0) | ||
213 | die("Unable to set up swap-space: unreadable"); | ||
214 | printf("Setting up swapspace, size = %ld bytes\n",goodpages*PAGE_SIZE); | ||
215 | strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); | ||
216 | if (lseek(DEV, 0, SEEK_SET)) | ||
217 | die("unable to rewind swap-device"); | ||
218 | if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) | ||
219 | die("unable to write signature page"); | ||
220 | |||
221 | close(DEV); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | int mkswap_main(struct FileInfo * unnecessary, int argc, char ** argv) | ||
226 | { | ||
227 | char * tmp; | ||
228 | long int pages=0; | ||
229 | int check=0; | ||
230 | |||
231 | if (argc && *argv) | ||
232 | program_name = *argv; | ||
233 | while (argc > 1) { | ||
234 | argv++; | ||
235 | argc--; | ||
236 | if (argv[0][0] != '-') | ||
237 | if (device_name) { | ||
238 | pages = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10); | ||
239 | if (*tmp) { | ||
240 | usage(mkswap_usage); | ||
241 | exit(1); | ||
242 | } | ||
243 | } else | ||
244 | device_name = argv[0]; | ||
245 | else while (*++argv[0]) | ||
246 | switch (argv[0][0]) { | ||
247 | case 'c': check=1; break; | ||
248 | default: usage(mkswap_usage); | ||
249 | exit(1); | ||
250 | } | ||
251 | } | ||
252 | return mkswap(device_name, pages, check); | ||
253 | } | ||