blob: 2b3503ad6a45dc8c15415e5e45257fed5bdaa110 [file] [log] [blame]
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <linux/fs.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
#include "kinit.h"
#include "do_mounts.h"
#include "fstype.h"
#include "zlib.h"
#define BUF_SZ 65536
static void wait_for_key(void)
{
/* Wait until the user presses Enter */
while (getchar() != '\n')
;
}
static int change_disk(const char *devpath, int rfd, int disk)
{
/* Try to eject and/or quiesce the device */
sync();
if (ioctl(rfd, FDEJECT, 0)) {
if (errno == ENOTTY) {
/* Not a floppy */
ioctl(rfd, CDROMEJECT, 0);
} else {
/* Non-ejectable floppy */
ioctl(rfd, FDRESET, FD_RESET_IF_NEEDED);
}
}
close(rfd);
fprintf(stderr,
"\nPlease insert disk %d for ramdisk and press Enter...", disk);
wait_for_key();
return open(devpath, O_RDONLY);
}
/* Also used in initrd.c */
int load_ramdisk_compressed(const char *devpath, FILE * wfd,
off_t ramdisk_start)
{
int rfd = -1;
unsigned long long ramdisk_size, ramdisk_left;
int disk = 1;
ssize_t bytes;
int rv;
unsigned char in_buf[BUF_SZ], out_buf[BUF_SZ];
z_stream zs;
zs.zalloc = Z_NULL; /* Use malloc() */
zs.zfree = Z_NULL; /* Use free() */
zs.next_in = Z_NULL; /* No data read yet */
zs.avail_in = 0;
zs.next_out = out_buf;
zs.avail_out = BUF_SZ;
if (inflateInit2(&zs, 32 + 15) != Z_OK)
goto err1;
rfd = open(devpath, O_RDONLY);
if (rfd < 0)
goto err2;
/* Set to the size of the medium, or "infinite" */
if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
ramdisk_size = ~0ULL;
do {
/* Purge the output preferentially over reading new
input, so we don't end up overrunning the input by
accident and demanding a new disk which doesn't
exist... */
if (zs.avail_out == 0) {
_fwrite(out_buf, BUF_SZ, wfd);
zs.next_out = out_buf;
zs.avail_out = BUF_SZ;
} else if (zs.avail_in == 0) {
if (ramdisk_start >= ramdisk_size) {
rfd = change_disk(devpath, rfd, ++disk);
if (rfd < 0)
goto err2;
if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
ramdisk_size = ~0ULL;
ramdisk_start = 0;
dprintf("New size = %llu\n", ramdisk_size);
}
do {
ramdisk_left = ramdisk_size - ramdisk_start;
bytes = min(ramdisk_left,
(unsigned long long)BUF_SZ);
bytes = pread(rfd, in_buf, bytes,
ramdisk_start);
} while (bytes == -1 && errno == EINTR);
if (bytes <= 0)
goto err2;
ramdisk_start += bytes;
zs.next_in = in_buf;
zs.avail_in = bytes;
/* Print dots if we're reading from a real block device */
if (ramdisk_size != ~0ULL)
putc('.', stderr);
}
rv = inflate(&zs, Z_SYNC_FLUSH);
} while (rv == Z_OK || rv == Z_BUF_ERROR);
dprintf("kinit: inflate returned %d\n", rv);
if (rv != Z_STREAM_END)
goto err2;
/* Write the last */
_fwrite(out_buf, BUF_SZ - zs.avail_out, wfd);
dprintf("kinit: writing %d bytes\n", BUF_SZ - zs.avail_out);
inflateEnd(&zs);
return 0;
err2:
inflateEnd(&zs);
err1:
return -1;
}
static int
load_ramdisk_raw(const char *devpath, FILE * wfd, off_t ramdisk_start,
unsigned long long fssize)
{
unsigned long long ramdisk_size, ramdisk_left;
int disk = 1;
ssize_t bytes;
unsigned char buf[BUF_SZ];
int rfd;
rfd = open(devpath, O_RDONLY);
if (rfd < 0)
return -1;
/* Set to the size of the medium, or "infinite" */
if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
ramdisk_size = ~0ULL;
dprintf("start: %llu size: %llu fssize: %llu\n",
ramdisk_start, ramdisk_size, fssize);
while (fssize) {
if (ramdisk_start >= ramdisk_size) {
rfd = change_disk(devpath, rfd, ++disk);
if (rfd < 0)
return -1;
if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
ramdisk_size = ~0ULL;
ramdisk_start = 0;
}
do {
ramdisk_left =
min(ramdisk_size - ramdisk_start, fssize);
bytes = min(ramdisk_left, (unsigned long long)BUF_SZ);
bytes = pread(rfd, buf, bytes, ramdisk_start);
} while (bytes == -1 && errno == EINTR);
if (bytes <= 0)
break;
_fwrite(buf, bytes, wfd);
ramdisk_start += bytes;
fssize -= bytes;
/* Print dots if we're reading from a real block device */
if (ramdisk_size != ~0ULL)
putc('.', stderr);
}
return !!fssize;
}
int ramdisk_load(int argc, char *argv[])
{
const char *arg_prompt_ramdisk = get_arg(argc, argv, "prompt_ramdisk=");
const char *arg_ramdisk_blocksize =
get_arg(argc, argv, "ramdisk_blocksize=");
const char *arg_ramdisk_start = get_arg(argc, argv, "ramdisk_start=");
const char *arg_ramdisk_device = get_arg(argc, argv, "ramdisk_device=");
int prompt_ramdisk = arg_prompt_ramdisk ? atoi(arg_prompt_ramdisk) : 0;
int ramdisk_blocksize =
arg_ramdisk_blocksize ? atoi(arg_ramdisk_blocksize) : 512;
off_t ramdisk_start =
arg_ramdisk_start
? strtoumax(arg_ramdisk_start, NULL, 10) * ramdisk_blocksize : 0;
const char *ramdisk_device =
arg_ramdisk_device ? arg_ramdisk_device : "/dev/fd0";
dev_t ramdisk_dev;
int rfd;
FILE *wfd;
const char *fstype;
unsigned long long fssize;
int is_gzip = 0;
int err;
if (prompt_ramdisk) {
fprintf(stderr,
"Please insert disk for ramdisk and press Enter...");
wait_for_key();
}
ramdisk_dev = name_to_dev_t(ramdisk_device);
if (!ramdisk_dev) {
fprintf(stderr,
"Failure loading ramdisk: unknown device: %s\n",
ramdisk_device);
return 0;
}
create_dev("/dev/rddev", ramdisk_dev);
create_dev("/dev/ram0", Root_RAM0);
rfd = open("/dev/rddev", O_RDONLY);
wfd = fopen("/dev/ram0", "w");
if (rfd < 0 || !wfd) {
perror("Could not open ramdisk device");
return 0;
}
/* Check filesystem type */
if (identify_fs(rfd, &fstype, &fssize, ramdisk_start) ||
(fssize == 0 && !(is_gzip = !strcmp(fstype, "gzip")))) {
fprintf(stderr,
"Failure loading ramdisk: unknown filesystem type\n");
close(rfd);
fclose(wfd);
return 0;
}
dprintf("kinit: ramdisk is %s, size %llu\n", fstype, fssize);
fprintf(stderr, "Loading ramdisk (%s) ...", is_gzip ? "gzip" : "raw");
close(rfd);
if (is_gzip)
err = load_ramdisk_compressed("/dev/rddev", wfd, ramdisk_start);
else
err = load_ramdisk_raw("/dev/rddev", wfd,
ramdisk_start, fssize);
fclose(wfd);
putc('\n', stderr);
if (err) {
perror("Failure loading ramdisk");
return 0;
}
return 1;
}