Example #1
0
static int bsd_write_disklabel(struct fdisk_context *cxt)
{
    off_t offset = 0;
    struct fdisk_bsd_label *l = self_label(cxt);
    struct bsd_disklabel *d = self_disklabel(cxt);


    if (l->dos_part)
        offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;

    d->d_checksum = 0;
    d->d_checksum = bsd_dkcksum(d);

    /* Update label within boot block. */
    memmove(&l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
                          + BSD_LABELOFFSET], d, sizeof(*d));

#if defined (__alpha__) && BSD_LABELSECTOR == 0
    /* Write the checksum to the end of the first sector. */
    alpha_bootblock_checksum(l->bsdbuffer);
#endif
    if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1) {
        fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
        return -errno;
    }
    if (write_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer))) {
        fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
        return -errno;
    }
    sync_disks(cxt);

    fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
                _("Disklabel written to %s."), cxt->dev_path);
    return 0;
}
Example #2
0
/*
 * Read a bsd_disklabel from sector 0 or from the starting sector of p.
 * If it has the right magic, return 0.
 */
static int bsd_readlabel(struct fdisk_context *cxt)
{
    struct fdisk_bsd_label *l;
    struct bsd_disklabel *d;
    int t;
    off_t offset = 0;

    l = self_label(cxt);
    d = self_disklabel(cxt);

    if (l->dos_part)
        /* BSD is nested within DOS partition, get the begin of the
         * partition. Note that DOS uses native sector size. */
        offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;

    if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1)
        return -1;
    if (read_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer)) < 0)
        return errno ? -errno : -1;

    /* The offset to begin of the disk label. Note that BSD uses
     * 512-byte (default) sectors. */
    memmove(d, &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
                             + BSD_LABELOFFSET], sizeof(*d));

    if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC) {
        DBG(LABEL, ul_debug("not found magic"));
        return -1;
    }

    for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
        d->d_partitions[t].p_size   = 0;
        d->d_partitions[t].p_offset = 0;
        d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
    }

    if (d->d_npartitions > BSD_MAXPARTITIONS)
        fdisk_warnx(cxt, ("Too many partitions (%d, maximum is %d)."),
                    d->d_npartitions, BSD_MAXPARTITIONS);

    /* let's follow in-PT geometry */
    cxt->geom.sectors = d->d_nsectors;
    cxt->geom.heads = d->d_ntracks;
    cxt->geom.cylinders = d->d_ncylinders;

    cxt->label->nparts_cur = d->d_npartitions;
    cxt->label->nparts_max = BSD_MAXPARTITIONS;
    DBG(LABEL, ul_debug("read BSD label"));
    return 0;
}
Example #3
0
/*
 * link partition from parent (DOS) to nested BSD partition table
 */
int fdisk_bsd_link_partition(struct fdisk_context *cxt)
{
    size_t k, i;
    int rc;
    struct dos_partition *p;
    struct bsd_disklabel *d = self_disklabel(cxt);

    if (!cxt->parent || !fdisk_is_disklabel(cxt->parent, DOS)) {
        fdisk_warnx(cxt, _("BSD label is not nested within a DOS partition."));
        return -EINVAL;
    }

    /* ask for DOS partition */
    rc = fdisk_ask_partnum(cxt->parent, &k, FALSE);
    if (rc)
        return rc;
    /* ask for BSD partition */
    rc = fdisk_ask_partnum(cxt, &i, TRUE);
    if (rc)
        return rc;

    if (i >= BSD_MAXPARTITIONS)
        return -EINVAL;

    p = fdisk_dos_get_partition(cxt->parent, k);

    d->d_partitions[i].p_size   = dos_partition_get_size(p);
    d->d_partitions[i].p_offset = dos_partition_get_start(p);
    d->d_partitions[i].p_fstype = bsd_translate_fstype(p->sys_ind);

    if (i >= d->d_npartitions)
        d->d_npartitions = i + 1;

    cxt->label->nparts_cur = d->d_npartitions;
    fdisk_label_set_changed(cxt->label, 1);

    fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
                _("BSD partition '%c' linked to DOS partition %zu."),
                'a' + (int) i, k + 1);
    return 0;
}
Example #4
0
/*
 * look for DOS partition usable for nested BSD partition table
 */
