propagator/mkinitrd_helper/mkinitrd_helper.c
2004-01-20 18:32:43 +00:00

309 lines
6.2 KiB
C

/*
* Guillaume Cottenceau (gc@mandrakesoft.com)
*
* Copyright 2001 MandrakeSoft
*
* This software is covered by the GPL license.
*
* This software may be freely redistributed under the terms of the GNU
* public license.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* This little program replaces usual sash and insmod.static based script
* from mkinitrd (that insmod modules, plus possibly mount a partition and
* losetup a loopback-based / on the partition).
*
*
* On my machine:
* gzipped sash + insmod.static 502491 bytes
* gzipped <this-program> 14243 bytes
*
* There will be room for linux-2.4 and many modules, now. Cool.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include "insmod.h"
int quiet = 0;
void vlog_message(const char * s, va_list args)
{
vprintf(s, args);
printf("\n");
}
void log_perror(char *msg)
{
perror(msg);
}
static void fatal_error(char *msg)
{
printf("[] E: %s\n[] giving hand to kernel.\n", msg);
exit(-1);
}
static void warning(char *msg)
{
printf("[] W: %s\n", msg);
}
static void parse_parms(const char * parm, char ** parm1, char ** parm2, char ** parm3)
{
char * ptr;
ptr = strchr(parm, '\n');
if (!ptr)
fatal_error("bad config file: no newline after parms");
*parm1 = malloc(ptr-parm+1); /* yup, never freed :-) */
memcpy(*parm1, parm, ptr-parm);
(*parm1)[ptr-parm] = '\0';
if (!parm2)
return;
*parm2 = strchr(*parm1, ' ');
if (!*parm2)
return;
**parm2 = '\0';
(*parm2)++;
if (!parm3)
return;
*parm3 = strchr(*parm2, ' ');
if (!*parm3)
return;
**parm3 = '\0';
(*parm3)++;
}
static void insmod_(const char * parm)
{
char * mod_name, * options;
parse_parms(parm, &mod_name, &options, NULL);
#ifdef DEBUG
printf("insmod %s options %s\n", mod_name, options);
#endif
if (!quiet)
printf("[] Loading module %s\n", mod_name);
if (insmod_call(mod_name, options))
perror("insmod failed");
}
static void mount_(const char * parm)
{
char * dev, * location, * fs;
unsigned long flags;
char * opts = NULL;
parse_parms(parm, &dev, &location, &fs);
#ifdef DEBUG
printf("mounting %s on %s as type %s\n", dev, location, fs);
#endif
if (!quiet)
printf("[] Mounting device containing loopback root filesystem\n");
flags = MS_MGC_VAL;
if (!strcmp(fs, "vfat"))
opts = "check=relaxed";
if (mount(dev, location, fs, flags, opts))
perror("mount failed");
}
#define LO_NAME_SIZE 64
#define LO_KEY_SIZE 32
struct loop_info
{
int lo_number; /* ioctl r/o */
dev_t lo_device; /* ioctl r/o */
unsigned long lo_inode; /* ioctl r/o */
dev_t lo_rdevice; /* ioctl r/o */
int lo_offset;
int lo_encrypt_type;
int lo_encrypt_key_size; /* ioctl w/o */
int lo_flags; /* ioctl r/o */
char lo_name[LO_NAME_SIZE];
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
unsigned long lo_init[2];
char reserved[4];
};
#define LOOP_SET_FD 0x4C00
#define LOOP_CLR_FD 0x4C01
#define LOOP_SET_STATUS 0x4C02
static void set_loop_(const char * parm)
{
struct loop_info loopinfo;
int fd, ffd;
char * device, * file;
parse_parms(parm, &device, &file, NULL);
#ifdef DEBUG
printf("set_looping %s with %s\n", device, file);
#endif
if (!quiet)
printf("[] Setting up loopback file %s\n", file);
if ((ffd = open(file, O_RDWR)) < 0) {
perror("set_loop, opening file in rw");
exit(-1);
}
if ((fd = open(device, O_RDWR)) < 0) {
perror("set_loop, opening loop device in rw");
close(ffd);
exit(-1);
}
memset(&loopinfo, 0, sizeof (loopinfo));
strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
loopinfo.lo_offset = 0;
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
close(fd);
close(ffd);
perror("LOOP_SET_FD");
exit(-1);
}
if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
(void) ioctl (fd, LOOP_CLR_FD, 0);
close(fd);
close(ffd);
perror("LOOP_SET_STATUS");
exit(-1);
}
close(fd);
close(ffd);
}
#define MD_MAJOR 9
#define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
#include <linux/raid/md_u.h>
static void raidautorun_(const char * parm)
{
char * device;
int fd;
parse_parms(parm, &device, NULL, NULL);
if (!quiet)
printf("[] Calling raid autorun for %s\n", device);
fd = open(device, O_RDWR, 0);
if (fd < 0) {
printf("raidautorun: failed to open %s: %d\n", device, errno);
return;
}
if (ioctl(fd, RAID_AUTORUN, 0)) {
printf("raidautorun: RAID_AUTORUN failed: %d\n", errno);
}
close(fd);
}
static int handle_command(char ** ptr, char * cmd_name, void (*cmd_func)(const char * parm))
{
if (!strncmp(*ptr, cmd_name, strlen(cmd_name))) {
*ptr = strchr(*ptr, '\n');
if (!*ptr)
fatal_error("Bad config file: no newline after command");
(*ptr)++;
cmd_func(*ptr);
*ptr = strchr(*ptr, '\n');
if (!*ptr)
exit(0);
(*ptr)++;
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
int fd_conf, i;
char buf[5000];
char * ptr;
if (strstr(argv[0], "modprobe"))
exit(0);
if (mount("/proc", "/loopfs", "proc", 0, NULL))
printf("[] couldn't mount proc filesystem\n");
else {
int fd_cmdline = open("/loopfs/cmdline", O_RDONLY);
if (fd_cmdline > 0) {
i = read(fd_cmdline, buf, sizeof(buf));
if (i == -1)
warning("could not read cmdline");
else {
buf[i] = '\0';
if (strstr(buf, "quiet"))
quiet = 1;
}
close(fd_cmdline);
}
umount("/loopfs");
}
if (!quiet)
printf("[] initrd_helper v" VERSION "\n");
if ((fd_conf = open("/mkinitrd_helper.conf", O_RDONLY)) < 0)
fatal_error("could not open mkinitrd_helper config file");
i = read(fd_conf, buf, sizeof(buf));
if (i == -1)
fatal_error("could not read mkinitrd_helper config file");
buf[i] = '\0';
close(fd_conf);
ptr = buf;
while (*ptr)
if (!(handle_command(&ptr, "insmod", insmod_) +
handle_command(&ptr, "mount", mount_) +
handle_command(&ptr, "raidautorun", raidautorun_) +
handle_command(&ptr, "set_loop", set_loop_)))
warning("unkown command (trying to continue)");
return 0;
}