-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmkswap_u.c
181 lines (159 loc) · 4.46 KB
/
mkswap_u.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/* mkswap - toolbox
Copyright 2015-2016 Rivoreo
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
// This util is used to make a Linux swap space
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef _WIN32
extern int fsync(int);
#endif
/* XXX This needs to be obtained from kernel headers. See b/9336527 */
struct linux_swap_header {
char bootbits[1024]; /* Space for disklabel etc. */
uint32_t version;
uint32_t last_page;
uint32_t nr_badpages;
unsigned char sws_uuid[16];
unsigned char sws_volume[16];
uint32_t padding[117];
uint32_t badpages[1];
};
#define MAGIC_SWAP_HEADER "SWAPSPACE2"
#define MAGIC_SWAP_HEADER_LEN 10
#define MIN_PAGES 10
static unsigned char atoxb(const char *s) {
unsigned char r = *s - (isalpha(*s) ? (islower(*s) ? 87 : 55) : '0');
if(*++s) r = (*s - (isalpha(*s) ? (islower(*s) ? 87 : 55) : '0')) + r * 16;
return r;
}
static int convert_uuid(unsigned char *uuid, const char *s) {
int i;
for(i=0; i<16; i++) {
if(*s == '-') s++;
if(!isxdigit(*s) || !isxdigit(s[1])) {
//memset(uuid + i, 0, 16 - i);
//return;
return -1;
}
uuid[i] = atoxb(s);
s += 2;
}
return 0;
}
int mkswap_main(int argc, char **argv) {
int e = 0;
int fd;
ssize_t len;
off_t swap_size;
int pagesize = 0;
struct linux_swap_header sw_hdr = { .version = 1 };
static struct option long_options[] = {
{ "pagesize", 1, NULL, 'p' },
{ "label", 1, NULL, 'L' },
{ "uuid", 1, NULL, 'U' },
{ NULL, 0, NULL, 0 }
};
while(1) {
int c = getopt_long(argc, argv, "p:L:U:", long_options, NULL);
if(c == -1) break;
switch(c) {
case 'p':
pagesize = atoi(optarg);
if(!pagesize) {
fprintf(stderr, "%s: Invalid page size\n", argv[0]);
return -EINVAL;
}
break;
case 'L':
strncpy((char *)sw_hdr.sws_volume, optarg, sizeof sw_hdr.sws_volume);
break;
case 'U':
if(convert_uuid(sw_hdr.sws_uuid, optarg) < 0) {
fprintf(stderr, "%s: Invalid UUID\n", argv[0]);
return -EINVAL;
}
break;
case '?':
return -EINVAL;
}
}
if(argc != optind + 1) {
#ifndef __linux__
fprintf(stderr, "This tool will set up a Linux swap space that is not suit your system\n");
#endif
fprintf(stderr, "Usage: %s "
#ifdef __linux__
"[-p <page size>]"
#else
"-p <page size>"
#endif
" [-L <label>] [-U <UUID>] <filename>\n", argv[0]);
return -EINVAL;
}
if(!pagesize) {
#ifdef __linux__
pagesize = getpagesize();
#else
fprintf(stderr, "%s: Page size not specified\n", argv[0]);
return -EINVAL;
#endif
}
fd = open(argv[optind], O_WRONLY);
if(fd == -1) {
e = errno;
fprintf(stderr, "%s: Cannot open %s, %s\n", argv[0], argv[optind], strerror(e));
return -e;
}
/* Determine the length of the swap file */
swap_size = lseek(fd, 0, SEEK_END);
if(swap_size < MIN_PAGES * pagesize) {
fprintf(stderr, "%s: Swap file needs to be at least %d KiB\n",
argv[0], (MIN_PAGES * pagesize) >> 10);
e = -ENOSPC;
goto err;
}
if(lseek(fd, 0, SEEK_SET)) {
e = errno;
fprintf(stderr, "Can't seek to the beginning of the file, %s\n", strerror(e));
goto err;
}
sw_hdr.last_page = (swap_size / pagesize) - 1;
len = write(fd, &sw_hdr, sizeof sw_hdr);
if(len != sizeof sw_hdr) {
e = errno;
fprintf(stderr, "Failed to write swap header into %s, %s\n", argv[optind], strerror(e));
goto err;
}
/* Write the magic header */
if(lseek(fd, pagesize - MAGIC_SWAP_HEADER_LEN, SEEK_SET) < 0) {
e = errno;
fprintf(stderr, "Failed to seek into %s, %s\n", argv[optind], strerror(e));
goto err;
}
len = write(fd, MAGIC_SWAP_HEADER, MAGIC_SWAP_HEADER_LEN);
if(len != MAGIC_SWAP_HEADER_LEN) {
e = errno;
fprintf(stderr, "Failed to write magic swap header into %s, %s\n", argv[optind], strerror(e));
goto err;
}
if(fsync(fd) < 0) {
e = errno;
fprintf(stderr, "Failed to sync %s, %s\n", argv[optind], strerror(e));
goto err;
}
return 0;
err:
close(fd);
return -e;
}