#include #include #include #include #include #include #include #include #include #include #include #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; }