Esempio n. 1
0
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;
	}
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/*
 * 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...
	 */
}