static int bsd_assign_dos_partition(struct fdisk_context *cxt)
{
    struct fdisk_bsd_label *l = self_label(cxt);
    size_t i;

    for (i = 0; i < 4; i++) {
        sector_t ss;

        l->dos_part = fdisk_dos_get_partition(cxt->parent, i);

        if (!l->dos_part || !is_bsd_partition_type(l->dos_part->sys_ind))
            continue;

        ss = dos_partition_get_start(l->dos_part);
        if (!ss) {
            fdisk_warnx(cxt, _("Partition %zd: has invalid starting "
                               "sector 0."), i + 1);
            return -1;
        }

        if (cxt->parent->dev_path) {
            free(cxt->dev_path);
            cxt->dev_path = fdisk_partname(
                                cxt->parent->dev_path, i + 1);
        }

        DBG(LABEL, ul_debug("partition %zu assigned to BSD", i + 1));
        return 0;
    }

    fdisk_warnx(cxt, _("There is no *BSD partition on %s."),
                cxt->parent->dev_path);
    free(cxt->dev_path);
    cxt->dev_path = NULL;
    l->dos_part = NULL;
    return 1;
}
Example #5
0
static int bsd_initlabel (struct fdisk_context *cxt)
{
    struct fdisk_bsd_label *l = self_label(cxt);
    struct bsd_disklabel *d = self_disklabel(cxt);
    struct bsd_partition *pp;

    memset (d, 0, sizeof (struct bsd_disklabel));

    d -> d_magic = BSD_DISKMAGIC;

    if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0)
        d -> d_type = BSD_DTYPE_SCSI;
    else
        d -> d_type = BSD_DTYPE_ST506;

#if !defined (__alpha__)
    d -> d_flags = BSD_D_DOSPART;
#else
    d -> d_flags = 0;
#endif
    d -> d_secsize = DEFAULT_SECTOR_SIZE;		/* bytes/sector  */
    d -> d_nsectors = cxt->geom.sectors;		/* sectors/track */
    d -> d_ntracks = cxt->geom.heads;		/* tracks/cylinder (heads) */
    d -> d_ncylinders = cxt->geom.cylinders;
    d -> d_secpercyl  = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */
    if (d -> d_secpercyl == 0)
        d -> d_secpercyl = 1;		/* avoid segfaults */
    d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;

    d -> d_rpm = 3600;
    d -> d_interleave = 1;
    d -> d_trackskew = 0;
    d -> d_cylskew = 0;
    d -> d_headswitch = 0;
    d -> d_trkseek = 0;

    d -> d_magic2 = BSD_DISKMAGIC;
    d -> d_bbsize = BSD_BBSIZE;
    d -> d_sbsize = BSD_SBSIZE;

    if (l->dos_part) {
        d->d_npartitions = 4;

        pp = &d->d_partitions[2];	/* Partition C should be the NetBSD partition */
        pp->p_offset = dos_partition_get_start(l->dos_part);
        pp->p_size   = dos_partition_get_size(l->dos_part);
        pp->p_fstype = BSD_FS_UNUSED;

        pp = &d -> d_partitions[3];	/* Partition D should be the whole disk */
        pp->p_offset = 0;
        pp->p_size   = d->d_secperunit;
        pp->p_fstype = BSD_FS_UNUSED;
    } else {
        d->d_npartitions = 3;

        pp = &d->d_partitions[2];	/* Partition C should be the whole disk */
        pp->p_offset = 0;
        pp->p_size   = d->d_secperunit;
        pp->p_fstype = BSD_FS_UNUSED;
    }

    return 0;
}
Example #6
0
int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt)
{
    struct bsd_disklabel dl, *d = self_disklabel(cxt);
    struct fdisk_bsd_label *l = self_label(cxt);
    char *name = d->d_type == BSD_DTYPE_SCSI ? "sd" : "wd";
    char buf[BUFSIZ];
    char *res, *dp, *p;
    int rc;
    sector_t sector;

    snprintf(buf, sizeof(buf),
             _("Bootstrap: %1$sboot -> boot%1$s (default %1$s)"),
             name);
    rc = fdisk_ask_string(cxt, buf, &res);
    if (rc)
        goto done;
    if (res && *res)
        name = res;

    snprintf(buf, sizeof(buf), "%s/%sboot", BSD_LINUX_BOOTDIR, name);
    rc = bsd_get_bootstrap(cxt, buf, l->bsdbuffer,	(int) d->d_secsize);
    if (rc)
        goto done;

    /* We need a backup of the disklabel (might have changed). */
    dp = &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE];
    memmove(&dl, dp, sizeof(struct bsd_disklabel));

    /* The disklabel will be overwritten by 0's from bootxx anyway */
    memset(dp, 0, sizeof(struct bsd_disklabel));

    snprintf(buf, sizeof(buf), "%s/boot%s", BSD_LINUX_BOOTDIR, name);
    rc = bsd_get_bootstrap(cxt, buf,
                           &l->bsdbuffer[d->d_secsize],
                           (int) d->d_bbsize - d->d_secsize);
    if (rc)
        goto done;

    /* check end of the bootstrap */
    for (p = dp; p < dp + sizeof(struct bsd_disklabel); p++) {
        if (!*p)
            continue;
        fdisk_warnx(cxt, _("Bootstrap overlaps with disklabel!"));
        return -EINVAL;
    }

    /* move disklabel back */
    memmove(dp, &dl, sizeof(struct bsd_disklabel));

    sector = 0;
    if (l->dos_part)
        sector = dos_partition_get_start(l->dos_part);
