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; }
/* * 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; }
/* * 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; }
/* * 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; }
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; }
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; }
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; }
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; }