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