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 if (fd == -1) 60fbda685dSPawel Jakub Dawidek return (-1); 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 /* 117f805f204SUlf Lilleengen * Return the correct provider name. 118f805f204SUlf Lilleengen */ 119f805f204SUlf Lilleengen char * 120f805f204SUlf Lilleengen g_providername(int fd) 121f805f204SUlf Lilleengen { 122f805f204SUlf Lilleengen char name[MAXPATHLEN]; 123f805f204SUlf Lilleengen 124f805f204SUlf Lilleengen if (g_ioctl_arg(fd, DIOCGPROVIDERNAME, name) == -1) 125f805f204SUlf Lilleengen return (NULL); 126f805f204SUlf Lilleengen return (strdup(name)); 127f805f204SUlf Lilleengen } 128f805f204SUlf Lilleengen 129f805f204SUlf Lilleengen /* 130fbda685dSPawel Jakub Dawidek * Call BIO_FLUSH for the given provider. 131fbda685dSPawel Jakub Dawidek */ 132fbda685dSPawel Jakub Dawidek int 133fbda685dSPawel Jakub Dawidek g_flush(int fd) 134fbda685dSPawel Jakub Dawidek { 135fbda685dSPawel Jakub Dawidek 136fbda685dSPawel Jakub Dawidek return (g_ioctl(fd, DIOCGFLUSH)); 137fbda685dSPawel Jakub Dawidek } 138fbda685dSPawel Jakub Dawidek 139fbda685dSPawel Jakub Dawidek /* 140fbda685dSPawel Jakub Dawidek * Call BIO_DELETE for the given range. 141fbda685dSPawel Jakub Dawidek */ 142fbda685dSPawel Jakub Dawidek int 143fbda685dSPawel Jakub Dawidek g_delete(int fd, off_t offset, off_t length) 144fbda685dSPawel Jakub Dawidek { 145fbda685dSPawel Jakub Dawidek off_t arg[2]; 146fbda685dSPawel Jakub Dawidek 147fbda685dSPawel Jakub Dawidek arg[0] = offset; 148fbda685dSPawel Jakub Dawidek arg[1] = length; 149fbda685dSPawel Jakub Dawidek return (g_ioctl_arg(fd, DIOCGDELETE, arg)); 150fbda685dSPawel Jakub Dawidek } 151fbda685dSPawel Jakub Dawidek 152fbda685dSPawel Jakub Dawidek /* 153fbda685dSPawel Jakub Dawidek * Return ID of the given provider. 154fbda685dSPawel Jakub Dawidek */ 155fbda685dSPawel Jakub Dawidek int 156fbda685dSPawel Jakub Dawidek g_get_ident(int fd, char *ident, size_t size) 157fbda685dSPawel Jakub Dawidek { 158fbda685dSPawel Jakub Dawidek char lident[DISK_IDENT_SIZE]; 159fbda685dSPawel Jakub Dawidek 160fbda685dSPawel Jakub Dawidek if (g_ioctl_arg(fd, DIOCGIDENT, lident) == -1) 161fbda685dSPawel Jakub Dawidek return (-1); 162fbda685dSPawel Jakub Dawidek if (lident[0] == '\0') { 163fbda685dSPawel Jakub Dawidek errno = ENOENT; 164fbda685dSPawel Jakub Dawidek return (-1); 165fbda685dSPawel Jakub Dawidek } 166fbda685dSPawel Jakub Dawidek if (strlcpy(ident, lident, size) >= size) { 167fbda685dSPawel Jakub Dawidek errno = ENAMETOOLONG; 168fbda685dSPawel Jakub Dawidek return (-1); 169fbda685dSPawel Jakub Dawidek } 170fbda685dSPawel Jakub Dawidek return (0); 171fbda685dSPawel Jakub Dawidek } 172fbda685dSPawel Jakub Dawidek 173fbda685dSPawel Jakub Dawidek /* 174fbda685dSPawel Jakub Dawidek * Return name of the provider, which has the given ID. 175fbda685dSPawel Jakub Dawidek */ 176fbda685dSPawel Jakub Dawidek int 177fbda685dSPawel Jakub Dawidek g_get_name(const char *ident, char *name, size_t size) 178fbda685dSPawel Jakub Dawidek { 179fbda685dSPawel Jakub Dawidek int fd; 180fbda685dSPawel Jakub Dawidek 181fbda685dSPawel Jakub Dawidek fd = g_open_by_ident(ident, 0, name, size); 182fbda685dSPawel Jakub Dawidek if (fd == -1) 183fbda685dSPawel Jakub Dawidek return (-1); 184fbda685dSPawel Jakub Dawidek g_close(fd); 185fbda685dSPawel Jakub Dawidek return (0); 186fbda685dSPawel Jakub Dawidek } 187fbda685dSPawel Jakub Dawidek 188fbda685dSPawel Jakub Dawidek /* 189fbda685dSPawel Jakub Dawidek * Find provider name by the given ID. 190fbda685dSPawel Jakub Dawidek */ 191fbda685dSPawel Jakub Dawidek int 1929ac6b8aeSPawel Jakub Dawidek g_open_by_ident(const char *ident, int dowrite, char *name, size_t size) 193fbda685dSPawel Jakub Dawidek { 194fbda685dSPawel Jakub Dawidek char lident[DISK_IDENT_SIZE]; 195fbda685dSPawel Jakub Dawidek struct gmesh mesh; 196fbda685dSPawel Jakub Dawidek struct gclass *mp; 197fbda685dSPawel Jakub Dawidek struct ggeom *gp; 198fbda685dSPawel Jakub Dawidek struct gprovider *pp; 199fbda685dSPawel Jakub Dawidek int error, fd; 200fbda685dSPawel Jakub Dawidek 201fbda685dSPawel Jakub Dawidek error = geom_gettree(&mesh); 202fbda685dSPawel Jakub Dawidek if (error != 0) { 203fbda685dSPawel Jakub Dawidek errno = error; 204fbda685dSPawel Jakub Dawidek return (-1); 205fbda685dSPawel Jakub Dawidek } 206fbda685dSPawel Jakub Dawidek 207fbda685dSPawel Jakub Dawidek error = ENOENT; 208fbda685dSPawel Jakub Dawidek fd = -1; 209fbda685dSPawel Jakub Dawidek 210fbda685dSPawel Jakub Dawidek LIST_FOREACH(mp, &mesh.lg_class, lg_class) { 211fbda685dSPawel Jakub Dawidek LIST_FOREACH(gp, &mp->lg_geom, lg_geom) { 212fbda685dSPawel Jakub Dawidek LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 2139ac6b8aeSPawel Jakub Dawidek fd = g_open(pp->lg_name, dowrite); 214fbda685dSPawel Jakub Dawidek if (fd == -1) 215fbda685dSPawel Jakub Dawidek continue; 216fbda685dSPawel Jakub Dawidek if (g_get_ident(fd, lident, 217fbda685dSPawel Jakub Dawidek sizeof(lident)) == -1) { 218fbda685dSPawel Jakub Dawidek g_close(fd); 219fbda685dSPawel Jakub Dawidek continue; 220fbda685dSPawel Jakub Dawidek } 221fbda685dSPawel Jakub Dawidek if (strcmp(ident, lident) != 0) { 222fbda685dSPawel Jakub Dawidek g_close(fd); 223fbda685dSPawel Jakub Dawidek continue; 224fbda685dSPawel Jakub Dawidek } 225fbda685dSPawel Jakub Dawidek error = 0; 226fbda685dSPawel Jakub Dawidek if (name != NULL && strlcpy(name, pp->lg_name, 227fbda685dSPawel Jakub Dawidek size) >= size) { 228fbda685dSPawel Jakub Dawidek error = ENAMETOOLONG; 229fbda685dSPawel Jakub Dawidek g_close(fd); 230fbda685dSPawel Jakub Dawidek } 231fbda685dSPawel Jakub Dawidek goto end; 232fbda685dSPawel Jakub Dawidek } 233fbda685dSPawel Jakub Dawidek } 234fbda685dSPawel Jakub Dawidek } 235fbda685dSPawel Jakub Dawidek end: 236fbda685dSPawel Jakub Dawidek geom_deletetree(&mesh); 237fbda685dSPawel Jakub Dawidek if (error != 0) { 238fbda685dSPawel Jakub Dawidek errno = error; 239fbda685dSPawel Jakub Dawidek return (-1); 240fbda685dSPawel Jakub Dawidek } 241fbda685dSPawel Jakub Dawidek return (fd); 242fbda685dSPawel Jakub Dawidek } 243f805f204SUlf Lilleengen 244f805f204SUlf Lilleengen /* 245f805f204SUlf Lilleengen * Return the device path device given a partial or full path to its node. 246f805f204SUlf Lilleengen * A pointer can be provided, which will be set to an opened file descriptor of 247f805f204SUlf Lilleengen * not NULL. 248f805f204SUlf Lilleengen */ 249f805f204SUlf Lilleengen static char * 250f805f204SUlf Lilleengen g_device_path_open(const char *devpath, int *fdp, int dowrite) 251f805f204SUlf Lilleengen { 252f805f204SUlf Lilleengen char *path; 253f805f204SUlf Lilleengen int fd; 254f805f204SUlf Lilleengen 255f805f204SUlf Lilleengen /* Make sure that we can fail. */ 256f805f204SUlf Lilleengen if (fdp != NULL) 257f805f204SUlf Lilleengen *fdp = -1; 258f805f204SUlf Lilleengen /* Use the device node if we're able to open it. */ 259f805f204SUlf Lilleengen do { 260f805f204SUlf Lilleengen fd = open(devpath, dowrite ? O_RDWR : O_RDONLY); 261f805f204SUlf Lilleengen if (fd == -1) 262f805f204SUlf Lilleengen break; 263f805f204SUlf Lilleengen /* 264f805f204SUlf Lilleengen * Let try to get sectorsize, which will prove it is a GEOM 265f805f204SUlf Lilleengen * provider. 266f805f204SUlf Lilleengen */ 267f805f204SUlf Lilleengen if (g_sectorsize(fd) == -1) { 268f805f204SUlf Lilleengen close(fd); 269f805f204SUlf Lilleengen errno = EFTYPE; 270f805f204SUlf Lilleengen return (NULL); 271f805f204SUlf Lilleengen } 272f805f204SUlf Lilleengen if ((path = strdup(devpath)) == NULL) { 273f805f204SUlf Lilleengen close(fd); 274f805f204SUlf Lilleengen return (NULL); 275f805f204SUlf Lilleengen } 276f805f204SUlf Lilleengen if (fdp != NULL) 277f805f204SUlf Lilleengen *fdp = fd; 278f805f204SUlf Lilleengen else 279f805f204SUlf Lilleengen close(fd); 280f805f204SUlf Lilleengen return (path); 281f805f204SUlf Lilleengen } while (0); 282f805f204SUlf Lilleengen 283f805f204SUlf Lilleengen /* If we're not given an absolute path, assume /dev/ prefix. */ 284f805f204SUlf Lilleengen if (*devpath != '/') { 285f805f204SUlf Lilleengen asprintf(&path, "%s%s", _PATH_DEV, devpath); 286f805f204SUlf Lilleengen if (path == NULL) 287f805f204SUlf Lilleengen return (NULL); 288f805f204SUlf Lilleengen fd = open(path, dowrite ? O_RDWR : O_RDONLY); 289f805f204SUlf Lilleengen if (fd == -1) { 290f805f204SUlf Lilleengen free(path); 291f805f204SUlf Lilleengen return (NULL); 292f805f204SUlf Lilleengen } 293f805f204SUlf Lilleengen /* 294f805f204SUlf Lilleengen * Let try to get sectorsize, which will prove it is a GEOM 295f805f204SUlf Lilleengen * provider. 296f805f204SUlf Lilleengen */ 297f805f204SUlf Lilleengen if (g_sectorsize(fd) == -1) { 298f805f204SUlf Lilleengen free(path); 299f805f204SUlf Lilleengen close(fd); 300f805f204SUlf Lilleengen errno = EFTYPE; 301f805f204SUlf Lilleengen return (NULL); 302f805f204SUlf Lilleengen } 303f805f204SUlf Lilleengen if (fdp != NULL) 304f805f204SUlf Lilleengen *fdp = fd; 305f805f204SUlf Lilleengen else 306f805f204SUlf Lilleengen close(fd); 307f805f204SUlf Lilleengen return (path); 308f805f204SUlf Lilleengen } 309f805f204SUlf Lilleengen return (NULL); 310f805f204SUlf Lilleengen } 311f805f204SUlf Lilleengen 312f805f204SUlf Lilleengen char * 313f805f204SUlf Lilleengen g_device_path(const char *devpath) 314f805f204SUlf Lilleengen { 315f805f204SUlf Lilleengen return (g_device_path_open(devpath, NULL, 0)); 316f805f204SUlf Lilleengen } 317