#if defined (__alpha__)
    alpha_bootblock_checksum(l->bsdbuffer);
#endif
    if (lseek(cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1) {
        fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
        rc = -errno;
        goto done;
    }
    if (write_all(cxt->dev_fd, l->bsdbuffer, BSD_BBSIZE)) {
        fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
        rc = -errno;
        goto done;
    }

    fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
                _("Bootstrap installed on %s."), cxt->dev_path);
    sync_disks(cxt);

    rc = 0;
done:
    free(res);
    return rc;
}
Example #7
0
static int bsd_add_partition(struct fdisk_context *cxt,
                             struct fdisk_partition *pa)
{
    struct fdisk_bsd_label *l = self_label(cxt);
    struct bsd_disklabel *d = self_disklabel(cxt);
    size_t i;
    unsigned int begin = 0, end;
    int rc = 0;

    rc = fdisk_partition_next_partno(pa, cxt, &i);
    if (rc)
        return rc;
    if (i >= BSD_MAXPARTITIONS)
        return -ERANGE;
    if (l->dos_part) {
        begin = dos_partition_get_start(l->dos_part);
        end = begin + dos_partition_get_size(l->dos_part) - 1;
    } else
        end = d->d_secperunit - 1;

    /*
     * First sector
     */
    if (pa && pa->start_follow_default)
        ;
    else if (pa && pa->start) {
        if (pa->start < begin || pa->start > end)
            return -ERANGE;
        begin = pa->start;
    } else {
        struct fdisk_ask *ask = fdisk_new_ask();

        if (!ask)
            return -ENOMEM;
        fdisk_ask_set_query(ask,
                            fdisk_context_use_cylinders(cxt) ?
                            _("First cylinder") : _("First sector"));
        fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
        fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
        fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin));
        fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));

        rc = fdisk_do_ask(cxt, ask);
        begin = fdisk_ask_number_get_result(ask);
        fdisk_free_ask(ask);
        if (rc)
            return rc;
        if (fdisk_context_use_cylinders(cxt))
            begin = (begin - 1) * d->d_secpercyl;
    }

    /*
     * Last sector
     */
    if (pa && pa->end_follow_default)
        ;
    else if (pa && pa->size) {
        if (begin + pa->size > end)
            return -ERANGE;
        end = begin + pa->size;
    } else {
        /* ask user by dialog */
        struct fdisk_ask *ask = fdisk_new_ask();

        if (!ask)
            return -ENOMEM;
        fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);

        if (fdisk_context_use_cylinders(cxt)) {
            fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}"));
            fdisk_ask_number_set_unit(ask,
                                      cxt->sector_size *
                                      fdisk_context_get_units_per_sector(cxt));
        } else {
            fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
            fdisk_ask_number_set_unit(ask,cxt->sector_size);
        }

        fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
        fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end));
        fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));
        fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin));

        rc = fdisk_do_ask(cxt, ask);
        end = fdisk_ask_number_get_result(ask);
        fdisk_free_ask(ask);
        if (rc)
            return rc;
        if (fdisk_context_use_cylinders(cxt))
            end = end * d->d_secpercyl - 1;
    }

    d->d_partitions[i].p_size   = end - begin + 1;
    d->d_partitions[i].p_offset = begin;
    d->d_partitions[i].p_fstype = BSD_FS_UNUSED;

    if (i >= d->d_npartitions)
        d->d_npartitions = i + 1;
    cxt->label->nparts_cur = d->d_npartitions;

    if (pa && pa->type)
        bsd_set_parttype(cxt, i, pa->type);

    fdisk_label_set_changed(cxt->label, 1);
    return 0;
}
Example #8
0
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
		uint32_t ex_start, uint32_t ex_size, int ssf)
{
	blkid_partlist ls = blkid_probe_get_partlist(pr);
	uint32_t cur_start = ex_start, cur_size = ex_size;
	unsigned char *data;
	int ct_nodata = 0;	/* count ext.partitions without data partitions */
	int i;

	DBG(LOWPROBE, ul_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf));
	if (ex_start == 0) {
		DBG(LOWPROBE, ul_debug("Bad offset in primary extended partition -- ignore"));
		return 0;
	}

	while (1) {
		struct dos_partition *p, *p0;
		uint32_t start, size;

		if (++ct_nodata > 100)
			return BLKID_PROBE_OK;
		data = blkid_probe_get_sector(pr, cur_start);
		if (!data) {
			if (errno)
				return -errno;
			goto leave;	/* malformed partition? */
		}

		if (!mbr_is_valid_magic(data))
			goto leave;

		p0 = mbr_get_partition(data, 0);

		/* Usually, the first entry is the real data partition,
		 * the 2nd entry is the next extended partition, or empty,
		 * and the 3rd and 4th entries are unused.
		 * However, DRDOS sometimes has the extended partition as
		 * the first entry (when the data partition is empty),
		 * and OS/2 seems to use all four entries.
		 * -- Linux kernel fs/partitions/dos.c
		 *
		 * See also http://en.wikipedia.org/wiki/Extended_boot_record
		 */

		/* Parse data partition */
		for (p = p0, i = 0; i < 4; i++, p++) {
			uint32_t abs_start;
			blkid_partition par;

			/* the start is relative to the parental ext.partition */
			start = dos_partition_get_start(p) * ssf;
			size = dos_partition_get_size(p) * ssf;
			abs_start = cur_start + start;	/* absolute start */

			if (!size || is_extended(p))
				continue;
			if (i >= 2) {
				/* extra checks to detect real data on
				 * 3rd and 4th entries */
				if (start + size > cur_size)
					continue;
				if (abs_start < ex_start)
					continue;
				if (abs_start + size > ex_start + ex_size)
					continue;
			}

			/* Avoid recursive non-empty links, see ct_nodata counter */
			if (blkid_partlist_get_partition_by_start(ls, abs_start)) {
				DBG(LOWPROBE, ul_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore",
							i + 1, abs_start));
				continue;
			}

			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
			if (!par)
				return -ENOMEM;

			blkid_partition_set_type(par, p->sys_ind);
			blkid_partition_set_flags(par, p->boot_ind);
			blkid_partition_gen_uuid(par);
			ct_nodata = 0;
		}
		/* The first nested ext.partition should be a link to the next
		 * logical partition. Everything other (recursive ext.partitions)
		 * is junk.
		 */
		for (p = p0, i = 0; i < 4; i++, p++) {
			start = dos_partition_get_start(p) * ssf;
			size = dos_partition_get_size(p) * ssf;

			if (size && is_extended(p)) {
				if (start == 0)
					DBG(LOWPROBE, ul_debug("#%d: EBR link offset is zero -- ignore", i + 1));
				else
					break;
			}
		}
		if (i == 4)
			goto leave;

		cur_start = ex_start + start;
		cur_size = size;
	}
leave:
	return BLKID_PROBE_OK;
}