1169299Spjd/*- 2169299Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3169299Spjd * All rights reserved. 4169299Spjd * 5169299Spjd * Redistribution and use in source and binary forms, with or without 6169299Spjd * modification, are permitted provided that the following conditions 7169299Spjd * are met: 8169299Spjd * 1. Redistributions of source code must retain the above copyright 9169299Spjd * notice, this list of conditions and the following disclaimer. 10169299Spjd * 2. Redistributions in binary form must reproduce the above copyright 11169299Spjd * notice, this list of conditions and the following disclaimer in the 12169299Spjd * documentation and/or other materials provided with the distribution. 13169299Spjd * 14169299Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15169299Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169299Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169299Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18169299Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169299Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169299Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169299Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169299Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169299Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169299Spjd * SUCH DAMAGE. 25169299Spjd */ 26169299Spjd 27169299Spjd#include <sys/cdefs.h> 28169299Spjd__FBSDID("$FreeBSD$"); 29169299Spjd 30169299Spjd#include <sys/param.h> 31169299Spjd#include <sys/disk.h> 32169299Spjd#include <sys/stat.h> 33169299Spjd 34169299Spjd#include <stdio.h> 35169299Spjd#include <fcntl.h> 36169299Spjd#include <errno.h> 37169299Spjd#include <stdint.h> 38169299Spjd#include <unistd.h> 39169299Spjd#include <string.h> 40169299Spjd#include <stdlib.h> 41169299Spjd#include <paths.h> 42169299Spjd 43169299Spjd#include <libgeom.h> 44169299Spjd 45182843Slulfstatic char *g_device_path_open(const char *, int *, int); 46182843Slulf 47169299Spjd/* 48169299Spjd * Open the given provider and at least check if this is a block device. 49169299Spjd */ 50169299Spjdint 51179152Spjdg_open(const char *name, int dowrite) 52169299Spjd{ 53182843Slulf char *path; 54169299Spjd int fd; 55169299Spjd 56182843Slulf path = g_device_path_open(name, &fd, dowrite); 57182843Slulf if (path != NULL) 58182843Slulf free(path); 59169299Spjd if (fd == -1) 60169299Spjd return (-1); 61169299Spjd return (fd); 62169299Spjd} 63169299Spjd 64169299Spjdint 65169299Spjdg_close(int fd) 66169299Spjd{ 67169299Spjd 68169299Spjd return (close(fd)); 69169299Spjd} 70169299Spjd 71169299Spjdstatic int 72169299Spjdg_ioctl_arg(int fd, unsigned long cmd, void *arg) 73169299Spjd{ 74169299Spjd int ret; 75169299Spjd 76169299Spjd if (arg != NULL) 77169299Spjd ret = ioctl(fd, cmd, arg); 78169299Spjd else 79169299Spjd ret = ioctl(fd, cmd); 80169299Spjd return (ret >= 0 ? 0 : -1); 81169299Spjd} 82169299Spjd 83169299Spjdstatic int 84169299Spjdg_ioctl(int fd, unsigned long cmd) 85169299Spjd{ 86169299Spjd 87169299Spjd return (g_ioctl_arg(fd, cmd, NULL)); 88169299Spjd} 89169299Spjd 90169299Spjd/* 91169299Spjd * Return media size of the given provider. 92169299Spjd */ 93169299Spjdoff_t 94169299Spjdg_mediasize(int fd) 95169299Spjd{ 96169299Spjd off_t mediasize; 97169299Spjd 98169299Spjd if (g_ioctl_arg(fd, DIOCGMEDIASIZE, &mediasize) == -1) 99169299Spjd mediasize = -1; 100169299Spjd return (mediasize); 101169299Spjd} 102169299Spjd 103169299Spjd/* 104169299Spjd * Return sector size of the given provider. 105169299Spjd */ 106169299Spjdssize_t 107169299Spjdg_sectorsize(int fd) 108169299Spjd{ 109169299Spjd u_int sectorsize; 110169299Spjd 111169299Spjd if (g_ioctl_arg(fd, DIOCGSECTORSIZE, §orsize) == -1) 112169299Spjd return (-1); 113169299Spjd return ((ssize_t)sectorsize); 114169299Spjd} 115169299Spjd 116169299Spjd/* 117202454Sdelphij * Return stripe size of the given provider. 118202454Sdelphij */ 119202454Sdelphijoff_t 120202454Sdelphijg_stripesize(int fd) 121202454Sdelphij{ 122202454Sdelphij off_t stripesize; 123202454Sdelphij 124202454Sdelphij if (g_ioctl_arg(fd, DIOCGSTRIPESIZE, &stripesize) == -1) 125202454Sdelphij return (-1); 126202454Sdelphij return (stripesize); 127202454Sdelphij} 128202454Sdelphij 129202454Sdelphij/* 130202454Sdelphij * Return stripe size of the given provider. 131202454Sdelphij */ 132202454Sdelphijoff_t 133202454Sdelphijg_stripeoffset(int fd) 134202454Sdelphij{ 135202454Sdelphij off_t stripeoffset; 136202454Sdelphij 137202454Sdelphij if (g_ioctl_arg(fd, DIOCGSTRIPEOFFSET, &stripeoffset) == -1) 138202454Sdelphij return (-1); 139202454Sdelphij return (stripeoffset); 140202454Sdelphij} 141202454Sdelphij 142202454Sdelphij/* 143182843Slulf * Return the correct provider name. 144182843Slulf */ 145182843Slulfchar * 146182843Slulfg_providername(int fd) 147182843Slulf{ 148182843Slulf char name[MAXPATHLEN]; 149182843Slulf 150182843Slulf if (g_ioctl_arg(fd, DIOCGPROVIDERNAME, name) == -1) 151182843Slulf return (NULL); 152182843Slulf return (strdup(name)); 153182843Slulf} 154182843Slulf 155182843Slulf/* 156169299Spjd * Call BIO_FLUSH for the given provider. 157169299Spjd */ 158169299Spjdint 159169299Spjdg_flush(int fd) 160169299Spjd{ 161169299Spjd 162169299Spjd return (g_ioctl(fd, DIOCGFLUSH)); 163169299Spjd} 164169299Spjd 165169299Spjd/* 166169299Spjd * Call BIO_DELETE for the given range. 167169299Spjd */ 168169299Spjdint 169169299Spjdg_delete(int fd, off_t offset, off_t length) 170169299Spjd{ 171169299Spjd off_t arg[2]; 172169299Spjd 173169299Spjd arg[0] = offset; 174169299Spjd arg[1] = length; 175169299Spjd return (g_ioctl_arg(fd, DIOCGDELETE, arg)); 176169299Spjd} 177169299Spjd 178169299Spjd/* 179169299Spjd * Return ID of the given provider. 180169299Spjd */ 181169299Spjdint 182169299Spjdg_get_ident(int fd, char *ident, size_t size) 183169299Spjd{ 184169299Spjd char lident[DISK_IDENT_SIZE]; 185169299Spjd 186169299Spjd if (g_ioctl_arg(fd, DIOCGIDENT, lident) == -1) 187169299Spjd return (-1); 188169299Spjd if (lident[0] == '\0') { 189169299Spjd errno = ENOENT; 190169299Spjd return (-1); 191169299Spjd } 192169299Spjd if (strlcpy(ident, lident, size) >= size) { 193169299Spjd errno = ENAMETOOLONG; 194169299Spjd return (-1); 195169299Spjd } 196169299Spjd return (0); 197169299Spjd} 198169299Spjd 199169299Spjd/* 200169299Spjd * Return name of the provider, which has the given ID. 201169299Spjd */ 202169299Spjdint 203169299Spjdg_get_name(const char *ident, char *name, size_t size) 204169299Spjd{ 205169299Spjd int fd; 206169299Spjd 207169299Spjd fd = g_open_by_ident(ident, 0, name, size); 208169299Spjd if (fd == -1) 209169299Spjd return (-1); 210169299Spjd g_close(fd); 211169299Spjd return (0); 212169299Spjd} 213169299Spjd 214169299Spjd/* 215169299Spjd * Find provider name by the given ID. 216169299Spjd */ 217169299Spjdint 218179152Spjdg_open_by_ident(const char *ident, int dowrite, char *name, size_t size) 219169299Spjd{ 220169299Spjd char lident[DISK_IDENT_SIZE]; 221169299Spjd struct gmesh mesh; 222169299Spjd struct gclass *mp; 223169299Spjd struct ggeom *gp; 224169299Spjd struct gprovider *pp; 225169299Spjd int error, fd; 226169299Spjd 227169299Spjd error = geom_gettree(&mesh); 228169299Spjd if (error != 0) { 229169299Spjd errno = error; 230169299Spjd return (-1); 231169299Spjd } 232169299Spjd 233169299Spjd error = ENOENT; 234169299Spjd fd = -1; 235169299Spjd 236169299Spjd LIST_FOREACH(mp, &mesh.lg_class, lg_class) { 237169299Spjd LIST_FOREACH(gp, &mp->lg_geom, lg_geom) { 238169299Spjd LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 239179152Spjd fd = g_open(pp->lg_name, dowrite); 240169299Spjd if (fd == -1) 241169299Spjd continue; 242169299Spjd if (g_get_ident(fd, lident, 243169299Spjd sizeof(lident)) == -1) { 244169299Spjd g_close(fd); 245169299Spjd continue; 246169299Spjd } 247169299Spjd if (strcmp(ident, lident) != 0) { 248169299Spjd g_close(fd); 249169299Spjd continue; 250169299Spjd } 251169299Spjd error = 0; 252169299Spjd if (name != NULL && strlcpy(name, pp->lg_name, 253169299Spjd size) >= size) { 254169299Spjd error = ENAMETOOLONG; 255169299Spjd g_close(fd); 256169299Spjd } 257169299Spjd goto end; 258169299Spjd } 259169299Spjd } 260169299Spjd } 261169299Spjdend: 262169299Spjd geom_deletetree(&mesh); 263169299Spjd if (error != 0) { 264169299Spjd errno = error; 265169299Spjd return (-1); 266169299Spjd } 267169299Spjd return (fd); 268169299Spjd} 269182843Slulf 270182843Slulf/* 271182843Slulf * Return the device path device given a partial or full path to its node. 272182843Slulf * A pointer can be provided, which will be set to an opened file descriptor of 273182843Slulf * not NULL. 274182843Slulf */ 275182843Slulfstatic char * 276182843Slulfg_device_path_open(const char *devpath, int *fdp, int dowrite) 277182843Slulf{ 278182843Slulf char *path; 279182843Slulf int fd; 280182843Slulf 281182843Slulf /* Make sure that we can fail. */ 282182843Slulf if (fdp != NULL) 283182843Slulf *fdp = -1; 284182843Slulf /* Use the device node if we're able to open it. */ 285182843Slulf do { 286182843Slulf fd = open(devpath, dowrite ? O_RDWR : O_RDONLY); 287182843Slulf if (fd == -1) 288182843Slulf break; 289182843Slulf /* 290182843Slulf * Let try to get sectorsize, which will prove it is a GEOM 291182843Slulf * provider. 292182843Slulf */ 293182843Slulf if (g_sectorsize(fd) == -1) { 294182843Slulf close(fd); 295182843Slulf errno = EFTYPE; 296182843Slulf return (NULL); 297182843Slulf } 298182843Slulf if ((path = strdup(devpath)) == NULL) { 299182843Slulf close(fd); 300182843Slulf return (NULL); 301182843Slulf } 302182843Slulf if (fdp != NULL) 303182843Slulf *fdp = fd; 304182843Slulf else 305182843Slulf close(fd); 306182843Slulf return (path); 307182843Slulf } while (0); 308182843Slulf 309182843Slulf /* If we're not given an absolute path, assume /dev/ prefix. */ 310182843Slulf if (*devpath != '/') { 311182843Slulf asprintf(&path, "%s%s", _PATH_DEV, devpath); 312182843Slulf if (path == NULL) 313182843Slulf return (NULL); 314182843Slulf fd = open(path, dowrite ? O_RDWR : O_RDONLY); 315182843Slulf if (fd == -1) { 316182843Slulf free(path); 317182843Slulf return (NULL); 318182843Slulf } 319182843Slulf /* 320182843Slulf * Let try to get sectorsize, which will prove it is a GEOM 321182843Slulf * provider. 322182843Slulf */ 323182843Slulf if (g_sectorsize(fd) == -1) { 324182843Slulf free(path); 325182843Slulf close(fd); 326182843Slulf errno = EFTYPE; 327182843Slulf return (NULL); 328182843Slulf } 329182843Slulf if (fdp != NULL) 330182843Slulf *fdp = fd; 331182843Slulf else 332182843Slulf close(fd); 333182843Slulf return (path); 334182843Slulf } 335182843Slulf return (NULL); 336182843Slulf} 337182843Slulf 338182843Slulfchar * 339182843Slulfg_device_path(const char *devpath) 340182843Slulf{ 341182843Slulf return (g_device_path_open(devpath, NULL, 0)); 342182843Slulf} 343