Пример #1
0
static int sun_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
{
	struct sun_disklabel *sunlabel;
	struct sun_info *p;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_label(cxt, SUN));

	if (i >= cxt->label->nparts_max)
		return -EINVAL;

	sunlabel = self_disklabel(cxt);
	p = &sunlabel->vtoc.infos[i];

	switch (flag) {
	case SUN_FLAG_UNMNT:
		p->flags ^= cpu_to_be16(SUN_FLAG_UNMNT);
		fdisk_label_set_changed(cxt->label, 1);
		break;
	case SUN_FLAG_RONLY:
		p->flags ^= cpu_to_be16(SUN_FLAG_RONLY);
		fdisk_label_set_changed(cxt->label, 1);
		break;
	default:
		return 1;
	}

	return 0;
}
Пример #2
0
static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
{
	struct sgi_disklabel *sgilabel;
	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_disklabel(cxt, SGI));

	if (i >= cxt->label->nparts_max)
		return -EINVAL;

	sgilabel = self_disklabel(cxt);

	switch (flag) {
	case SGI_FLAG_BOOT:
		sgilabel->root_part_num =
			be16_to_cpu(sgilabel->root_part_num) == i ?
			0 : cpu_to_be16(i);
		fdisk_label_set_changed(cxt->label, 1);
		break;
	case SGI_FLAG_SWAP:
		sgilabel->swap_part_num =
			be16_to_cpu(sgilabel->swap_part_num) == i ?
			0 : cpu_to_be16(i);
		fdisk_label_set_changed(cxt->label, 1);
		break;
	default:
		return 1;
	}

	return 0;
}
Пример #3
0
static int sun_delete_partition(struct fdisk_context *cxt,
		size_t partnum)
{
	struct sun_disklabel *sunlabel;
	struct sun_partition *part;
	struct sun_info *info;
	unsigned int nsec;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_label(cxt, SUN));

	sunlabel = self_disklabel(cxt);
	part = &sunlabel->partitions[partnum];
	info = &sunlabel->vtoc.infos[partnum];

	if (partnum == 2 &&
	    be16_to_cpu(info->id) == SUN_TAG_WHOLEDISK &&
	    !part->start_cylinder &&
	    (nsec = be32_to_cpu(part->num_sectors))
	    == cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders)
		fdisk_info(cxt, _("If you want to maintain SunOS/Solaris compatibility, "
			 "consider leaving this "
			 "partition as Whole disk (5), starting at 0, with %u "
			 "sectors"), nsec);
	info->id = cpu_to_be16(SUN_TAG_UNASSIGNED);
	part->num_sectors = 0;
	cxt->label->nparts_cur = count_used_partitions(cxt);
	fdisk_label_set_changed(cxt->label, 1);
	return 0;
}
Пример #4
0
static int sgi_set_partition(struct fdisk_context *cxt, size_t i,
			     unsigned int start, unsigned int length, int sys)
{
	struct sgi_disklabel *sgilabel;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_disklabel(cxt, SGI));

	sgilabel = self_disklabel(cxt);
	sgilabel->partitions[i].type = cpu_to_be32(sys);
	sgilabel->partitions[i].num_blocks = cpu_to_be32(length);
	sgilabel->partitions[i].first_block = cpu_to_be32(start);

	fdisk_label_set_changed(cxt->label, 1);

	if (sgi_gaps(cxt) < 0)	/* rebuild freelist */
		fdisk_warnx(cxt, _("Partition overlap on the disk."));
	if (length) {
		struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, sys);
		fdisk_info_new_partition(cxt, i + 1, start, start + length, t);
	}

	return 0;
}
Пример #5
0
static int sgi_set_partition(struct fdisk_context *cxt,
		size_t i,
		struct fdisk_partition *pa)
{
	struct sgi_disklabel *sgilabel;

	if (i >= cxt->label->nparts_max)
		return -EINVAL;

	sgilabel = self_disklabel(cxt);

