summaryrefslogtreecommitdiff
path: root/mkswap.c
diff options
context:
space:
mode:
Diffstat (limited to 'mkswap.c')
-rw-r--r--mkswap.c253
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
40const 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
48static const char * program_name = "mkswap";
49static const char * device_name = NULL;
50static int DEV = -1;
51static long PAGES = 0;
52static int do_check = 0;
53static int badpages = 0;
54
55
56static 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
67static 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 */
83volatile 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
91static 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
121static 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
132static 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
152static 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
172int
173mkswap(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
225int 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}