Exemplo n.º 1
0
/*
 * Read the ADV from an existing instance, or initialize if invalid.
 * Returns -1 on fatal errors, 0 if ADV is okay, 1 if the ADV is
 * invalid, and 2 if the file does not exist.
 */
int read_adv(const char *path, const char *cfg)
{
    char *file;
    int fd = -1;
    struct stat st;
    int err = 0;
    int rv;

    rv = asprintf(&file, "%s%s%s", path,
		  path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg);

    if (rv < 0 || !file) {
	perror(program);
	return -1;
    }

    fd = open(file, O_RDONLY);
    if (fd < 0) {
	if (errno != ENOENT) {
	    err = -1;
	} else {
	    syslinux_reset_adv(syslinux_adv);
	    err = 2;		/* Nonexistence is not a fatal error */
	}
    } else if (fstat(fd, &st)) {
	err = -1;
    } else if (st.st_size < 2 * ADV_SIZE) {
	/* Too small to be useful */
	syslinux_reset_adv(syslinux_adv);
	err = 0;		/* Nothing to read... */
    } else if (xpread(fd, syslinux_adv, 2 * ADV_SIZE,
		      st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
	err = -1;
    } else {
	/* We got it... maybe? */
	err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
    }

    if (err < 0)
	perror(file);

    if (fd >= 0)
	close(fd);

    free(file);

    return err;
}
Exemplo n.º 2
0
/*
 * Verify that an in-memory ADV is consistent, making the copies consistent.
 * If neither copy is OK, return -1 and call syslinux_reset_adv().
 */
int syslinux_validate_adv(unsigned char *advbuf)
{
    if (adv_consistent(advbuf + 0 * ADV_SIZE)) {
        memcpy(advbuf + ADV_SIZE, advbuf, ADV_SIZE);
        return 0;
    } else if (adv_consistent(advbuf + 1 * ADV_SIZE)) {
        memcpy(advbuf, advbuf + ADV_SIZE, ADV_SIZE);
        return 0;
    } else {
        syslinux_reset_adv(advbuf);
        return -1;
    }
}
Exemplo n.º 3
0
/*
 * Modify the ADV of an existing installation
 */
int modify_existing_adv(const char *path)
{
    if (opt.reset_adv)
	syslinux_reset_adv(syslinux_adv);
    else if (read_adv(path, "ldlinux.sys") < 0)
	return 1;

    if (modify_adv() < 0)
	return 1;

    if (write_adv(path, "ldlinux.sys") < 0)
	return 1;

    return 0;
}
Exemplo n.º 4
0
/*
 * Make any user-specified ADV modifications in memory
 */
int modify_adv(void)
{
    int rv = 0;

    if (opt.reset_adv)
	syslinux_reset_adv(syslinux_adv);

    if (opt.set_once) {
	if (syslinux_setadv(ADV_BOOTONCE, strlen(opt.set_once), opt.set_once)) {
	    fprintf(stderr, "%s: not enough space for boot-once command\n",
		    program);
	    rv = -1;
	}
    }
    if (opt.menu_save) {
        if (syslinux_setadv(ADV_MENUSAVE, strlen(opt.menu_save), opt.menu_save)) {
	    fprintf(stderr, "%s: not enough space for menu-save label\n",
		    program);
	    rv = -1;
        }
    }

    return rv;
}
Exemplo n.º 5
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd, fd;
    struct stat st;
    int err = 0;
    char mntname[128];
    char *ldlinux_name;
    char *ldlinux_path;
    char *subdir;
    //sector_t *sectors = NULL;
    libfat_sector_t *sectors = NULL;
    int ldlinux_sectors = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    const char *errmsg;
    int mnt_cookie;
    int patch_sectors;
    int i;
    
    printf("syslinux for Mac OS X; created by Geza Kovacs for UNetbootin unetbootin.sf.net\n");

    mypid = getpid();
    umask(077);
    parse_options(argc, argv, MODE_SYSLINUX);

    /* Note: subdir is guaranteed to start and end in / */
    if (opt.directory && opt.directory[0]) {
	int len = strlen(opt.directory);
	int rv = asprintf(&subdir, "%s%s%s",
			  opt.directory[0] == '/' ? "" : "/",
			  opt.directory,
			  opt.directory[len-1] == '/' ? "" : "/");
	if (rv < 0 || !subdir) {
	    perror(program);
	    exit(1);
	}
    } else {
	subdir = "/";
    }

    if (!opt.device || opt.install_mbr || opt.activate_partition)
	usage(EX_USAGE, MODE_SYSLINUX);

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */

    if (geteuid()) {
	die("This program needs root privilege");
    }
    char umountCommand[4096];
    memset(umountCommand, 0, 4096);
    strcat(umountCommand, "hdiutil unmount ");
    strcat(umountCommand, opt.device);
    system(umountCommand);
    
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }

    if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
	die("not a device or regular file");
    }

    if (opt.offset && S_ISBLK(st.st_mode)) {
	die("can't combine an offset with a block device");
    }

    fs_type = VFAT;
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    fsync(dev_fd);
    close(dev_fd);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf))) {
	fprintf(stderr, "%s: %s\n", opt.device, errmsg);
	exit(1);
    }

    /*
     * Now mount the device.
     */
    if (geteuid()) {
	die("This program needs root privilege");
    }