	if (pa->type) {
		struct fdisk_parttype *t = pa->type;

		if (sgi_get_num_sectors(cxt, i) == 0)	/* caught already before, ... */ {
			fdisk_warnx(cxt, _("Sorry, only for non-empty partitions you can change the tag."));
			return -EINVAL;
		}

		if ((i == 10 && t->code != SGI_TYPE_ENTIRE_DISK)
		    || (i == 8 && t->code != 0))
			fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), "
					  "and partition 11 as entire volume (6), "
					  "as IRIX expects it."));

		if (cxt->script == NULL
		    && ((t->code != SGI_TYPE_ENTIRE_DISK) && (t->code != SGI_TYPE_VOLHDR))
		    && (sgi_get_start_sector(cxt, i) < 1)) {
			int yes = 0;
			fdisk_ask_yesno(cxt,
				_("It is highly recommended that the partition at offset 0 "
				  "is of type \"SGI volhdr\", the IRIX system will rely on it to "
				  "retrieve from its directory standalone tools like sash and fx. "
				  "Only the \"SGI volume\" entire disk section may violate this. "
				  "Are you sure about tagging this partition differently?"), &yes);
			if (!yes)
				return 1;
		}

		sgilabel->partitions[i].type = cpu_to_be32(t->code);
	}

	if (fdisk_partition_has_start(pa))
		sgilabel->partitions[i].first_block = cpu_to_be32(pa->start);
	if (fdisk_partition_has_size(pa))
		sgilabel->partitions[i].num_blocks = cpu_to_be32(pa->size);

	fdisk_label_set_changed(cxt->label, 1);
	return 0;
}
Пример #6
0
static void set_sun_partition(struct fdisk_context *cxt, size_t i,
		uint32_t start,uint32_t stop, uint16_t sysid)
{
	struct sun_disklabel *sunlabel = self_disklabel(cxt);
	struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, sysid);

	sunlabel->vtoc.infos[i].id = cpu_to_be16(sysid);
	sunlabel->vtoc.infos[i].flags = cpu_to_be16(0);
	sunlabel->partitions[i].start_cylinder =
		cpu_to_be32(start / (cxt->geom.heads * cxt->geom.sectors));
	sunlabel->partitions[i].num_sectors = cpu_to_be32(stop - start);
	fdisk_label_set_changed(cxt->label, 1);

	fdisk_info_new_partition(cxt, i + 1, start, stop, t);
}
Пример #7
0
static int bsd_delete_part(
    struct fdisk_context *cxt,
    size_t partnum)
{
    struct bsd_disklabel *d = self_disklabel(cxt);

    d->d_partitions[partnum].p_size   = 0;
    d->d_partitions[partnum].p_offset = 0;
    d->d_partitions[partnum].p_fstype = BSD_FS_UNUSED;

    if (d->d_npartitions == partnum + 1)
        while (!d->d_partitions[d->d_npartitions - 1].p_size)
            d->d_npartitions--;

    cxt->label->nparts_cur = d->d_npartitions;
    fdisk_label_set_changed(cxt->label, 1);
    return 0;
}
Пример #8
0
static int bsd_set_parttype(
    struct fdisk_context *cxt,
    size_t partnum,
    struct fdisk_parttype *t)
{
    struct bsd_partition *p;
    struct bsd_disklabel *d = self_disklabel(cxt);

    if (partnum >= d->d_npartitions || !t || t->type > UINT8_MAX)
        return -EINVAL;

    p = &d->d_partitions[partnum];
    if (t->type == p->p_fstype)
        return 0;

    p->p_fstype = t->type;
    fdisk_label_set_changed(cxt->label, 1);
    return 0;
}
Пример #9
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;
}
Пример #10
0
static int sun_set_partition(
		struct fdisk_context *cxt,
		size_t i,
		struct fdisk_partition *pa)
{
	struct sun_disklabel *sunlabel;
	struct sun_partition *part;
	struct sun_info *info;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_label(cxt, SUN));

	sunlabel = self_disklabel(cxt);

	if (i >= cxt->label->nparts_max)
		return -EINVAL;

	if (pa->type) {
		struct fdisk_parttype *t = pa->type;

		if (t->code > UINT16_MAX)
			return -EINVAL;

		if (i == 2 && t->code != SUN_TAG_WHOLEDISK)
			fdisk_info(cxt, _("Consider leaving partition 3 as Whole disk (5),\n"
			         "as SunOS/Solaris expects it and even Linux likes it.\n"));

		part = &sunlabel->partitions[i];
		info = &sunlabel->vtoc.infos[i];

		if (cxt->script == NULL &&
		    t->code == SUN_TAG_LINUX_SWAP && !part->start_cylinder) {
			int yes, rc;

			rc = fdisk_ask_yesno(cxt,
			      _("It is highly recommended that the partition at offset 0\n"
			      "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
			      "there may destroy your partition table and bootblock.\n"
			      "Are you sure you want to tag the partition as Linux swap?"), &yes);
			if (rc)
				return rc;
			if (!yes)
				return 1;
		}

		switch (t->code) {
		case SUN_TAG_SWAP:
		case SUN_TAG_LINUX_SWAP:
			/* swaps are not mountable by default */
			info->flags |= cpu_to_be16(SUN_FLAG_UNMNT);
			break;
		default:
			/* assume other types are mountable;
			   user can change it anyway */
			info->flags &= ~cpu_to_be16(SUN_FLAG_UNMNT);
			break;
		}
		info->id = cpu_to_be16(t->code);
	}

	if (fdisk_partition_has_start(pa))
		sunlabel->partitions[i].start_cylinder =
			cpu_to_be32(pa->start / (cxt->geom.heads * cxt->geom.sectors));
	if (fdisk_partition_has_size(pa))
		sunlabel->partitions[i].num_sectors = cpu_to_be32(pa->size);

	fdisk_label_set_changed(cxt->label, 1);
	return 0;
}
Пример #11
0
static int sun_create_disklabel(struct fdisk_context *cxt)
{
	unsigned int ndiv;
	struct fdisk_sun_label *sun;		/* libfdisk sun handler */
	struct sun_disklabel *sunlabel;	/* on disk data */
	int rc = 0;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_label(cxt, SUN));

	/* map first sector to header */
	rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
	if (rc)
		return rc;

	sun = (struct fdisk_sun_label *) cxt->label;
	sun->header = (struct sun_disklabel *) cxt->firstsector;

	sunlabel = sun->header;

	cxt->label->nparts_max = SUN_MAXPARTITIONS;

	sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC);
	sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
	sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
	sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);

