]> git.ipfire.org Git - thirdparty/util-linux.git/blob - historic/mkswap.c
Imported from util-linux-2.5 tarball.
[thirdparty/util-linux.git] / historic / 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/stat.h>
28
29 #include <linux/mm.h>
30
31 #ifndef __GNUC__
32 #error "needs gcc for the bitop-__asm__'s"
33 #endif
34
35 #ifndef __linux__
36 #define volatile
37 #endif
38
39 #define TEST_BUFFER_PAGES 8
40
41 static char * program_name = "mkswap";
42 static char * device_name = NULL;
43 static int DEV = -1;
44 static long PAGES = 0;
45 static int check = 0;
46 static int badpages = 0;
47
48 static char signature_page[PAGE_SIZE];
49
50 #define bitop(name,op) \
51 static inline int name(char * addr,unsigned int nr) \
52 { \
53 int __res; \
54 __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
55 :"=g" (__res) \
56 :"r" (nr),"m" (*(addr)),"0" (0)); \
57 return __res; \
58 }
59
60 bitop(bit,"")
61 bitop(setbit,"s")
62 bitop(clrbit,"r")
63
64 /*
65 * Volatile to let gcc know that this doesn't return. When trying
66 * to compile this under minix, volatile gives a warning, as
67 * exit() isn't defined as volatile under minix.
68 */
69 volatile void fatal_error(const char * fmt_string)
70 {
71 fprintf(stderr,fmt_string,program_name,device_name);
72 exit(1);
73 }
74
75 #define usage() fatal_error("Usage: %s [-c] /dev/name [blocks]\n")
76 #define die(str) fatal_error("%s: " str "\n")
77
78 void check_blocks(void)
79 {
80 unsigned int current_page;
81 int do_seek = 1;
82 static char buffer[PAGE_SIZE];
83
84 current_page = 0;
85 while (current_page < PAGES) {
86 if (!check) {
87 setbit(signature_page,current_page++);
88 continue;
89 }
90 if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) !=
91 current_page*PAGE_SIZE)
92 die("seek failed in check_blocks");
93 if (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) {
94 clrbit(signature_page,current_page++);
95 badpages++;
96 continue;
97 }
98 setbit(signature_page,current_page++);
99 }
100 if (badpages)
101 printf("%d bad page%s\n",badpages,(badpages>1)?"s":"");
102 }
103
104 static long valid_offset (int fd, int offset)
105 {
106 char ch;
107
108 if (lseek (fd, offset, 0) < 0)
109 return 0;
110 if (read (fd, &ch, 1) < 1)
111 return 0;
112 return 1;
113 }
114
115 static int count_blocks (int fd)
116 {
117 int high, low;
118
119 low = 0;
120 for (high = 1; valid_offset (fd, high); high *= 2)
121 low = high;
122 while (low < high - 1)
123 {
124 const int mid = (low + high) / 2;
125
126 if (valid_offset (fd, mid))
127 low = mid;
128 else
129 high = mid;
130 }
131 valid_offset (fd, 0);
132 return (low + 1);
133 }
134
135 static int get_size(const char *file)
136 {
137 int fd;
138 int size;
139
140 fd = open(file, O_RDWR);
141 if (fd < 0) {
142 perror(file);
143 exit(1);
144 }
145 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
146 close(fd);
147 return (size * 512);
148 }
149
150 size = count_blocks(fd);
151 close(fd);
152 return size;
153 }
154
155 int main(int argc, char ** argv)
156 {
157 char * tmp;
158 struct stat statbuf;
159 int goodpages;
160
161 memset(signature_page,0,PAGE_SIZE);
162 if (argc && *argv)
163 program_name = *argv;
164 while (argc-- > 1) {
165 argv++;
166 if (argv[0][0] != '-')
167 if (device_name) {
168 PAGES = strtol(argv[0],&tmp,0)>>2;
169 if (*tmp)
170 usage();
171 } else
172 device_name = argv[0];
173 else while (*++argv[0])
174 switch (argv[0][0]) {
175 case 'c': check=1; break;
176 default: usage();
177 }
178 }
179 if (device_name && !PAGES) {
180 PAGES = get_size(device_name) / PAGE_SIZE;
181 }
182 if (!device_name || PAGES<10)
183 usage();
184 if (PAGES > 32688) /* 130752 blocks */
185 PAGES=32688;
186 #if 0
187 if (PAGES > 32768)
188 PAGES=32768;
189 #endif
190 DEV = open(device_name,O_RDWR);
191 if (DEV < 0 || fstat(DEV, &statbuf) < 0) {
192 perror(device_name);
193 exit(1);
194 }
195 if (!S_ISBLK(statbuf.st_mode))
196 check=0;
197 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
198 die("Will not try to make swapdevice on '%s'");
199 check_blocks();
200 if (!clrbit(signature_page,0))
201 die("fatal: first page unreadable");
202 goodpages = PAGES - badpages - 1;
203 if (!goodpages)
204 die("Unable to set up swap-space: unreadable");
205 printf("Setting up swapspace, size = %d bytes\n",goodpages*PAGE_SIZE);
206 strncpy(signature_page+PAGE_SIZE-10,"SWAP-SPACE",10);
207 if (lseek(DEV, 0, SEEK_SET))
208 die("unable to rewind swap-device");
209 if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE))
210 die("unable to write signature page");
211 return 0;
212 }