NetBSD/sbin/fsck/partutil.c

197 lines
5.4 KiB
C
Raw Normal View History

/* $NetBSD: partutil.c,v 1.17 2019/09/28 18:03:18 bad Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: partutil.c,v 1.17 2019/09/28 18:03:18 bad Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/disklabel.h>
#include <sys/disk.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <disktab.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <util.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <prop/proplib.h>
#include "partutil.h"
/*
* Convert disklabel geometry info to disk_geom.
*/
static void
label2geom(struct disk_geom *geo, const struct disklabel *lp)
{
geo->dg_secperunit = lp->d_secperunit;
geo->dg_secsize = lp->d_secsize;
geo->dg_nsectors = lp->d_nsectors;
geo->dg_ntracks = lp->d_ntracks;
geo->dg_ncylinders = lp->d_ncylinders;
geo->dg_secpercyl = lp->d_secpercyl;
geo->dg_pcylinders = lp->d_ncylinders;
geo->dg_sparespertrack = lp->d_sparespertrack;
geo->dg_sparespercyl = lp->d_sparespercyl;
geo->dg_acylinders = lp->d_acylinders;
}
/*
* Set what we need to know about disk geometry.
*/
static void
dict2geom(struct disk_geom *geo, prop_dictionary_t dict)
{
(void)memset(geo, 0, sizeof(struct disk_geom));
prop_dictionary_get_int64(dict, "sectors-per-unit",
&geo->dg_secperunit);
prop_dictionary_get_uint32(dict, "sector-size", &geo->dg_secsize);
prop_dictionary_get_uint32(dict, "sectors-per-track",
&geo->dg_nsectors);
prop_dictionary_get_uint32(dict, "tracks-per-cylinder",
&geo->dg_ntracks);
prop_dictionary_get_uint32(dict, "cylinders-per-unit",
&geo->dg_ncylinders);
}
int
getdiskinfo(const char *s, int fd, const char *dt, struct disk_geom *geo,
struct dkwedge_info *dkw)
{
struct disklabel lab;
struct disklabel *lp = &lab;
prop_dictionary_t disk_dict, geom_dict;
struct stat sb;
const struct partition *pp;
int ptn, error;
if (dt) {
lp = getdiskbyname(dt);
if (lp == NULL)
errx(1, "unknown disk type `%s'", dt);
}
/* Get disk description dictionary */
disk_dict = NULL;
error = prop_dictionary_recv_ioctl(fd, DIOCGDISKINFO, &disk_dict);
/* fail quickly if the device does not exist at all */
if (error == ENXIO)
return -1;
if (error) {
/*
* Ask for disklabel if DIOCGDISKINFO failed. This is
* compatibility call and can be removed when all devices
* will support DIOCGDISKINFO.
* cgd, ccd pseudo disk drives doesn't support DIOCGDDISKINFO
*/
if (ioctl(fd, DIOCGDINFO, lp) == -1) {
if (errno != ENXIO)
warn("DIOCGDINFO on %s failed", s);
return -1;
}
label2geom(geo, lp);
} else {
geom_dict = prop_dictionary_get(disk_dict, "geometry");
dict2geom(geo, geom_dict);
}
if (disk_dict != NULL)
prop_object_release(disk_dict);
2014-12-29 19:35:38 +03:00
if (dkw == NULL)
return 0;
/* Get info about partition/wedge */
if (ioctl(fd, DIOCGWEDGEINFO, dkw) != -1) {
/* DIOCGWEDGEINFO didn't fail, we're done */
return 0;
}
if (ioctl(fd, DIOCGDINFO, lp) == -1) {
err(1, "Please implement DIOCGWEDGEINFO or "
"DIOCGDINFO for disk device %s", s);
}
/* DIOCGDINFO didn't fail */
(void)memset(dkw, 0, sizeof(*dkw));
if (stat(s, &sb) == -1)
return 0;
ptn = strchr(s, '\0')[-1] - 'a';
if ((unsigned)ptn >= lp->d_npartitions ||
(devminor_t)ptn != DISKPART(sb.st_rdev))
return 0;
pp = &lp->d_partitions[ptn];
if (ptn != getrawpartition()) {
dkw->dkw_offset = pp->p_offset;
dkw->dkw_size = pp->p_size;
} else {
dkw->dkw_offset = 0;
dkw->dkw_size = geo->dg_secperunit;
}
dkw->dkw_parent[0] = '*';
strlcpy(dkw->dkw_ptype, getfstypename(pp->p_fstype),
sizeof(dkw->dkw_ptype));
return 0;
}
int
getdisksize(const char *name, u_int *secsize, off_t *mediasize)
{
char buf[MAXPATHLEN];
struct disk_geom geo;
int fd, error;
if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) == -1)
return -1;
error = getdiskinfo(name, fd, NULL, &geo, NULL);
close(fd);
if (error)
return error;
*secsize = geo.dg_secsize;
*mediasize = geo.dg_secsize * geo.dg_secperunit;
return 0;
}