#ifdef HDIO_GETGEO
	if (cxt->geom.heads && cxt->geom.sectors) {
		fdisk_sector_t llsectors;

		if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
			int sec_fac = cxt->sector_size / 512;
			fdisk_sector_t llcyls;

			llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
			cxt->geom.cylinders = llcyls;
			if (cxt->geom.cylinders != llcyls)
				cxt->geom.cylinders = ~0;
		} else {
			fdisk_warnx(cxt,
				_("BLKGETSIZE ioctl failed on %s. "
				  "Using geometry cylinder value of %llu. "
				  "This value may be truncated for devices "
				  "> 33.8 GB."),
				cxt->dev_path, cxt->geom.cylinders);
		}
	} else
#endif
		ask_geom(cxt);

	sunlabel->acyl   = cpu_to_be16(0);
	sunlabel->pcyl   = cpu_to_be16(cxt->geom.cylinders);
	sunlabel->rpm    = cpu_to_be16(5400);
	sunlabel->intrlv = cpu_to_be16(1);
	sunlabel->apc    = cpu_to_be16(0);

	sunlabel->nhead  = cpu_to_be16(cxt->geom.heads);
	sunlabel->nsect  = cpu_to_be16(cxt->geom.sectors);
	sunlabel->ncyl   = cpu_to_be16(cxt->geom.cylinders);

	snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id),
		 "Linux cyl %ju alt %u hd %u sec %ju",
		 (uintmax_t) cxt->geom.cylinders,
		 be16_to_cpu(sunlabel->acyl),
		 cxt->geom.heads,
		 (uintmax_t) cxt->geom.sectors);

	if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) {
	        ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */
	} else
	        ndiv = cxt->geom.cylinders * 2 / 3;

	/* create the default layout only if no-script defined */
	if (!cxt->script) {
		set_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors,
			  SUN_TAG_LINUX_NATIVE);
		set_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors,
			  cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
			  SUN_TAG_LINUX_SWAP);
		sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT);

		set_partition(cxt, 2, 0,
			  cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
			  SUN_TAG_WHOLEDISK);
	}

	{
		unsigned short *ush = (unsigned short *)sunlabel;
		unsigned short csum = 0;
		while(ush < (unsigned short *)(&sunlabel->csum))
			csum ^= *ush++;
		sunlabel->csum = csum;
	}

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

	fdisk_info(cxt, _("Created a new Sun disklabel."));
	return 0;
}
Пример #12
0
static int sun_probe_label(struct fdisk_context *cxt)
{
	struct fdisk_sun_label *sun;
	struct sun_disklabel *sunlabel;
	unsigned short *ush;
	int csum;
	int need_fixing = 0;

	assert(cxt);
	assert(cxt->label);
	assert(fdisk_is_label(cxt, SUN));

	/* map first sector to header */
	sun = (struct fdisk_sun_label *) cxt->label;
	sun->header = (struct sun_disklabel *) cxt->firstsector;
	sunlabel = sun->header;

	if (be16_to_cpu(sunlabel->magic) != SUN_LABEL_MAGIC) {
		sun->header = NULL;
		return 0;		/* failed */
	}

	ush = ((unsigned short *) (sunlabel + 1)) - 1;
	for (csum = 0; ush >= (unsigned short *)sunlabel;)
		csum ^= *ush--;

	if (csum) {
		fdisk_warnx(cxt, _("Detected sun disklabel with wrong checksum. "
			      "Probably you'll have to set all the values, "
			      "e.g. heads, sectors, cylinders and partitions "
			      "or force a fresh label (s command in main menu)"));
		return 1;
	}

	cxt->label->nparts_max = SUN_MAXPARTITIONS;
	cxt->geom.heads = be16_to_cpu(sunlabel->nhead);
	cxt->geom.cylinders = be16_to_cpu(sunlabel->ncyl);
	cxt->geom.sectors = be16_to_cpu(sunlabel->nsect);

	if (be32_to_cpu(sunlabel->vtoc.version) != SUN_VTOC_VERSION) {
		fdisk_warnx(cxt, _("Detected sun disklabel with wrong version [%d]."),
			be32_to_cpu(sunlabel->vtoc.version));
		need_fixing = 1;
	}
	if (be32_to_cpu(sunlabel->vtoc.sanity) != SUN_VTOC_SANITY) {
		fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
			be32_to_cpu(sunlabel->vtoc.sanity));
		need_fixing = 1;
	}
	if (be16_to_cpu(sunlabel->vtoc.nparts) != SUN_MAXPARTITIONS) {
		fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
			be16_to_cpu(sunlabel->vtoc.nparts));
		need_fixing = 1;
	}
	if (need_fixing) {
		fdisk_warnx(cxt, _("Warning: Wrong values need to be fixed up and "
			           "will be corrected by w(rite)"));

		sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
		sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
		sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);

		ush = (unsigned short *)sunlabel;
		csum = 0;
		while(ush < (unsigned short *)(&sunlabel->csum))
			csum ^= *ush++;
		sunlabel->csum = csum;

		fdisk_label_set_changed(cxt->label, 1);
	}

	cxt->label->nparts_cur = count_used_partitions(cxt);

	return 1;
}
Пример #13
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;
}
Пример #14
0
static int sun_create_disklabel(struct fdisk_context *cxt)
{
    struct hd_geometry geometry;
    sector_t llsectors, llcyls;
    unsigned int ndiv, sec_fac;
    int res;

    struct fdisk_sun_label *sun;		/* libfdisk sun handler */
    struct sun_disklabel *sunlabel;	/* on disk data */

    assert(cxt);
    assert(cxt->label);
    assert(fdisk_is_disklabel(cxt, SUN));

    /* map first sector to header */
    fdisk_zeroize_firstsector(cxt);
    sun = (struct fdisk_sun_label *) cxt->label;
    sun->header = (struct sun_disklabel *) cxt->firstsector;

    sunlabel = sun->header;

    cxt->label->nparts_max = SUN_MAXPARTITIONS;

    sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC);
    sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION);
    sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY);
    sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS);

    res = blkdev_get_sectors(cxt->dev_fd, &llsectors);
    sec_fac = cxt->sector_size / 512;

