/* This is the source for linuxrc.
*
*  It mounts the dos, win or winnt partition and associates the image file 
*  \linux\linuxdsk.img with the loop device /dev/loop0.
*  
*  You create the initrd like above, but you only have this on it.
*
*  drwxr-xr-x  2 root root  4096 2004-10-31 15:45 dev/
*  crw--w--w-  1 root tty   5, 1 2004-10-31 14:57 dev/console
*  brw-rw----  1 root disk  3, 1 2004-10-31 14:57 dev/hda1
*  brw-rw----  1 root disk  7, 0 2004-10-31 15:45 dev/loop0
*  lrwxr-xr-x  1 root root     4 2004-10-31 14:59 dev/win -> hda1
*  -rwxr-xr-x  1 root root 23032 2004-10-31 15:54 linuxrc
*  drwxr-xr-x  2 root root  4096 2004-10-31 15:44 mnt/
*
*  In the above example i have a win9x partition with \linux\linuxdsk.img
*  on /dev/hda1, so i make a link called win to it 'ln -sf hda1 win'.
*  
*  If it were a dos partition it would be 'ln -sf hda1 dos'.
*  If it were a ntfs partition it would be 'ln -sf hda1 winnt'.
*
* I took the original file from The Loopback Root Filesystem HOWTO
*
*  by Andrew M. Bishop, amb@gedanken.demon.co.uk
*  v1.1.2, 23 Mar 2000
*
*  v1.1.11, 7 Sep 2002
*  Kent Robotti <robotti@godmail.com> 
*
*  v1.2.2, 1 Nov 2004
*  Bodo Giannone <http://www.giannone.de>
*
*
* You can compile it this way.
* gcc -Os -mcpu=i386 -D_FILE_OFFSET_BITS=64 -static -s -o linuxrc linuxrc.c
*
* It does compile also with uClibc (a very small libc) 
* with the command line from above.
* http://www.uclibc.org
*
* You could use a smaller static libc, called dietlibc.
* http://www.fefe.de/dietlibc/
*
* dietlibc# make
* dietlibc/bin-i386# ./diet gcc -Os -m386 -D_FILE_OFFSET_BITS=64 \
* -static -s -o linuxrc linuxrc.c
*/

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <linux/fs.h>

#include <linux/posix_types.h>
#undef dev_t
#define dev_t __kernel_dev_t
#include <linux/loop.h>
#undef dev_t

void die(char *s) {
  write(2,s,strlen(s));
}

int set_loop(const char *device, const char *file, int offset, int loopro)
{
	struct loop_info loopinfo;
	int	fd, ffd, mode, i;
	char	*pass;

	mode = loopro ? O_RDONLY : O_RDWR;
	if ((ffd = open (file, mode)) < 0 && !loopro
	    && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) {
	  perror (file);
	  return 0;
	}
	if ((fd = open (device, mode)) < 0) {
	  perror (device);
	  return 0;
	}
	loopro = (mode == O_RDONLY);

	memset(&loopinfo, 0, sizeof(loopinfo));
	strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
	loopinfo.lo_name[LO_NAME_SIZE-1] = 0;
	loopinfo.lo_offset = offset;
	loopinfo.lo_encrypt_key_size = 0;
	if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
		perror("ioctl: LOOP_SET_FD");
		exit(1);
	}
	if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
		(void) ioctl(fd, LOOP_CLR_FD, 0);
		perror("ioctl: LOOP_SET_STATUS");
		exit(1);
	}
	close(fd);
	close(ffd);
	return 1;
}

int main(void) {

	int i,notmounted;
	FILE *distfile;

		distfile=fopen("/dev/dos","r");

		if (distfile) {  
        
		fclose(distfile);
              
	while (1) {
		notmounted=mount("/dev/dos","/mnt","msdos",MS_MGC_VAL | MS_NOEXEC,"quiet",0);
		if (!notmounted)
			break;
		else

		die("\n\tERROR!\tCould not mount the dos partition!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		pause();
		exit(1);
	}
	die("INITRD: Mounted dos partition under /initrd/mnt directory...\n");
	while (1) {
		distfile=fopen("/mnt/linux/linuxdsk.img","r");
		if (distfile==NULL) {
			die("\n\tERROR!\tCould not find \\linux\\linuxdsk.img on the dos system!\n");
        		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
			umount("/mnt");
     		        pause();
 		        exit(1);
		}
		break;
	}

	fclose(distfile);

           umask(0);

	if(!(set_loop("/dev/loop0","/mnt/linux/linuxdsk.img",0,0))) {
		die("\n\tERROR!\tCan't associate \\linux\\linuxdsk.img\n");
		die("\t\twith the loop device /dev/loop0!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		umount("/mnt");
		pause();
		exit(1);
	}

		exit(0);
    } else

		distfile=fopen("/dev/win","r");

		if (distfile) {  

        	fclose(distfile);


	while (1) {
		notmounted=mount("/dev/win","/mnt","vfat",MS_MGC_VAL | MS_NOEXEC,"quiet",0);
		if (!notmounted)
			break;
		else

		die("\n\tERROR!\tCould not mount the win partition!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		pause();
		exit(1);
	}
	die("INITRD: Mounted win partition under /initrd/mnt directory...\n");
	while (1) {
		distfile=fopen("/mnt/linux/linuxdsk.img","r");
		if (distfile==NULL) {
		die("\n\tERROR!\tCould not find \\linux\\linuxdsk.img on the win system!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		umount("/mnt");
		pause();
 		exit(1);
		}
		break;
	}

	fclose(distfile);

           umask(0);

	if(!(set_loop("/dev/loop0","/mnt/linux/linuxdsk.img",0,0))) {
		die("\n\tERROR!\tCan't associate \\linux\\linuxdsk.img\n");
		die("t\twith the loop device /dev/loop0!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		umount("/mnt");
		pause();
		exit(1);
	}

		exit(0);

    } else

		distfile=fopen("/dev/winnt","r");

		if (distfile) {  

        	fclose(distfile);


	while (1) {
//		notmounted=mount("/dev/winnt","/mnt","ntfs",MS_MGC_VAL | MS_NOEXEC,"quiet",0);
		notmounted=mount("/dev/winnt","/mnt","ntfs",MS_MGC_VAL | MS_NOEXEC,0);		
		if (!notmounted)
			break;
		else

		die("\n\tERROR!\tCould not mount the winnt partition!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		pause();
		exit(1);
	}
	die("INITRD: Mounted winnt partition under /initrd/mnt directory...\n");
	while (1) {
		distfile=fopen("/mnt/linux/linuxdsk.img","r");
		if (distfile==NULL) {
		die("\n\tERROR!\tCould not find \\linux\\linuxdsk.img on the winnt system!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		umount("/mnt");
		pause();
 		exit(1);
		}
		break;
	}

	fclose(distfile);

           umask(0);

	if(!(set_loop("/dev/loop0","/mnt/linux/linuxdsk.img",0,0))) {
		die("\n\tERROR!\tCan't associate \\linux\\linuxdsk.img\n");
		die("t\twith the loop device /dev/loop0!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		umount("/mnt");
		pause();
		exit(1);
	}

		exit(0);

	}
	die("\n\tERROR!\tCould not find a device /dev/dos, /dev/win,\n");
		die("\t\tor /dev/winnt to mount!\n");
	//	die("\n\tERROR!\tCould not find a device /dev/dos, /dev/win, or /dev/winnt to mount!\n");
		die("\n\t\tPress Ctrl-Alt-Del to reboot!\n");
		pause();
		exit(1);
    }

/* End of linuxrc.c */

