static gpt_type_t netbsd_fstype_to_gpt_type(gpt_t gpt, u_int i, u_int fstype) { switch (fstype) { case FS_UNUSED: return GPT_TYPE_INVALID; case FS_HFS: return GPT_TYPE_APPLE_HFS; case FS_EX2FS: return GPT_TYPE_LINUX_DATA; case FS_SWAP: return GPT_TYPE_NETBSD_SWAP; case FS_BSDFFS: return GPT_TYPE_NETBSD_FFS; case FS_BSDLFS: return GPT_TYPE_NETBSD_LFS; case FS_RAID: return GPT_TYPE_NETBSD_RAIDFRAME; case FS_CCD: return GPT_TYPE_NETBSD_CCD; case FS_CGD: return GPT_TYPE_NETBSD_CGD; default: gpt_warnx(gpt, "Partition %u unknown type %s, " "using \"Microsoft Basic Data\"", i, fstypename(fstype)); return GPT_TYPE_MS_BASIC_DATA; } }
static struct gpt_ent * migrate_disklabel(gpt_t gpt, off_t start, struct gpt_ent *ent, gpt_type_t (*convert)(gpt_t, u_int, u_int)) { char *buf; struct disklabel *dl; off_t ofs, rawofs; unsigned int i; gpt_type_t type; buf = gpt_read(gpt, start + LABELSECTOR, 1); if (buf == NULL) { gpt_warn(gpt, "Error reading label"); return NULL; } dl = (void*)(buf + LABELOFFSET); if (le32toh(dl->d_magic) != DISKMAGIC || le32toh(dl->d_magic2) != DISKMAGIC) { gpt_warnx(gpt, "MBR partition without disklabel"); free(buf); return ent; } rawofs = le32toh(dl->d_partitions[RAW_PART].p_offset) * le32toh(dl->d_secsize); for (i = 0; i < le16toh(dl->d_npartitions); i++) { if (dl->d_partitions[i].p_fstype == FS_UNUSED) continue; ofs = le32toh(dl->d_partitions[i].p_offset) * le32toh(dl->d_secsize); if (ofs < rawofs) rawofs = 0; } if (gpt->verbose > 1) gpt_msg(gpt, "rawofs=%ju", (uintmax_t)rawofs); rawofs /= gpt->secsz; for (i = 0; i < le16toh(dl->d_npartitions); i++) { if (gpt->verbose > 1) gpt_msg(gpt, "Disklabel partition %u type %s", i, fstypename(dl->d_partitions[i].p_fstype)); type = (*convert)(gpt, i, dl->d_partitions[i].p_fstype); if (type == GPT_TYPE_INVALID) continue; gpt_uuid_create(type, ent->ent_type, ent->ent_name, sizeof(ent->ent_name)); ofs = (le32toh(dl->d_partitions[i].p_offset) * le32toh(dl->d_secsize)) / gpt->secsz; ofs = (ofs > 0) ? ofs - rawofs : 0; ent->ent_lba_start = htole64((uint64_t)ofs); ent->ent_lba_end = htole64((uint64_t)(ofs + (off_t)le32toh((uint64_t)dl->d_partitions[i].p_size) - 1LL)); ent++; } free(buf); return ent; }
/* * Report a read error, logging how many bytes were trying to be read, which * sector they were being read from, and try to also find out what that sector * is used for. */ void logreaderror(struct disk *dp, int nbytes) { quad_t secno; off_t saved_offset; char newdev[512]; #ifdef DIOCGDINFO int fd, slice, part; struct dos_partition *dos; struct disklabel label; char buf[512]; #else /* DIOCGDINFO */ static size_t geomSize = 0; static char * geomConf = NULL; char * cp; static size_t partLen = 31; static char *part = NULL; quad_t relsec = -1; char *typefld = NULL; #endif /* DIOCGDINFO */ saved_offset = dseek(dp, 0, SEEK_CUR); secno = (quad_t)saved_offset / dp->secsize; dp->errors++; syslog(LOG_NOTICE, "error reading %d bytes from sector " QD " on %s", nbytes, secno, dp->device); #ifdef DIOCGDINFO /* * First, find out which slice it's in. To do this, we seek to the * start of the disk, read the first sector, and go through the DOS * slice table. */ if (dseek(dp, 0, SEEK_SET) == -1) { syslog(LOG_NOTICE, "could not seek to start of disk: %m"); exit(EXIT_FAILURE); } if (read(dp->fd, buf, sizeof buf) != sizeof buf) { dseek(dp, saved_offset, SEEK_SET); return; } /* seek back to where we were */ if (dseek(dp, saved_offset, SEEK_SET) == -1) { syslog(LOG_NOTICE, "could not seek to previous position" "after reading first sector: %m"); exit(EXIT_FAILURE); } // TODO: should validate DOS partition table (vs GPT or dedicated) dos = (struct dos_partition *)&buf[DOSPARTOFF]; for (slice = 0; slice < NDOSPART; slice++) if (dos[slice].dp_start <= secno && secno < dos[slice].dp_start + dos[slice].dp_size) break; if (slice == NDOSPART) { syslog(LOG_NOTICE, "sector " QD " on %s doesn't appear " "to be within any DOS slice", secno, dp->device); return; } /* Make secno relative to this slice */ secno -= dos[slice].dp_start; snprintf(newdev, sizeof newdev, "%ss%d", dp->device, slice + 1); syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev); /* Check the type of that partition. */ if (dos[slice].dp_typ != DOSPTYP_386BSD) { /* If not a BSD slice, we can't do much more. */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on device %s, type %02x", secno, newdev, dos[slice].dp_typ); return; } if ((fd = open(newdev, O_RDONLY)) < 0) { syslog(LOG_NOTICE, "open %s failure: %m", newdev); return; } /* Try to read the disklabel from that device. */ if (ioctl(fd, DIOCGDINFO, &label) < 0) { syslog(LOG_NOTICE, "DIOCGDINFO on %s failed: %m", newdev); return; } /* Check which partition this sector is in. */ for (part = 0; part < MAXPARTITIONS; part++) if (part != 2 && /* skip 'c' partition */ label.d_partitions[part].p_offset <= secno && secno < label.d_partitions[part].p_offset + label.d_partitions[part].p_size) break; if (part == MAXPARTITIONS) { syslog(LOG_NOTICE, "sector " QD " on %s doesn't appear " "to be within any BSD partition", secno, newdev); return; } secno -= label.d_partitions[part].p_offset; snprintf(newdev, sizeof newdev, "%ss%d%c", dp->device, slice + 1, 'a' + part); syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev); if (label.d_partitions[part].p_fstype != FS_BSDFFS) { /* Again, if not a BSD partition, can't do much. */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on device %s, type %s", secno, newdev, fstypename(label.d_partitions[part].p_fstype)); return; } #else /* DIOCGDINFO */ if (geomSize == 0) { sysctlbyname("kern.geom.conftxt", NULL, &geomSize, NULL, 0); if (geomSize <= 0) { printf("sysctlbyname() returned size = %d\n", geomSize); geomSize = 0; exit(EXIT_FAILURE); } geomConf = malloc(geomSize); if (geomConf == NULL) { printf("malloc(%d) returned NULL\n", geomSize); geomSize = 0; exit(EXIT_FAILURE); } if (sysctlbyname("kern.geom.conftxt", geomConf, &geomSize, NULL, 0) != 0) { perror("sysctlbyname()"); geomSize = 0; free(geomConf); geomConf = NULL; exit(EXIT_FAILURE); } } if (part == NULL) part = malloc(partLen + 1); for ( cp = geomConf ; *cp ; ++cp ) { // find line "0 DISK " matching current disk, using // strncmp because where cp points is not null-terminated // (All DISK lines, and only DISK lines, are at level 0.) // Magic numbers: 7 == strlen("0 DISK "); 5 == strlen("/dev/") if (strncmp(cp, "0 DISK ", 7) == 0 && strncmp(&cp[7], &dp->device[5], strlen(dp->device) - 5) == 0 && cp[7 + strlen(dp->device) - 5] == ' ') { for (;;) { // scan to end of line while (cp[1] && *cp != '\n') ++cp; ++cp; // start of next line // Find PART line containing the failed sector; // must be on same disk => stop upon finding // another DISK line. If more than one matching // PART -- due to nested geoms -- use the last // (innermost). if (*cp == '\0' || *cp == '0') break; // end of current DISK's entries // scan to end of level number while (cp[1] && *cp != ' ') ++cp; if (strncmp(cp, " PART ", 6) == 0) { char *pp = &cp[6]; int pl = strchr(pp, ' ') - pp; quad_t mediasize, offset; long secsize; cp = pp + pl; // cp -> mediasize mediasize = strtoq(cp, &cp, 10); secsize = strtol(cp, &cp, 10); mediasize /= secsize; cp = strchr(cp, 'o') + 1; offset = strtoq(cp, &cp, 10) / secsize; if (secno >= offset && (secno - offset) < mediasize) { if (pl > partLen) { part = realloc(part, pl+1); partLen = pl; } strncpy(part, pp, pl); part[pl] = '\0'; relsec = secno - offset; typefld = cp + 1; } } } } // scan to end of line while (cp[1] && *cp != '\n') ++cp; } //// printf("part %s, relsec %qd, typefld %p: %.27s\n", //// part, relsec, typefld, typefld); secno = relsec; strncpy(newdev, part, sizeof(newdev) - 1); newdev[sizeof(newdev) - 1] = '\0'; // paranoia #endif /* DIOCGDINFO */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on 4.2BSD filesystem %s", secno, newdev); /* * XXX: todo: find out which file on the BSD filesystem uses this * sector... */ }