1fbda685dSPawel Jakub Dawidek /*- 2*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*5e53a4f9SPedro F. Giffuni * 4fbda685dSPawel Jakub Dawidek * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5fbda685dSPawel Jakub Dawidek * All rights reserved. 6fbda685dSPawel Jakub Dawidek * 7fbda685dSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 8fbda685dSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 9fbda685dSPawel Jakub Dawidek * are met: 10fbda685dSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 11fbda685dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 12fbda685dSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 13fbda685dSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 14fbda685dSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 15fbda685dSPawel Jakub Dawidek * 16fbda685dSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17fbda685dSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18fbda685dSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19fbda685dSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20fbda685dSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21fbda685dSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22fbda685dSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23fbda685dSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24fbda685dSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25fbda685dSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26fbda685dSPawel Jakub Dawidek * SUCH DAMAGE. 27fbda685dSPawel Jakub Dawidek */ 28fbda685dSPawel Jakub Dawidek 29fbda685dSPawel Jakub Dawidek #include <sys/cdefs.h> 30fbda685dSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 31fbda685dSPawel Jakub Dawidek 32fbda685dSPawel Jakub Dawidek #include <sys/param.h> 33fbda685dSPawel Jakub Dawidek #include <sys/disk.h> 34fbda685dSPawel Jakub Dawidek #include <sys/stat.h> 35fbda685dSPawel Jakub Dawidek 36fbda685dSPawel Jakub Dawidek #include <stdio.h> 37fbda685dSPawel Jakub Dawidek #include <fcntl.h> 38fbda685dSPawel Jakub Dawidek #include <errno.h> 39fbda685dSPawel Jakub Dawidek #include <stdint.h> 40fbda685dSPawel Jakub Dawidek #include <unistd.h> 41fbda685dSPawel Jakub Dawidek #include <string.h> 42fbda685dSPawel Jakub Dawidek #include <stdlib.h> 43fbda685dSPawel Jakub Dawidek #include <paths.h> 44fbda685dSPawel Jakub Dawidek 45fbda685dSPawel Jakub Dawidek #include <libgeom.h> 46fbda685dSPawel Jakub Dawidek 47f805f204SUlf Lilleengen static char *g_device_path_open(const char *, int *, int); 48f805f204SUlf Lilleengen 49fbda685dSPawel Jakub Dawidek /* 50fbda685dSPawel Jakub Dawidek * Open the given provider and at least check if this is a block device. 51fbda685dSPawel Jakub Dawidek */ 52fbda685dSPawel Jakub Dawidek int 539ac6b8aeSPawel Jakub Dawidek g_open(const char *name, int dowrite) 54fbda685dSPawel Jakub Dawidek { 55f805f204SUlf Lilleengen char *path; 56fbda685dSPawel Jakub Dawidek int fd; 57fbda685dSPawel Jakub Dawidek 58f805f204SUlf Lilleengen path = g_device_path_open(name, &fd, dowrite); 59f805f204SUlf Lilleengen if (path != NULL) 60f805f204SUlf Lilleengen free(path); 61fbda685dSPawel Jakub Dawidek return (fd); 62fbda685dSPawel Jakub Dawidek } 63fbda685dSPawel Jakub Dawidek 64fbda685dSPawel Jakub Dawidek int 65fbda685dSPawel Jakub Dawidek g_close(int fd) 66fbda685dSPawel Jakub Dawidek { 67fbda685dSPawel Jakub Dawidek 68fbda685dSPawel Jakub Dawidek return (close(fd)); 69fbda685dSPawel Jakub Dawidek } 70fbda685dSPawel Jakub Dawidek 71fbda685dSPawel Jakub Dawidek static int 72fbda685dSPawel Jakub Dawidek g_ioctl_arg(int fd, unsigned long cmd, void *arg) 73fbda685dSPawel Jakub Dawidek { 74fbda685dSPawel Jakub Dawidek int ret; 75fbda685dSPawel Jakub Dawidek 76fbda685dSPawel Jakub Dawidek if (arg != NULL) 77fbda685dSPawel Jakub Dawidek ret = ioctl(fd, cmd, arg); 78fbda685dSPawel Jakub Dawidek else 79fbda685dSPawel Jakub Dawidek ret = ioctl(fd, cmd); 80fbda685dSPawel Jakub Dawidek return (ret >= 0 ? 0 : -1); 81fbda685dSPawel Jakub Dawidek } 82fbda685dSPawel Jakub Dawidek 83fbda685dSPawel Jakub Dawidek static int 84fbda685dSPawel Jakub Dawidek g_ioctl(int fd, unsigned long cmd) 85fbda685dSPawel Jakub Dawidek { 86fbda685dSPawel Jakub Dawidek 87fbda685dSPawel Jakub Dawidek return (g_ioctl_arg(fd, cmd, NULL)); 88fbda685dSPawel Jakub Dawidek } 89fbda685dSPawel Jakub Dawidek 90fbda685dSPawel Jakub Dawidek /* 91fbda685dSPawel Jakub Dawidek * Return media size of the given provider. 92fbda685dSPawel Jakub Dawidek */ 93fbda685dSPawel Jakub Dawidek off_t 94fbda685dSPawel Jakub Dawidek g_mediasize(int fd) 95fbda685dSPawel Jakub Dawidek { 96fbda685dSPawel Jakub Dawidek off_t mediasize; 97fbda685dSPawel Jakub Dawidek 98fbda685dSPawel Jakub Dawidek if (g_ioctl_arg(fd, DIOCGMEDIASIZE, &mediasize) == -1) 99fbda685dSPawel Jakub Dawidek mediasize = -1; 100fbda685dSPawel Jakub Dawidek return (mediasize); 101fbda685dSPawel Jakub Dawidek } 102fbda685dSPawel Jakub Dawidek 103fbda685dSPawel Jakub Dawidek /* 104fbda685dSPawel Jakub Dawidek * Return sector size of the given provider. 105fbda685dSPawel Jakub Dawidek */ 106fbda685dSPawel Jakub Dawidek ssize_t 107fbda685dSPawel Jakub Dawidek g_sectorsize(int fd) 108fbda685dSPawel Jakub Dawidek { 109fbda685dSPawel Jakub Dawidek u_int sectorsize; 110fbda685dSPawel Jakub Dawidek 111fbda685dSPawel Jakub Dawidek if (g_ioctl_arg(fd, DIOCGSECTORSIZE, §orsize) == -1) 112fbda685dSPawel Jakub Dawidek return (-1); 113fbda685dSPawel Jakub Dawidek return ((ssize_t)sectorsize); 114fbda685dSPawel Jakub Dawidek } 115fbda685dSPawel Jakub Dawidek 116fbda685dSPawel Jakub Dawidek /* 11735daa28fSXin LI * Return stripe size of the given provider. 11835daa28fSXin LI */ 11935daa28fSXin LI off_t 12035daa28fSXin LI g_stripesize(int fd) 12135daa28fSXin LI { 12235daa28fSXin LI off_t stripesize; 12335daa28fSXin LI 12435daa28fSXin LI if (g_ioctl_arg(fd, DIOCGSTRIPESIZE, &stripesize) == -1) 12535daa28fSXin LI return (-1); 12635daa28fSXin LI return (stripesize); 12735daa28fSXin LI } 12835daa28fSXin LI 12935daa28fSXin LI /* 13035daa28fSXin LI * Return stripe size of the given provider. 13135daa28fSXin LI */ 13235daa28fSXin LI off_t 13335daa28fSXin LI g_stripeoffset(int fd) 13435daa28fSXin LI { 13535daa28fSXin LI off_t stripeoffset; 13635daa28fSXin LI 13735daa28fSXin LI if (g_ioctl_arg(fd, DIOCGSTRIPEOFFSET, &stripeoffset) == -1) 13835daa28fSXin LI return (-1); 13935daa28fSXin LI return (stripeoffset); 14035daa28fSXin LI } 14135daa28fSXin LI 14235daa28fSXin LI /* 143f805f204SUlf Lilleengen * Return the correct provider name. 144f805f204SUlf Lilleengen */ 145f805f204SUlf Lilleengen char * 146f805f204SUlf Lilleengen g_providername(int fd) 147f805f204SUlf Lilleengen { 148f805f204SUlf Lilleengen char name[MAXPATHLEN]; 149f805f204SUlf Lilleengen 150f805f204SUlf Lilleengen if (g_ioctl_arg(fd, DIOCGPROVIDERNAME, name) == -1) 151f805f204SUlf Lilleengen return (NULL); 152f805f204SUlf Lilleengen return (strdup(name)); 153f805f204SUlf Lilleengen } 154f805f204SUlf Lilleengen 155f805f204SUlf Lilleengen /* 156fbda685dSPawel Jakub Dawidek * Call BIO_FLUSH for the given provider. 157fbda685dSPawel Jakub Dawidek */ 158fbda685dSPawel Jakub Dawidek int 159fbda685dSPawel Jakub Dawidek g_flush(int fd) 160fbda685dSPawel Jakub Dawidek { 161fbda685dSPawel Jakub Dawidek 162fbda685dSPawel Jakub Dawidek return (g_ioctl(fd, DIOCGFLUSH)); 163fbda685dSPawel Jakub Dawidek } 164fbda685dSPawel Jakub Dawidek 165fbda685dSPawel Jakub Dawidek /* 166fbda685dSPawel Jakub Dawidek * Call BIO_DELETE for the given range. 167fbda685dSPawel Jakub Dawidek */ 168fbda685dSPawel Jakub Dawidek int 169fbda685dSPawel Jakub Dawidek g_delete(int fd, off_t offset, off_t length) 170fbda685dSPawel Jakub Dawidek { 171fbda685dSPawel Jakub Dawidek off_t arg[2]; 172fbda685dSPawel Jakub Dawidek 173fbda685dSPawel Jakub Dawidek arg[0] = offset; 174fbda685dSPawel Jakub Dawidek arg[1] = length; 175fbda685dSPawel Jakub Dawidek return (g_ioctl_arg(fd, DIOCGDELETE, arg)); 176fbda685dSPawel Jakub Dawidek } 177fbda685dSPawel Jakub Dawidek 178fbda685dSPawel Jakub Dawidek /* 179fbda685dSPawel Jakub Dawidek * Return ID of the given provider. 180fbda685dSPawel Jakub Dawidek */ 181fbda685dSPawel Jakub Dawidek int 182fbda685dSPawel Jakub Dawidek g_get_ident(int fd, char *ident, size_t size) 183fbda685dSPawel Jakub Dawidek { 184fbda685dSPawel Jakub Dawidek char lident[DISK_IDENT_SIZE]; 185fbda685dSPawel Jakub Dawidek 186fbda685dSPawel Jakub Dawidek if (g_ioctl_arg(fd, DIOCGIDENT, lident) == -1) 187fbda685dSPawel Jakub Dawidek return (-1); 188fbda685dSPawel Jakub Dawidek if (lident[0] == '\0') { 189fbda685dSPawel Jakub Dawidek errno = ENOENT; 190fbda685dSPawel Jakub Dawidek return (-1); 191fbda685dSPawel Jakub Dawidek } 192fbda685dSPawel Jakub Dawidek if (strlcpy(ident, lident, size) >= size) { 193fbda685dSPawel Jakub Dawidek errno = ENAMETOOLONG; 194fbda685dSPawel Jakub Dawidek return (-1); 195fbda685dSPawel Jakub Dawidek } 196fbda685dSPawel Jakub Dawidek return (0); 197fbda685dSPawel Jakub Dawidek } 198fbda685dSPawel Jakub Dawidek 199fbda685dSPawel Jakub Dawidek /* 200fbda685dSPawel Jakub Dawidek * Return name of the provider, which has the given ID. 201fbda685dSPawel Jakub Dawidek */ 202fbda685dSPawel Jakub Dawidek int 203fbda685dSPawel Jakub Dawidek g_get_name(const char *ident, char *name, size_t size) 204fbda685dSPawel Jakub Dawidek { 205fbda685dSPawel Jakub Dawidek int fd; 206fbda685dSPawel Jakub Dawidek 207fbda685dSPawel Jakub Dawidek fd = g_open_by_ident(ident, 0, name, size); 208fbda685dSPawel Jakub Dawidek if (fd == -1) 209fbda685dSPawel Jakub Dawidek return (-1); 210fbda685dSPawel Jakub Dawidek g_close(fd); 211fbda685dSPawel Jakub Dawidek return (0); 212fbda685dSPawel Jakub Dawidek } 213fbda685dSPawel Jakub Dawidek 214fbda685dSPawel Jakub Dawidek /* 215fbda685dSPawel Jakub Dawidek * Find provider name by the given ID. 216fbda685dSPawel Jakub Dawidek */ 217fbda685dSPawel Jakub Dawidek int 2189ac6b8aeSPawel Jakub Dawidek g_open_by_ident(const char *ident, int dowrite, char *name, size_t size) 219fbda685dSPawel Jakub Dawidek { 220fbda685dSPawel Jakub Dawidek char lident[DISK_IDENT_SIZE]; 221fbda685dSPawel Jakub Dawidek struct gmesh mesh; 222fbda685dSPawel Jakub Dawidek struct gclass *mp; 223fbda685dSPawel Jakub Dawidek struct ggeom *gp; 224fbda685dSPawel Jakub Dawidek struct gprovider *pp; 225fbda685dSPawel Jakub Dawidek int error, fd; 226fbda685dSPawel Jakub Dawidek 227fbda685dSPawel Jakub Dawidek error = geom_gettree(&mesh); 228fbda685dSPawel Jakub Dawidek if (error != 0) { 229fbda685dSPawel Jakub Dawidek errno = error; 230fbda685dSPawel Jakub Dawidek return (-1); 231fbda685dSPawel Jakub Dawidek } 232fbda685dSPawel Jakub Dawidek 233fbda685dSPawel Jakub Dawidek error = ENOENT; 234fbda685dSPawel Jakub Dawidek fd = -1; 235fbda685dSPawel Jakub Dawidek 236fbda685dSPawel Jakub Dawidek LIST_FOREACH(mp, &mesh.lg_class, lg_class) { 237fbda685dSPawel Jakub Dawidek LIST_FOREACH(gp, &mp->lg_geom, lg_geom) { 238fbda685dSPawel Jakub Dawidek LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 2399ac6b8aeSPawel Jakub Dawidek fd = g_open(pp->lg_name, dowrite); 240fbda685dSPawel Jakub Dawidek if (fd == -1) 241fbda685dSPawel Jakub Dawidek continue; 242fbda685dSPawel Jakub Dawidek if (g_get_ident(fd, lident, 243fbda685dSPawel Jakub Dawidek sizeof(lident)) == -1) { 244fbda685dSPawel Jakub Dawidek g_close(fd); 245fbda685dSPawel Jakub Dawidek continue; 246fbda685dSPawel Jakub Dawidek } 247fbda685dSPawel Jakub Dawidek if (strcmp(ident, lident) != 0) { 248fbda685dSPawel Jakub Dawidek g_close(fd); 249fbda685dSPawel Jakub Dawidek continue; 250fbda685dSPawel Jakub Dawidek } 251fbda685dSPawel Jakub Dawidek error = 0; 252fbda685dSPawel Jakub Dawidek if (name != NULL && strlcpy(name, pp->lg_name, 253fbda685dSPawel Jakub Dawidek size) >= size) { 254fbda685dSPawel Jakub Dawidek error = ENAMETOOLONG; 255fbda685dSPawel Jakub Dawidek g_close(fd); 256fbda685dSPawel Jakub Dawidek } 257fbda685dSPawel Jakub Dawidek goto end; 258fbda685dSPawel Jakub Dawidek } 259fbda685dSPawel Jakub Dawidek } 260fbda685dSPawel Jakub Dawidek } 261fbda685dSPawel Jakub Dawidek end: 262fbda685dSPawel Jakub Dawidek geom_deletetree(&mesh); 263fbda685dSPawel Jakub Dawidek if (error != 0) { 264fbda685dSPawel Jakub Dawidek errno = error; 265fbda685dSPawel Jakub Dawidek return (-1); 266fbda685dSPawel Jakub Dawidek } 267fbda685dSPawel Jakub Dawidek return (fd); 268fbda685dSPawel Jakub Dawidek } 269f805f204SUlf Lilleengen 270f805f204SUlf Lilleengen /* 271f805f204SUlf Lilleengen * Return the device path device given a partial or full path to its node. 272f805f204SUlf Lilleengen * A pointer can be provided, which will be set to an opened file descriptor of 273f805f204SUlf Lilleengen * not NULL. 274f805f204SUlf Lilleengen */ 275f805f204SUlf Lilleengen static char * 276f805f204SUlf Lilleengen g_device_path_open(const char *devpath, int *fdp, int dowrite) 277f805f204SUlf Lilleengen { 278f805f204SUlf Lilleengen char *path; 279f805f204SUlf Lilleengen int fd; 280f805f204SUlf Lilleengen 281f805f204SUlf Lilleengen /* Make sure that we can fail. */ 282f805f204SUlf Lilleengen if (fdp != NULL) 283f805f204SUlf Lilleengen *fdp = -1; 284b906c1a0SConrad Meyer 285f805f204SUlf Lilleengen /* Use the device node if we're able to open it. */ 286f805f204SUlf Lilleengen fd = open(devpath, dowrite ? O_RDWR : O_RDONLY); 287b906c1a0SConrad Meyer if (fd != -1) { 288f805f204SUlf Lilleengen if ((path = strdup(devpath)) == NULL) { 289f805f204SUlf Lilleengen close(fd); 290f805f204SUlf Lilleengen return (NULL); 291f805f204SUlf Lilleengen } 292b906c1a0SConrad Meyer goto fd_ok; 293b906c1a0SConrad Meyer } 294f805f204SUlf Lilleengen 295f805f204SUlf Lilleengen /* If we're not given an absolute path, assume /dev/ prefix. */ 296b906c1a0SConrad Meyer if (*devpath == '/') 297b906c1a0SConrad Meyer return (NULL); 298b906c1a0SConrad Meyer 299f805f204SUlf Lilleengen asprintf(&path, "%s%s", _PATH_DEV, devpath); 300f805f204SUlf Lilleengen if (path == NULL) 301f805f204SUlf Lilleengen return (NULL); 302f805f204SUlf Lilleengen fd = open(path, dowrite ? O_RDWR : O_RDONLY); 303f805f204SUlf Lilleengen if (fd == -1) { 304f805f204SUlf Lilleengen free(path); 305f805f204SUlf Lilleengen return (NULL); 306f805f204SUlf Lilleengen } 307b906c1a0SConrad Meyer 308b906c1a0SConrad Meyer fd_ok: 309f805f204SUlf Lilleengen /* 310b906c1a0SConrad Meyer * Let try to get sectorsize, which will prove it is a GEOM provider. 311f805f204SUlf Lilleengen */ 312f805f204SUlf Lilleengen if (g_sectorsize(fd) == -1) { 313f805f204SUlf Lilleengen free(path); 314f805f204SUlf Lilleengen close(fd); 315f805f204SUlf Lilleengen errno = EFTYPE; 316f805f204SUlf Lilleengen return (NULL); 317f805f204SUlf Lilleengen } 318f805f204SUlf Lilleengen if (fdp != NULL) 319f805f204SUlf Lilleengen *fdp = fd; 320f805f204SUlf Lilleengen else 321f805f204SUlf Lilleengen close(fd); 322f805f204SUlf Lilleengen return (path); 323f805f204SUlf Lilleengen } 324f805f204SUlf Lilleengen 325f805f204SUlf Lilleengen char * 326f805f204SUlf Lilleengen g_device_path(const char *devpath) 327f805f204SUlf Lilleengen { 328f805f204SUlf Lilleengen return (g_device_path_open(devpath, NULL, 0)); 329f805f204SUlf Lilleengen } 330