diff --git a/lib/libgeom/geom_util.c b/lib/libgeom/geom_util.c index c596178..539b6c6 100644 --- a/lib/libgeom/geom_util.c +++ b/lib/libgeom/geom_util.c @@ -42,29 +42,22 @@ __FBSDID("$FreeBSD$"); #include +static char *g_device_path_open(const char *, int *, int); + /* * Open the given provider and at least check if this is a block device. */ int g_open(const char *name, int dowrite) { - char path[MAXPATHLEN]; + char *path; int fd; - if (name[0] == '/') - strlcpy(path, name, sizeof(path)); - else - snprintf(path, sizeof(path), "%s%s", _PATH_DEV, name); - - fd = open(path, dowrite ? O_RDWR : O_RDONLY); + path = g_device_path_open(name, &fd, dowrite); + if (path != NULL) + free(path); if (fd == -1) return (-1); - /* Let try to get sectorsize, which will prove it is a GEOM provider. */ - if (g_sectorsize(fd) == -1) { - close(fd); - errno = EFTYPE; - return (-1); - } return (fd); } @@ -121,6 +114,19 @@ g_sectorsize(int fd) } /* + * Return the correct provider name. + */ +char * +g_providername(int fd) +{ + char name[MAXPATHLEN]; + + if (g_ioctl_arg(fd, DIOCGPROVIDERNAME, name) == -1) + return (NULL); + return (strdup(name)); +} + +/* * Call BIO_FLUSH for the given provider. */ int @@ -234,3 +240,77 @@ end: } return (fd); } + +/* + * Return the device path device given a partial or full path to its node. + * A pointer can be provided, which will be set to an opened file descriptor of + * not NULL. + */ +static char * +g_device_path_open(const char *devpath, int *fdp, int dowrite) +{ + char *path; + int fd; + + /* Make sure that we can fail. */ + if (fdp != NULL) + *fdp = -1; + /* Use the device node if we're able to open it. */ + do { + fd = open(devpath, dowrite ? O_RDWR : O_RDONLY); + if (fd == -1) + break; + /* + * Let try to get sectorsize, which will prove it is a GEOM + * provider. + */ + if (g_sectorsize(fd) == -1) { + close(fd); + errno = EFTYPE; + return (NULL); + } + if ((path = strdup(devpath)) == NULL) { + close(fd); + return (NULL); + } + if (fdp != NULL) + *fdp = fd; + else + close(fd); + return (path); + } while (0); + + /* If we're not given an absolute path, assume /dev/ prefix. */ + if (*devpath != '/') { + asprintf(&path, "%s%s", _PATH_DEV, devpath); + if (path == NULL) + return (NULL); + fd = open(path, dowrite ? O_RDWR : O_RDONLY); + if (fd == -1) { + free(path); + return (NULL); + } + /* + * Let try to get sectorsize, which will prove it is a GEOM + * provider. + */ + if (g_sectorsize(fd) == -1) { + free(path); + close(fd); + errno = EFTYPE; + return (NULL); + } + if (fdp != NULL) + *fdp = fd; + else + close(fd); + return (path); + } + return (NULL); +} + +char * +g_device_path(const char *devpath) +{ + return (g_device_path_open(devpath, NULL, 0)); +} diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h index 56736a3..7255bd4 100644 --- a/lib/libgeom/libgeom.h +++ b/lib/libgeom/libgeom.h @@ -154,6 +154,8 @@ int g_delete(int, off_t, off_t); int g_get_ident(int, char *, size_t); int g_get_name(const char *, char *, size_t); int g_open_by_ident(const char *, int, char *, size_t); +char *g_device_path(const char *); +char *g_providername(int); __END_DECLS diff --git a/sbin/fdisk/fdisk.c b/sbin/fdisk/fdisk.c index e484578..e540038 100644 --- a/sbin/fdisk/fdisk.c +++ b/sbin/fdisk/fdisk.c @@ -245,7 +245,6 @@ static void usage(void); int main(int argc, char *argv[]) { - struct stat sb; int c, i; int partition = -1; struct dos_partition *partp; @@ -307,18 +306,9 @@ main(int argc, char *argv[]) if (argc == 0) { disk = get_rootdisk(); } else { - if (stat(argv[0], &sb) == 0) { - /* OK, full pathname given */ - disk = argv[0]; - } else if (errno == ENOENT && argv[0][0] != '/') { - /* Try prepending "/dev" */ - asprintf(&disk, "%s%s", _PATH_DEV, argv[0]); - if (disk == NULL) - errx(1, "out of memory"); - } else { - /* other stat error, let it fail below */ - disk = argv[0]; - } + disk = g_device_path(argv[0]); + if (disk == NULL) + err(1, "unable to get correct path for %s\n", argv[0]); } if (open_disk(u_flag) < 0) err(1, "cannot open disk %s", disk); @@ -724,21 +714,14 @@ dos(struct dos_partition *partp) static int open_disk(int flag) { - struct stat st; int rwmode; - if (stat(disk, &st) == -1) { - if (errno == ENOENT) - return -2; - warnx("can't get file status of %s", disk); - return -1; - } - if ( !(st.st_mode & S_IFCHR) ) - warnx("device %s is not character special", disk); - rwmode = a_flag || I_flag || B_flag || flag ? O_RDWR : O_RDONLY; - fd = open(disk, rwmode); - if (fd == -1 && errno == EPERM && rwmode == O_RDWR) - fd = open(disk, O_RDONLY); + /* Write mode if one of these flags are set. */ + rwmode = (a_flag || I_flag || B_flag || flag); + fd = g_open(disk, rwmode); + /* If the mode fails, try read-only if we didn't. */ + if (fd == -1 && errno == EPERM && rwmode) + fd = g_open(disk, 0); if (fd == -1 && errno == ENXIO) return -2; if (fd == -1) { @@ -778,29 +761,30 @@ write_disk(off_t sector, void *buf) { int error; struct gctl_req *grq; - const char *q; - char fbuf[BUFSIZ]; + const char *errmsg; + char fbuf[BUFSIZ], *pname; int i, fdw; grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write MBR"); gctl_ro_param(grq, "class", -1, "MBR"); - q = strrchr(disk, '/'); - if (q == NULL) - q = disk; - else - q++; - gctl_ro_param(grq, "geom", -1, q); + pname = g_providername(fd); + if (pname == NULL) { + warnx("Error getting providername for %s\n", disk); + return (-1); + } + gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "data", secsize, buf); - q = gctl_issue(grq); - if (q == NULL) { + errmsg = gctl_issue(grq); + free(pname); + if (errmsg == NULL) { gctl_free(grq); return(0); } if (!q_flag) /* GEOM errors are benign, not all devices supported */ - warnx("%s", q); + warnx("%s", errmsg); gctl_free(grq); - + error = pwrite(fd, buf, secsize, (sector * 512)); if (error == secsize) return (0); @@ -841,21 +825,18 @@ get_params() dos_cylsecs = cylsecs = heads * sectors; disksecs = cyls * heads * sectors; - error = ioctl(fd, DIOCGSECTORSIZE, &u); - if (error != 0 || u == 0) - u = 512; - else - secsize = u; + u = g_sectorsize(fd); + if (u <= 0) + return (-1); - error = ioctl(fd, DIOCGMEDIASIZE, &o); - if (error == 0) { - disksecs = o / u; - cyls = dos_cyls = o / (u * dos_heads * dos_sectors); - } + o = g_mediasize(fd); + if (o < 0) + return (-1); + disksecs = o / u; + cyls = dos_cyls = o / (u * dos_heads * dos_sectors); return (disksecs); } - static int read_s0() diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index 4abbfc0..eeb3b09 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -244,6 +244,7 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread { struct g_geom *gp; struct g_consumer *cp; + struct g_provider *pp; struct g_kerneldump kd; off_t offset, length, chunk; int i, error; @@ -251,6 +252,7 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread gp = dev->si_drv1; cp = dev->si_drv2; + pp = cp->provider; error = 0; KASSERT(cp->acr || cp->acw, @@ -329,6 +331,11 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread case DIOCGIDENT: error = g_io_getattr("GEOM::ident", cp, &i, data); break; + case DIOCGPROVIDERNAME: + if (pp == NULL) + return (ENOENT); + strlcpy(data, pp->name, i); + break; default: if (cp->provider->geom->ioctl != NULL) { diff --git a/sys/sys/disk.h b/sys/sys/disk.h index 71e775e..4fe2e09 100644 --- a/sys/sys/disk.h +++ b/sys/sys/disk.h @@ -98,4 +98,10 @@ void disk_err(struct bio *bp, const char *what, int blkdone, int nl); * - ident is optional and applications can't relay on its presence. */ +#define DIOCGPROVIDERNAME _IOR('d', 138, char[MAXPATHLEN]) + /*- + * Store the provider name, given a device path, in a buffer. The buffer + * must be at least MAXPATHLEN bytes long. + */ + #endif /* _SYS_DISK_H_ */ diff --git a/usr.sbin/boot0cfg/boot0cfg.c b/usr.sbin/boot0cfg/boot0cfg.c index 6fd0587..63fa78e 100644 --- a/usr.sbin/boot0cfg/boot0cfg.c +++ b/usr.sbin/boot0cfg/boot0cfg.c @@ -80,7 +80,6 @@ static void display_mbr(u_int8_t *); static int boot0version(const u_int8_t *); static int boot0bs(const u_int8_t *); static void stropt(const char *, int *, int *); -static char *mkrdev(const char *); static int argtoi(const char *, int, int, int); static void usage(void); @@ -142,7 +141,9 @@ main(int argc, char *argv[]) argv += optind; if (argc != 1) usage(); - disk = mkrdev(*argv); + disk = g_device_path(*argv); + if (disk == NULL) + errx(1, "Unable to get providername for %s\n", *argv); up = B_flag || d_arg != -1 || m_arg != -1 || o_flag || s_arg != -1 || t_arg != -1; @@ -257,7 +258,8 @@ write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size) int fd, p; ssize_t n; char *s; - const char *q; + const char *errmsg; + char *pname; struct gctl_req *grq; fd = open(fname, O_WRONLY | flags, 0666); @@ -269,23 +271,31 @@ write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size) return; } + /* Try open it read only. */ + fd = open(fname, O_RDONLY); + if (fd == -1) { + warnx("Error opening %s\n", fname); + return; + } + pname = g_providername(fd); + if (pname == NULL) { + warnx("Error getting providername for %s\n", fname); + return; + } if (flags != 0) err(1, "%s", fname); grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write MBR"); gctl_ro_param(grq, "class", -1, "MBR"); - q = strrchr(fname, '/'); - if (q == NULL) - q = fname; - else - q++; - gctl_ro_param(grq, "geom", -1, q); + gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "data", mbr_size, mbr); - q = gctl_issue(grq); - if (q == NULL) + errmsg = gctl_issue(grq); + if (errmsg == NULL) { + free(pname); return; - - warnx("%s: %s", fname, q); + } + warnx("%s: %s", fname, pname); + free(pname); gctl_free(grq); #ifdef DIOCSMBR @@ -422,26 +432,6 @@ stropt(const char *arg, int *xa, int *xo) } /* - * Produce a device path for a "canonical" name, where appropriate. - */ -static char * -mkrdev(const char *fname) -{ - char buf[MAXPATHLEN]; - char *s; - - if (!strchr(fname, '/')) { - snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); - s = strdup(buf); - } else - s = strdup(fname); - - if (s == NULL) - errx(1, "No more memory"); - return s; -} - -/* * Convert and check an option argument. */ static int