#if 0
    else {
	int i = 0;
	struct stat dst;
	int rv;

	/* We're root or at least setuid.
	   Make a temp dir and pass all the gunky options to mount. */

	if (chdir(_PATH_TMP)) {
	    fprintf(stderr, "%s: Cannot access the %s directory.\n",
		    program, _PATH_TMP);
	    exit(1);
	}
#define TMP_MODE (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH|S_ISVTX)

	if (stat(".", &dst) || !S_ISDIR(dst.st_mode) ||
	    (dst.st_mode & TMP_MODE) != TMP_MODE) {
	    die("possibly unsafe " _PATH_TMP " permissions");
	}

	for (i = 0;; i++) {
	    snprintf(mntname, sizeof mntname, "syslinux.mnt.%lu.%d",
		     (unsigned long)mypid, i);

	    if (lstat(mntname, &dst) != -1 || errno != ENOENT)
		continue;

	    rv = mkdir(mntname, 0000);

	    if (rv == -1) {
		if (errno == EEXIST || errno == EINTR)
		    continue;
		perror(program);
		exit(1);
	    }

	    if (lstat(mntname, &dst) || dst.st_mode != (S_IFDIR | 0000) ||
		dst.st_uid != 0) {
		die("someone is trying to symlink race us!");
	    }
	    break;		/* OK, got something... */
	}

	mntpath = mntname;
    }

    if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
	do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
	rmdir(mntpath);
	die("mount failed");
    }

