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