#ifdef HDIO_GETGEO
    if (!ioctl(cxt->dev_fd, HDIO_GETGEO, &geometry)) {
        cxt->geom.heads = geometry.heads;
        cxt->geom.sectors = geometry.sectors;
        if (res == 0) {
            llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac);
            cxt->geom.cylinders = llcyls;
            if (cxt->geom.cylinders != llcyls)
                cxt->geom.cylinders = ~0;
        } else {
            cxt->geom.cylinders = geometry.cylinders;
            fdisk_warnx(cxt,
                        _("BLKGETSIZE ioctl failed on %s. "
                          "Using geometry cylinder value of %llu. "
                          "This value may be truncated for devices "
                          "> 33.8 GB."),
                        cxt->dev_path, cxt->geom.cylinders);
        }
    } else
#endif
        ask_geom(cxt);

    sunlabel->acyl   = cpu_to_be16(0);
    sunlabel->pcyl   = cpu_to_be16(cxt->geom.cylinders);
    sunlabel->rpm    = cpu_to_be16(5400);
    sunlabel->intrlv = cpu_to_be16(1);
    sunlabel->apc    = cpu_to_be16(0);

    sunlabel->nhead  = cpu_to_be16(cxt->geom.heads);
    sunlabel->nsect  = cpu_to_be16(cxt->geom.sectors);
    sunlabel->ncyl   = cpu_to_be16(cxt->geom.cylinders);

    snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id),
             "Linux cyl %llu alt %u hd %u sec %llu",
             cxt->geom.cylinders, be16_to_cpu(sunlabel->acyl),
             cxt->geom.heads, cxt->geom.sectors);

    if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) {
        ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */
    } else
        ndiv = cxt->geom.cylinders * 2 / 3;

    set_sun_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors,
                      SUN_TAG_LINUX_NATIVE);
    set_sun_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors,
                      cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
                      SUN_TAG_LINUX_SWAP);
    sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT);

    set_sun_partition(cxt, 2, 0,
                      cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
                      SUN_TAG_WHOLEDISK);

    {
        unsigned short *ush = (unsigned short *)sunlabel;
        unsigned short csum = 0;
        while(ush < (unsigned short *)(&sunlabel->csum))
            csum ^= *ush++;
        sunlabel->csum = csum;
    }

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

    fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
                _("Created a new Sun disklabel."));
    return 0;
}