#endif

    char mountCmd[4096];
    memset(mountCmd, 0, 4096);
    strcat(mountCmd, "hdiutil mount ");
    strcat(mountCmd, opt.device);
    system(mountCmd);
    
    char mountGrepCmd[4096];
    memset(mountGrepCmd, 0, 4096);
    strcat(mountGrepCmd, "echo `mount | grep ");
    strcat(mountGrepCmd, opt.device);
    strcat(mountGrepCmd, " | sed 's/ on /$/' | tr '$' '\n' | head -n 2 | tail -n 1 | tr '(' '\n' | head -n 1`");
    char mountPoint[4096];
    memset(mountPoint, 0, 4096);
    FILE *mountCmdOutput = popen(mountGrepCmd, "r");
    fgets(mountPoint, 4096, mountCmdOutput);
    mountPoint[strlen(mountPoint)-1] = 0; // removes trailing newline
    printf("mountpoint is %s\n", mountPoint);
    
    mntpath = mountPoint;
    ldlinux_path = alloca(strlen(mntpath) + strlen(subdir) + 1);
    sprintf(ldlinux_path, "%s%s", mntpath, subdir);

    ldlinux_name = alloca(strlen(ldlinux_path) + 14);
    if (!ldlinux_name) {
	perror(program);
	err = 1;
	goto umount;
    }
    sprintf(ldlinux_name, "%sldlinux.sys", ldlinux_path);

    /* update ADV only ? */
    if (opt.update_only == -1) {
	if (opt.reset_adv || opt.set_once) {
	    modify_existing_adv(ldlinux_path);
	    //do_umount(mntpath, mnt_cookie);
	    sync();
	    //rmdir(mntpath);
	    exit(0);
	} else {
	    fprintf(stderr, "%s: please specify --install or --update for the future\n", argv[0]);
	    opt.update_only = 0;
	}
    }

    printf("checkpoint1\n");

    /* Read a pre-existing ADV, if already installed */
    if (opt.reset_adv)
	syslinux_reset_adv(syslinux_adv);
    else if (read_adv(ldlinux_path, "ldlinux.sys") < 0)
	syslinux_reset_adv(syslinux_adv);
    if (modify_adv() < 0)
	exit(1);
	
	printf("checkpoint1.5\n");

    if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) {
	uint32_t zero_attr = 0;
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr);
	printf("checkpoint1.55bad\n");
	close(fd);
    }
    
    printf("checkpoint1.6\n");

    unlink(ldlinux_name);
    printf(ldlinux_name);
    printf(" ldlinuxname\n");
    fd = open(ldlinux_name, O_WRONLY | O_CREAT | O_TRUNC, 0444);
    if (fd < 0) {
	perror(opt.device);
	err = 1;
	goto umount;
    }
    
    printf("checkpoint2\n");

    /* Write it the first time */
    if (xpwrite(fd, boot_image, boot_image_len, 0) != (int)boot_image_len ||
	xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
		boot_image_len) != 2 * ADV_SIZE) {
	fprintf(stderr, "%s: write failure on %s\n", program, ldlinux_name);
	exit(1);
    }

    fsync(fd);
    /*
     * Set the attributes
     */
    {
	uint32_t attr = 0x07;	/* Hidden+System+Readonly */
	//ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
    }
    
    printf("checkpoint3\n");

    /*
     * Create a block map.
     */
    
    ldlinux_sectors += 2; /* 2 ADV sectors */
    
    close(fd);
    sync();
    /*
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    if (sectmap(fd, sectors, ldlinux_sectors)) {
	perror("bmap");
	exit(1);
    }
    close(fd);
    sync();
    printf("checkpoint4\n");
    */
    
    /* Map the file (is there a better way to do this?) */
    //ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    struct libfat_filesystem *fs;
    libfat_sector_t s;
    libfat_sector_t *secp;
    //libfat_sector_t *sectors;
    uint32_t ldlinux_cluster;
    
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    //fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
    system(umountCommand);
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	perror("couldn't open device");
	exit(1);
    }
    fs = libfat_open(libfat_readfile, dev_fd);
    if (fs == NULL) printf("null fs struct\n");
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    
    printf("checkpoint4\n");
    
    secp = sectors;
    int nsectors;
    nsectors  = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);
    printf("checkpoint5\n");

