
#include <stdio.h>
#include <minix/partition.h>

#define SECTSIZE	512
#define BLOCKSIZE	1024
#define WHOLEHD		"/dev/hd0"
#define V1_SUPERMAGIC	0x137F		/* magic for V1 file system */
#define V2_SUPERMAGIC	0x2468		/* magic for V2 file system */

char tblbuf[SECTSIZE], dskbuf[BLOCKSIZE];
long lseek();

main(ac, av)
int ac;
char *av[];
{
    int fd, devfd, part, i, k, j;
    short fs_magic;
    long offset;
    char *device, ch;
    struct part_entry *p, *parttbl[4];

    if (ac != 3 || strlen(av[1]) != 8 || strncmp(av[1], "/dev/hd", 7) != 0) {
	printf("usage: mxinstall /dev/hd? MXboot\n");
	exit(1);
    }

    device = WHOLEHD;
    part = av[1][7] - '0';
    if (part <= 0 || part > 9 || part == 5) {
	printf("Cannot install %s\n", av[1]);
	exit(1);
    }
    *(device + 7) = ((part > 5) ? 5: 0) + '0';
    if ((devfd = open(device, 2)) < 0) {
	printf("Cannot open %s\n", device);
	exit(1);
    }
    if (read(devfd, tblbuf, SECTSIZE) != SECTSIZE) {
	printf("Cannot read partition table.");
	exit(1);
    }
    close(devfd);

    if (*(unsigned short *)&tblbuf[0x1fe] != 0xaa55) {
	printf("Invalid partition table.\n");
	exit(1);
    }
    for(i = 0, k = PART_TABLE_OFF; i < NR_PARTITIONS; i++, k += 16) {
	parttbl[i] = (struct part_entry *)&tblbuf[k];
    }
    sort(parttbl);

#ifdef DEBUG
    for(i = 0; i < 4; i++) {
	printf("Part#%d = %ld\n", i, parttbl[i]->lowsec);
    }
#endif

    p = parttbl[part % 5 - 1];
    switch (p->sysind) {
	case OLD_MINIX_PART:
	case 0x40:			/* for old J3100 minix */
		if (p->lowsec & 1L) {
		    printf("%s is sure parttiton, but it will adjust base sector to even.\n");
		    exit(1);
		}
	case MINIX_PART:
		/* check magic number */
		devfd = open(av[1], 2);
		if (devfd < 0) {
		    printf("cannot open %s\n", av[1]);
		    exit(1);
		}
		lseek(devfd, 1024L, 0);
		read(devfd, dskbuf, BLOCKSIZE);
		fs_magic = *(unsigned short *)&dskbuf[16];
		if (fs_magic != V1_SUPERMAGIC && fs_magic != V2_SUPERMAGIC) {
			printf("magic number mismatched\n");
			exit(1);
		}

		/* read mxboot code */
		if ((fd = open(av[2], 0)) < 0) {
		    printf("\"%s\" not exist.\n", av[2]);
		    exit(1);
		}
		if ((k = read(fd, dskbuf, BLOCKSIZE)) < 0) {
		    printf("read error.");
		    exit(1);
		}
		close(fd);

		lseek(devfd, 0L, 0);
		write(devfd, dskbuf, k);
		sync();
		printf("%s installed in %s.\n", av[2], av[1]);
		break;
	default:
		printf("\"%s\" is not MINIX partition.\n", av[1]);
    }
    exit(0);
}

sort(tbl)
struct part_entry *tbl[];
{
    int i, j;
    struct part_entry *p;

    for(i = 0; i < 4; i++)
      for (j = 0; j < 3; j++) {
	if ((tbl[j]->lowsec == 0) && (tbl[j + 1]->lowsec != 0)) {
	    p = tbl[j]; tbl[j] = tbl[j + 1]; tbl[j] = p;
	} else if (tbl[j]->lowsec > tbl[j + 1]->lowsec
						&& tbl[j + 1]->lowsec != 0) {
	    p = tbl[j]; tbl[j] = tbl[j + 1]; tbl[j] = p;
	}
      }
}
