diff options
| author | hpa <hpa> | 1998-02-03 19:02:57 +0000 |
|---|---|---|
| committer | hpa <hpa> | 1998-02-03 19:02:57 +0000 |
| commit | 6d78fcfbd21231dda700d6aa16e1d708835309e2 (patch) | |
| tree | 449fc29b2f8a49aeaab439abf21f3936483c6250 /syslinux.c | |
| parent | 1a54fbb3c5fdf3b7392ce046043b8eab44786a5c (diff) | |
| download | syslinux-6d78fcfbd21231dda700d6aa16e1d708835309e2.tar.gz | |
More work on Linux installer
Diffstat (limited to 'syslinux.c')
| -rw-r--r-- | syslinux.c | 178 |
1 files changed, 177 insertions, 1 deletions
@@ -13,10 +13,28 @@ /* * syslinux.c - Linux installer program for SYSLINUX + * + * This program ought to be portable. I hope so, at least. + * + * HPA note: this program needs too much privilege. We should probably + * access the filesystem directly like mtools does so we don't have to + * mount the disk. Either that or if Linux gets an fmount() system call + * we probably could do the mounting ourselves, and make this program + * setuid safe. */ +#include <paths.h> #include <stdio.h> #include <mntent.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +#ifndef _PATH_MOUNT +#define _PATH_MOUNT "/bin/mount" +#endif extern const unsigned char bootsect[]; extern const unsigned int bootsect_len; @@ -24,14 +42,172 @@ extern const unsigned int bootsect_len; extern const unsigned char ldlinux[]; extern const unsigned int ldlinux_len; +char *program; /* Name of program */ char *device; /* Device to install to */ +enum bs_offsets = { + bsJump = 0x00, + bsOemName = 0x03, + bsBytesPerSec = 0x0b, + bsSecPerClust = 0x0d, + bsResSectors = 0x0e, + bsFATs = 0x10, + bsRootDirEnts = 0x11, + bsSectors = 0x13, + bsMedia = 0x15, + bsFATsecs = 0x16, + bsSecPerTrack = 0x18, + bsHeads = 0x1a, + bsHiddenSecs = 0x1c, + bsHugeSectors = 0x20, + bsDriveNumber = 0x24, + bsReserved1 = 0x25, + bsBootSignature = 0x26, + bsVolumeID = 0x27, + bsVolumeLabel = 0x2b, + bsFileSysType = 0x36, + bsCode = 0x3e, + bsSignature = 0x1fe +}; + +#define bsCopyStart bsBytesPerSec +#define bsCopyLen (bsCode-bsBytesPerSec) + +/* + * Access functions for littleendian numbers, possibly misaligned. + */ +static uint16 get_16(unsigned char *p) +{ + return (uint16)p[0] + ((uint16)p[1] << 8); +} + +static uint32 get_32(unsigned char *p) +{ + return (uint32)p[0] + ((uint32)p[1] << 8) + + ((uint32)p[2] << 16) + ((uint32)p[3] << 24); +} + int main(int argc, char *argv[]) { + static unsigned char sectbuf[512], *dp; + int *dev_fd; + struct stat st; + int nb, left, veryold; + unsigned int sectors, clusters; + + program = argv[0]; + if ( argc != 2 ) { - fprintf(stderr, "Usage: %s device\n", argv[0]); + fprintf(stderr, "Usage: %s device\n", program); + exit(1); + } + + device = argv[1]; + + /* + * First make sure we can open the device at all, and that we have + * read/write permission. + */ + dev_fd = open(device, O_RDWR); + if ( dev_fd < 0 || fstat(dev_fd, &st) < 0 ) { + perror(device); + exit(1); + } + + if ( !S_ISBLK(st.st_mode) || !S_ISREG(st.st_mode) ) { + fprintf("%s: not a block device or regular file\n", device); + exit(1); + } + + left = 512; + dp = sectbuf; + while ( left ) { + nb = read(dp, left, dev_fd); + if ( nb == -1 && errno == EINTR ) + continue; + if ( nb < 0 ) { + perror(device); + exit(1); + } else if ( nb == 0 ) { + fprintf(stderr, "%s: no boot sector\n", device); + exit(1); + } + dp += nb; + left -= nb; + } + close(device); + + /* + * Check to see that what we got was indeed an MS-DOS boot sector/superblock + */ + + if ( sectbuf[bsBootSignature] == 0x29 ) { + /* It's DOS, and it has all the new nice fields */ + + veryold = 0; + + sectors = get_16(sectbuf+bsSectors); + sectors = sectors ? sectors : get_32(sectbuf+bsHugeSectors); + clusters = sectors / sectbuf[bsSecPerClust]; + + if ( !memcmp(sectbuf+bsFileSysType, "FAT12 ", 8) ) { + if ( clust > 4086 ) { + fprintf(stderr, "%s: ERROR: FAT12 but claims more than 4086 clusters\n", + device); + exit(1); + } + } else { + fprintf(stderr, "%s: filesystem type \"%8.8s\" not supported\n", + sectbuf+bsFileSysType); + exit(1); + } + } else { + veryold = 1; + + if ( sectbuf[bsSecPerClust] & (sectbuf[bsSecPerClust] - 1) || + sectbuf[bsSecPerClust] == 0 ) { + fprintf(stderr, "%s: This doesn't look like a FAT filesystem\n", + device); + } + + sectors = get_16(sectbuf+bsSectors); + sectors = sectors ? sectors : get_32(sectbuf+bsHugeSectors); + clusters = sectors / sectbuf[bsSecPerClust]; + + if ( clusters > 4086 ) { + fprintf(stderr, "%s: Only FAT12 filesystems supported\n", device); + exit(1); + } + } + + if ( get_16(sectbuf+bsBytesPerSec) != 512 ) { + fprintf(stderr, "%s: Sector sizes other than 512 not supported\n", + device); exit(1); } + if ( sectbuf[bsSecPerClust] > 64 ) { + fprintf(stderr, "%s: Cluster sizes larger than 32K not supported\n", + device); + } + + /* + * Now mount the device. If we are non-root we need to find an fstab + * entry for this device which has the user flag set. + */ + if ( geteuid() ) { + FILE *fstab; + struct mntent *mnt; + if ( !(fstab = setmntent(MNTTAB, "r")) ) { + fprintf("%s: cannot open " MNTTAB "\n", program); + } + + while ( (mnt = getmntent(fstab)) ) { + if ( !strcmp(device, mnt->mnt_fsname) ) { + if ( !strcmp(mnt->mnt_type, "msdos") || + !strcmp(mnt->mnt_type, "umsdos") || + !strcmp(mnt->mnt_type, "vfat") || + !strcmp(mnt->mnt_type, "uvfat") || + !strcmp(mnt->mnt_type, "auto") return 0; } |