umount:
    //do_umount(mntpath, mnt_cookie);
    sync();
    //rmdir(mntpath);

    if (err)
	exit(err);
	
	printf("checkpoint6\n");

    /*
     * Patch ldlinux.sys and the boot sector
     */
    i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode,
		       opt.raid_mode, subdir, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /*
     * Write the now-patched first sectors of ldlinux.sys
     */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, boot_image + i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }
    
    printf("checkpoint7\n");

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
    
    printf("checkpoint8\n");

    close(dev_fd);
    sync();
    system(mountCmd);

    /* Done! */

    return 0;
}
Exemplo n.º 6
0
int main(int argc, char *argv[])
{
    static unsigned char sectbuf[SECTOR_SIZE];
    int dev_fd;
    struct stat st;
    int status;
    const char *tmpdir;
    char *mtools_conf;
    int mtc_fd;
    FILE *mtc, *mtp;
    struct libfat_filesystem *fs;
    libfat_sector_t s, *secp;
    libfat_sector_t *sectors;
    int32_t ldlinux_cluster;
    int nsectors;
    const char *errmsg;
    int ldlinux_sectors, patch_sectors;
    int i;

    (void)argc;			/* Unused */

    mypid = getpid();
    program = argv[0];

    parse_options(argc, argv, MODE_SYSLINUX);

    if (!opt.device)
	usage(EX_USAGE, MODE_SYSLINUX);

    if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
	|| (opt.update_only > 0) || opt.menu_save) {
	fprintf(stderr,
		"At least one specified option not yet implemented"
		" for this installer.\n");
	exit(1);
    }

    /*
     * Temp directory of choice...
     */
    tmpdir = getenv("TMPDIR");
    if (!tmpdir) {
#ifdef P_tmpdir
	tmpdir = P_tmpdir;
#elif defined(_PATH_TMP)
	tmpdir = _PATH_TMP;
#else
	tmpdir = "/tmp";
#endif
    }

    /*
     * First make sure we can open the device at all, and that we have
     * read/write permission.
     */
    dev_fd = open(opt.device, O_RDWR);
    if (dev_fd < 0 || fstat(dev_fd, &st) < 0) {
	die_err(opt.device);
	exit(1);
    }

    if (!opt.force && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) {
	fprintf(stderr,
		"%s: not a block device or regular file (use -f to override)\n",
		opt.device);
	exit(1);
    }

    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /*
     * Check to see that what we got was indeed an MS-DOS boot sector/superblock
     */
    if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
	die(errmsg);
    }

    /*
     * Create an mtools configuration file
     */
    if (asprintf(&mtools_conf, "%s//syslinux-mtools-XXXXXX", tmpdir) < 0 ||
	!mtools_conf)
	die_err(tmpdir);

    mtc_fd = mkstemp(mtools_conf);
    if (mtc_fd < 0 || !(mtc = fdopen(mtc_fd, "w")))
	die_err(mtools_conf);

    fprintf(mtc,
	    /* These are needed for some flash memories */
	    "MTOOLS_SKIP_CHECK=1\n"
	    "MTOOLS_FAT_COMPATIBILITY=1\n"
	    "drive s:\n"
	    "  file=\"/proc/%lu/fd/%d\"\n"
	    "  offset=%llu\n",
	    (unsigned long)mypid,
	    dev_fd, (unsigned long long)opt.offset);

    if (ferror(mtc) || fclose(mtc))
	die_err(mtools_conf);

    /*
     * Run mtools to create the LDLINUX.SYS file
     */
    if (setenv("MTOOLSRC", mtools_conf, 1)) {
	perror(program);
	exit(1);
    }

    /*
     * Create a vacuous ADV in memory.  This should be smarter.
     */
    syslinux_reset_adv(syslinux_adv);

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.sys 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.sys", "w");
    if (!mtp ||
	fwrite((const void _force *)syslinux_ldlinux,
	       1, syslinux_ldlinux_len, mtp)
		!= syslinux_ldlinux_len ||
	fwrite((const void _force *)syslinux_adv,
	       1, 2 * ADV_SIZE, mtp)
		!= 2 * ADV_SIZE ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.sys");
    }

    /*
     * Now, use libfat to create a block map
     */
    ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE
		       + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
    sectors = calloc(ldlinux_sectors, sizeof *sectors);
    fs = libfat_open(libfat_xpread, dev_fd);
    ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
    secp = sectors;
    nsectors = 0;
    s = libfat_clustertosector(fs, ldlinux_cluster);
    while (s && nsectors < ldlinux_sectors) {
	*secp++ = s;
	nsectors++;
	s = libfat_nextsector(fs, s);
    }
    libfat_close(fs);

    /* Patch ldlinux.sys and the boot sector */
    i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode,
		       opt.directory, NULL);
    patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;

    /* Write the now-patched first sectors of ldlinux.sys */
    for (i = 0; i < patch_sectors; i++) {
	xpwrite(dev_fd, (const char _force *)syslinux_ldlinux
		+ i * SECTOR_SIZE, SECTOR_SIZE,
		opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT));
    }

    /* Move ldlinux.sys to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.sys");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.sys");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.sys\n",
		program);
    }

    /* This command may fail legitimately */
    status = system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null");
    (void)status;		/* Keep _FORTIFY_SOURCE happy */

    mtp = popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w");
    if (!mtp ||	fwrite((const char _force *)syslinux_ldlinuxc32,
		       1, syslinux_ldlinuxc32_len, mtp)
	!= syslinux_ldlinuxc32_len ||
	(status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) {
	die("failed to create ldlinux.c32");
    }

    /* Move ldlinux.c32 to the desired location */
    if (opt.directory) {
	status = move_file("ldlinux.c32");
    } else {
	status = system("mattrib +r +h +s s:/ldlinux.c32");
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
	fprintf(stderr,
		"%s: warning: failed to set system bit on ldlinux.c32\n",
		program);
    }

    /*
     * Cleanup
     */
    unlink(mtools_conf);

    /*
     * To finish up, write the boot sector
     */

    /* Read the superblock again since it might have changed while mounted */
    xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    /* Copy the syslinux code into the boot sector */
    syslinux_make_bootsect(sectbuf, VFAT);

    /* Write new boot sector */
    xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);

    close(dev_fd);
    sync();

    /* Done! */

    return 0;
}