Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/ramdisk_load.c
Parent Directory | Revision Log
Revision 1297 -
(hide annotations)
(download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 6339 byte(s)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 6339 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 | niro | 532 | #include <errno.h> |
2 | #include <fcntl.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | #include <inttypes.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <linux/fs.h> | ||
10 | #include <linux/cdrom.h> | ||
11 | #include <linux/fd.h> | ||
12 | |||
13 | #include "kinit.h" | ||
14 | #include "do_mounts.h" | ||
15 | #include "fstype.h" | ||
16 | #include "zlib.h" | ||
17 | |||
18 | #define BUF_SZ 65536 | ||
19 | |||
20 | static void wait_for_key(void) | ||
21 | { | ||
22 | /* Wait until the user presses Enter */ | ||
23 | while (getchar() != '\n') | ||
24 | ; | ||
25 | } | ||
26 | |||
27 | static int change_disk(const char *devpath, int rfd, int disk) | ||
28 | { | ||
29 | /* Try to eject and/or quiesce the device */ | ||
30 | sync(); | ||
31 | if (ioctl(rfd, FDEJECT, 0)) { | ||
32 | if (errno == ENOTTY) { | ||
33 | /* Not a floppy */ | ||
34 | ioctl(rfd, CDROMEJECT, 0); | ||
35 | } else { | ||
36 | /* Non-ejectable floppy */ | ||
37 | ioctl(rfd, FDRESET, FD_RESET_IF_NEEDED); | ||
38 | } | ||
39 | } | ||
40 | close(rfd); | ||
41 | |||
42 | fprintf(stderr, | ||
43 | "\nPlease insert disk %d for ramdisk and press Enter...", disk); | ||
44 | wait_for_key(); | ||
45 | |||
46 | return open(devpath, O_RDONLY); | ||
47 | } | ||
48 | |||
49 | /* Also used in initrd.c */ | ||
50 | int load_ramdisk_compressed(const char *devpath, FILE * wfd, | ||
51 | off_t ramdisk_start) | ||
52 | { | ||
53 | int rfd = -1; | ||
54 | unsigned long long ramdisk_size, ramdisk_left; | ||
55 | int disk = 1; | ||
56 | ssize_t bytes; | ||
57 | int rv; | ||
58 | unsigned char in_buf[BUF_SZ], out_buf[BUF_SZ]; | ||
59 | z_stream zs; | ||
60 | |||
61 | zs.zalloc = Z_NULL; /* Use malloc() */ | ||
62 | zs.zfree = Z_NULL; /* Use free() */ | ||
63 | zs.next_in = Z_NULL; /* No data read yet */ | ||
64 | zs.avail_in = 0; | ||
65 | zs.next_out = out_buf; | ||
66 | zs.avail_out = BUF_SZ; | ||
67 | |||
68 | if (inflateInit2(&zs, 32 + 15) != Z_OK) | ||
69 | goto err1; | ||
70 | |||
71 | rfd = open(devpath, O_RDONLY); | ||
72 | if (rfd < 0) | ||
73 | goto err2; | ||
74 | |||
75 | /* Set to the size of the medium, or "infinite" */ | ||
76 | if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size)) | ||
77 | ramdisk_size = ~0ULL; | ||
78 | |||
79 | do { | ||
80 | /* Purge the output preferentially over reading new | ||
81 | input, so we don't end up overrunning the input by | ||
82 | accident and demanding a new disk which doesn't | ||
83 | exist... */ | ||
84 | if (zs.avail_out == 0) { | ||
85 | _fwrite(out_buf, BUF_SZ, wfd); | ||
86 | zs.next_out = out_buf; | ||
87 | zs.avail_out = BUF_SZ; | ||
88 | } else if (zs.avail_in == 0) { | ||
89 | if (ramdisk_start >= ramdisk_size) { | ||
90 | rfd = change_disk(devpath, rfd, ++disk); | ||
91 | if (rfd < 0) | ||
92 | goto err2; | ||
93 | |||
94 | if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size)) | ||
95 | ramdisk_size = ~0ULL; | ||
96 | ramdisk_start = 0; | ||
97 | niro | 1122 | dprintf("New size = %llu\n", ramdisk_size); |
98 | niro | 532 | } |
99 | do { | ||
100 | ramdisk_left = ramdisk_size - ramdisk_start; | ||
101 | bytes = min(ramdisk_left, | ||
102 | (unsigned long long)BUF_SZ); | ||
103 | bytes = pread(rfd, in_buf, bytes, | ||
104 | ramdisk_start); | ||
105 | } while (bytes == -1 && errno == EINTR); | ||
106 | if (bytes <= 0) | ||
107 | goto err2; | ||
108 | ramdisk_start += bytes; | ||
109 | zs.next_in = in_buf; | ||
110 | zs.avail_in = bytes; | ||
111 | |||
112 | /* Print dots if we're reading from a real block device */ | ||
113 | if (ramdisk_size != ~0ULL) | ||
114 | putc('.', stderr); | ||
115 | } | ||
116 | rv = inflate(&zs, Z_SYNC_FLUSH); | ||
117 | } while (rv == Z_OK || rv == Z_BUF_ERROR); | ||
118 | |||
119 | niro | 1122 | dprintf("kinit: inflate returned %d\n", rv); |
120 | niro | 532 | |
121 | if (rv != Z_STREAM_END) | ||
122 | goto err2; | ||
123 | |||
124 | /* Write the last */ | ||
125 | _fwrite(out_buf, BUF_SZ - zs.avail_out, wfd); | ||
126 | niro | 1122 | dprintf("kinit: writing %d bytes\n", BUF_SZ - zs.avail_out); |
127 | niro | 532 | |
128 | inflateEnd(&zs); | ||
129 | return 0; | ||
130 | |||
131 | err2: | ||
132 | inflateEnd(&zs); | ||
133 | err1: | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | static int | ||
138 | load_ramdisk_raw(const char *devpath, FILE * wfd, off_t ramdisk_start, | ||
139 | unsigned long long fssize) | ||
140 | { | ||
141 | unsigned long long ramdisk_size, ramdisk_left; | ||
142 | int disk = 1; | ||
143 | ssize_t bytes; | ||
144 | unsigned char buf[BUF_SZ]; | ||
145 | int rfd; | ||
146 | |||
147 | rfd = open(devpath, O_RDONLY); | ||
148 | if (rfd < 0) | ||
149 | return -1; | ||
150 | |||
151 | /* Set to the size of the medium, or "infinite" */ | ||
152 | if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size)) | ||
153 | ramdisk_size = ~0ULL; | ||
154 | |||
155 | niro | 1122 | dprintf("start: %llu size: %llu fssize: %llu\n", |
156 | ramdisk_start, ramdisk_size, fssize); | ||
157 | niro | 532 | |
158 | while (fssize) { | ||
159 | |||
160 | if (ramdisk_start >= ramdisk_size) { | ||
161 | rfd = change_disk(devpath, rfd, ++disk); | ||
162 | if (rfd < 0) | ||
163 | return -1; | ||
164 | |||
165 | if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size)) | ||
166 | ramdisk_size = ~0ULL; | ||
167 | ramdisk_start = 0; | ||
168 | } | ||
169 | |||
170 | do { | ||
171 | ramdisk_left = | ||
172 | min(ramdisk_size - ramdisk_start, fssize); | ||
173 | bytes = min(ramdisk_left, (unsigned long long)BUF_SZ); | ||
174 | bytes = pread(rfd, buf, bytes, ramdisk_start); | ||
175 | } while (bytes == -1 && errno == EINTR); | ||
176 | if (bytes <= 0) | ||
177 | break; | ||
178 | _fwrite(buf, bytes, wfd); | ||
179 | |||
180 | ramdisk_start += bytes; | ||
181 | fssize -= bytes; | ||
182 | |||
183 | /* Print dots if we're reading from a real block device */ | ||
184 | if (ramdisk_size != ~0ULL) | ||
185 | putc('.', stderr); | ||
186 | } | ||
187 | |||
188 | return !!fssize; | ||
189 | } | ||
190 | |||
191 | niro | 1122 | int ramdisk_load(int argc, char *argv[]) |
192 | niro | 532 | { |
193 | const char *arg_prompt_ramdisk = get_arg(argc, argv, "prompt_ramdisk="); | ||
194 | const char *arg_ramdisk_blocksize = | ||
195 | get_arg(argc, argv, "ramdisk_blocksize="); | ||
196 | const char *arg_ramdisk_start = get_arg(argc, argv, "ramdisk_start="); | ||
197 | const char *arg_ramdisk_device = get_arg(argc, argv, "ramdisk_device="); | ||
198 | |||
199 | int prompt_ramdisk = arg_prompt_ramdisk ? atoi(arg_prompt_ramdisk) : 0; | ||
200 | int ramdisk_blocksize = | ||
201 | arg_ramdisk_blocksize ? atoi(arg_ramdisk_blocksize) : 512; | ||
202 | off_t ramdisk_start = | ||
203 | arg_ramdisk_start | ||
204 | ? strtoumax(arg_ramdisk_start, NULL, 10) * ramdisk_blocksize : 0; | ||
205 | const char *ramdisk_device = | ||
206 | arg_ramdisk_device ? arg_ramdisk_device : "/dev/fd0"; | ||
207 | |||
208 | dev_t ramdisk_dev; | ||
209 | int rfd; | ||
210 | FILE *wfd; | ||
211 | const char *fstype; | ||
212 | unsigned long long fssize; | ||
213 | int is_gzip = 0; | ||
214 | int err; | ||
215 | |||
216 | if (prompt_ramdisk) { | ||
217 | fprintf(stderr, | ||
218 | "Please insert disk for ramdisk and press Enter..."); | ||
219 | wait_for_key(); | ||
220 | } | ||
221 | |||
222 | ramdisk_dev = name_to_dev_t(ramdisk_device); | ||
223 | if (!ramdisk_dev) { | ||
224 | fprintf(stderr, | ||
225 | "Failure loading ramdisk: unknown device: %s\n", | ||
226 | ramdisk_device); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | create_dev("/dev/rddev", ramdisk_dev); | ||
231 | create_dev("/dev/ram0", Root_RAM0); | ||
232 | rfd = open("/dev/rddev", O_RDONLY); | ||
233 | wfd = fopen("/dev/ram0", "w"); | ||
234 | |||
235 | if (rfd < 0 || !wfd) { | ||
236 | perror("Could not open ramdisk device"); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* Check filesystem type */ | ||
241 | if (identify_fs(rfd, &fstype, &fssize, ramdisk_start) || | ||
242 | (fssize == 0 && !(is_gzip = !strcmp(fstype, "gzip")))) { | ||
243 | fprintf(stderr, | ||
244 | "Failure loading ramdisk: unknown filesystem type\n"); | ||
245 | niro | 1297 | close(rfd); |
246 | fclose(wfd); | ||
247 | niro | 532 | return 0; |
248 | } | ||
249 | |||
250 | niro | 1122 | dprintf("kinit: ramdisk is %s, size %llu\n", fstype, fssize); |
251 | niro | 532 | |
252 | fprintf(stderr, "Loading ramdisk (%s) ...", is_gzip ? "gzip" : "raw"); | ||
253 | |||
254 | close(rfd); | ||
255 | |||
256 | if (is_gzip) | ||
257 | err = load_ramdisk_compressed("/dev/rddev", wfd, ramdisk_start); | ||
258 | else | ||
259 | err = load_ramdisk_raw("/dev/rddev", wfd, | ||
260 | ramdisk_start, fssize); | ||
261 | |||
262 | fclose(wfd); | ||
263 | |||
264 | putc('\n', stderr); | ||
265 | |||
266 | if (err) { | ||
267 | perror("Failure loading ramdisk"); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | return 1; | ||
272 | } |