Date: Sat, 2 Dec 2017 12:22:17 +0100 From: "O. Hartmann" <ohartmann@walstatt.org> To: Warner Losh <imp@FreeBSD.org> Cc: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r326458 - head/lib/libefivar Message-ID: <20171202122217.4e40a80f@thor.intern.walstatt.dynvpn.de> In-Reply-To: <201712020729.vB27TJTE015093@repo.freebsd.org> References: <201712020729.vB27TJTE015093@repo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--Sig_/AveLuR8PmdXW5NE4YkT/Zgu Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Am Sat, 2 Dec 2017 07:29:19 +0000 (UTC) Warner Losh <imp@FreeBSD.org> schrieb: > Author: imp > Date: Sat Dec 2 07:29:19 2017 > New Revision: 326458 > URL: https://svnweb.freebsd.org/changeset/base/326458 >=20 > Log: > Create a function to translate UEFI paths to unix paths > =20 > efivar_device_path_to_unix_path translates from UEFI to Unix > efivar_unix_path_to_device_path translates from Unix to UEFI > =20 > At present, only HD() device types are supported (both GPT and > MBR). CdRom and floppy devices aren't supported. ZFS isn't supported > because there's no way in the UEFI standard to specify a ZFS datastore. > Network devices aren't supported either. > =20 > Three forms of Unix path are accepted: /path/to/file (for a mounted > filesystem), //path/to/file (uses the EFI partition on the same disk > as /), and dev:/path/to/file (for unmounted filesystem). Two forms are > produced (the first and last). > =20 > Sponsored by: Netflix >=20 > Added: > head/lib/libefivar/efivar-dp-xlate.c (contents, props changed) > Modified: > head/lib/libefivar/Makefile > head/lib/libefivar/efivar-dp-format.c > head/lib/libefivar/efivar-dp.h >=20 > Modified: head/lib/libefivar/Makefile > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/lib/libefivar/Makefile Sat Dec 2 07:29:07 2017 (r326457) > +++ head/lib/libefivar/Makefile Sat Dec 2 07:29:19 2017 (r326458) > @@ -35,6 +35,7 @@ PACKAGE=3Dlib${LIB} > LIB=3D efivar > SRCS=3D efivar.c efichar.c efivar-dp-format.c \ > efivar-dp-parse.c \ > + efivar-dp-xlate.c \ > uefi-guid.c uefi-dputil.c > INCS=3D efivar.h efivar-dp.h > SHLIB_MAJOR=3D 1 >=20 > Modified: head/lib/libefivar/efivar-dp-format.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/lib/libefivar/efivar-dp-format.c Sat Dec 2 07:29:07 2017 > (r326457) +++ head/lib/libefivar/efivar-dp-format.c Sat Dec 2 07:29:19 > 2017 (r326458) @@ -2432,7 +2432,7 @@ efidp_format_device_path(char *buf, = size_t > len, const_ } > =20 > ssize_t > -efidp_format_device_path_node(char *buf, size_t len, const_efidp dp, ssi= ze_t max) > +efidp_format_device_path_node(char *buf, size_t len, const_efidp dp) > { > char *str; > ssize_t retval; > @@ -2453,4 +2453,15 @@ efidp_size(const_efidp dp) > { > =20 > return GetDevicePathSize(__DECONST(EFI_DEVICE_PATH_PROTOCOL *, dp)); > +} > + > +char * > +efidp_extract_file_path(const_efidp dp) > +{ > + const FILEPATH_DEVICE_PATH *fp; > + char *name =3D NULL; > + > + fp =3D (const void *)dp; > + ucs2_to_utf8(fp->PathName, &name); > + return name; > } >=20 > Added: head/lib/libefivar/efivar-dp-xlate.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/lib/libefivar/efivar-dp-xlate.c Sat Dec 2 07:29:19 2017 > (r326458) @@ -0,0 +1,715 @@ > +/*- > + * Copyright (c) 2017 Netflix, Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer > + * in this position and unchanged. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distributio= n. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRAN= TIES > + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIME= D. > + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, = BUT > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF = USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE= OF > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include <sys/cdefs.h> > +__FBSDID("$FreeBSD$"); > + > +#include <sys/param.h> > +#include <sys/ucred.h> > +#include <sys/mount.h> > + > +#undef MAX > +#undef MIN > + > +#include <assert.h> > +#include <efivar.h> > +#include <errno.h> > +#include <libgeom.h> > +#include <paths.h> > +#include <stdio.h> > +#include <string.h> > + > +#include "efichar.h" > + > +#include "efi-osdep.h" > +#include "efivar-dp.h" > + > +#include "uefi-dplib.h" > + > +#define MAX_DP_SANITY 4096 /* Biggest device path in bytes */ > +#define MAX_DP_TEXT_LEN 4096 /* Longest string rep of dp */ > + > +#define G_PART "PART" > +#define G_LABEL "LABEL" > +#define G_DISK "DISK" > + > +static const char * > +geom_pp_attr(struct gmesh *mesh, struct gprovider *pp, const char *attr) > +{ > + struct gconfig *conf; > + > + LIST_FOREACH(conf, &pp->lg_config, lg_config) { > + if (strcmp(conf->lg_name, attr) !=3D 0) > + continue; > + return (conf->lg_val); > + } > + return (NULL); > +} > + > +static struct gprovider * > +find_provider_by_efimedia(struct gmesh *mesh, const char *efimedia) > +{ > + struct gclass *classp; > + struct ggeom *gp; > + struct gprovider *pp; > + const char *val; > + > + /* > + * Find the partition class so we can search it... > + */ > + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { > + if (strcasecmp(classp->lg_name, G_PART) =3D=3D 0) > + break; > + } > + if (classp =3D=3D NULL) > + return (NULL); > + > + /* > + * Each geom will have a number of providers, search each > + * one of them for the efimedia that matches. > + */ > + /* XXX just used gpart class since I know it's the only one, but maybe I > should search all classes */ > + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { > + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { > + val =3D geom_pp_attr(mesh, pp, "efimedia"); > + if (val =3D=3D NULL) > + continue; > + if (strcasecmp(efimedia, val) =3D=3D 0) > + return (pp); > + } > + } > + > + return (NULL); > +} > + > +static struct gprovider * > +find_provider_by_name(struct gmesh *mesh, const char *name) > +{ > + struct gclass *classp; > + struct ggeom *gp; > + struct gprovider *pp; > + > + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { > + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { > + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { > + if (strcmp(pp->lg_name, name) =3D=3D 0) > + return (pp); > + } > + } > + } > + > + return (NULL); > +} > + > + > +static int > +efi_hd_to_unix(struct gmesh *mesh, const_efidp dp, char **dev, char **re= lpath, char > **abspath) +{ > + int rv =3D 0, n, i; > + const_efidp media, file, walker; > + size_t len, mntlen; > + char buf[MAX_DP_TEXT_LEN]; > + char *pwalk; > + struct gprovider *pp, *provider; > + struct gconsumer *cp; > + struct statfs *mnt; > + > + walker =3D media =3D dp; > + > + /* > + * Now, we can either have a filepath node next, or the end. > + * Otherwise, it's an error. > + */ > + walker =3D (const_efidp)NextDevicePathNode(walker); > + if ((uintptr_t)walker - (uintptr_t)dp > MAX_DP_SANITY) > + return (EINVAL); > + if (DevicePathType(walker) =3D=3D MEDIA_DEVICE_PATH && > + DevicePathSubType(walker) =3D=3D MEDIA_FILEPATH_DP) > + file =3D walker; > + else if (DevicePathType(walker) =3D=3D MEDIA_DEVICE_PATH && > + DevicePathType(walker) =3D=3D END_DEVICE_PATH_TYPE) > + file =3D NULL; > + else > + return (EINVAL); > + > + /* > + * Format this node. We're going to look for it as a efimedia > + * attribute of some geom node. Once we find that node, we use it > + * as the device it comes from, at least provisionally. > + */ > + len =3D efidp_format_device_path_node(buf, sizeof(buf), media); > + if (len > sizeof(buf)) > + return (EINVAL); > + > + pp =3D find_provider_by_efimedia(mesh, buf); > + if (pp =3D=3D NULL) { > + rv =3D ENOENT; > + goto errout; > + } > + > + *dev =3D strdup(pp->lg_name); > + if (*dev =3D=3D NULL) { > + rv =3D ENOMEM; > + goto errout; > + } > + > + /* > + * No file specified, just return the device. Don't even look > + * for a mountpoint. XXX Sane? > + */ > + if (file =3D=3D NULL) > + goto errout; > + > + /* > + * Now extract the relative path. The next node in the device path shou= ld > + * be a filesystem node. If not, we have issues. > + */ > + *relpath =3D efidp_extract_file_path(file); > + if (*relpath =3D=3D NULL) { > + rv =3D ENOMEM; > + goto errout; > + } > + for (pwalk =3D *relpath; *pwalk; pwalk++) > + if (*pwalk =3D=3D '\\') > + *pwalk =3D '/'; > + > + /* > + * To find the absolute path, we have to look for where we're mounted. > + * We only look a little hard, since looking too hard can come up with > + * false positives (imagine a graid, one of whose devices is *dev). > + */ > + n =3D getfsstat(NULL, 0, MNT_NOWAIT) + 1; > + if (n < 0) { > + rv =3D errno; > + goto errout; > + } > + mntlen =3D sizeof(struct statfs) * n; > + mnt =3D malloc(mntlen); > + n =3D getfsstat(mnt, mntlen, MNT_NOWAIT); > + if (n < 0) { > + rv =3D errno; > + goto errout; > + } > + provider =3D pp; > + for (i =3D 0; i < n; i++) { > + /* > + * Skip all pseudo filesystems. This also skips the real filesytsem > + * of ZFS. There's no EFI designator for ZFS in the standard, so > + * we'll need to invent one, but its decoding will be handled in > + * a separate function. > + */ > + if (mnt[i].f_mntfromname[0] !=3D '/') > + continue; > + > + /* > + * First see if it is directly attached > + */ > + if (strcmp(provider->lg_name, mnt[i].f_mntfromname + 5) =3D=3D 0) > + break; > + > + /* > + * Next see if it is attached via one of the physical disk's > + * labels. > + */ > + LIST_FOREACH(cp, &provider->lg_consumers, lg_consumer) { > + pp =3D cp->lg_provider; > + if (strcmp(pp->lg_geom->lg_class->lg_name, G_LABEL) !=3D 0) > + continue; > + if (strcmp(g_device_path(pp->lg_name), mnt[i].f_mntfromname) > =3D=3D 0) > + goto break2; > + } > + /* Not the one, try the next mount point */ > + } > +break2: > + > + /* > + * No mountpoint found, no absolute path possible > + */ > + if (i >=3D n) > + goto errout; > + > + /* > + * Construct absolute path and we're finally done. > + */ > + if (strcmp(mnt[i].f_mntonname, "/") =3D=3D 0) > + asprintf(abspath, "/%s", *relpath); > + else > + asprintf(abspath, "%s/%s", mnt[i].f_mntonname, *relpath); > + > +errout: > + if (rv !=3D 0) { > + free(*dev); > + *dev =3D NULL; > + free(*relpath); > + *relpath =3D NULL; > + } > + return (rv); > +} > + > +/* > + * Translate the passed in device_path to a unix path via the following > + * algorithm. > + * > + * If dp, dev or path NULL, return EDOOFUS. XXX wise? > + * > + * Set *path =3D NULL; *dev =3D NULL; > + * > + * Walk through the device_path until we find either a media device path. > + * Return EINVAL if not found. Return EINVAL if walking dp would > + * land us more than sanity size away from the start (4k). > + * > + * If we find a media descriptor, we search through the geom mesh to see= if we > + * can find a matching node. If no match is found in the mesh that match= es, > + * return ENXIO. > + * > + * Once we find a matching node, we search to see if there is a filesyst= em > + * mounted on it. If we find nothing, then search each of the devices th= at are > + * mounted to see if we can work up the geom tree to find the matching n= ode. if > + * we still can't find anything, *dev =3D sprintf("/dev/%s", provider_na= me > + * of the original node we found), but return ENOTBLK. > + * > + * Record the dev of the mountpoint in *dev. > + * > + * Once we find something, check to see if the next node in the device p= ath is > + * the end of list. If so, return the mountpoint. > + * > + * If the next node isn't a File path node, return EFTYPE. > + * > + * Extract the path from the File path node(s). translate any \ file sep= arators > + * to /. Append the result to the mount point. Copy the resulting path i= nto > + * *path. Stat that path. If it is not found, return the errorr from st= at. > + * > + * Finally, check to make sure the resulting path is still on the same > + * device. If not, return ENODEV. > + * > + * Otherwise return 0. > + * > + * The dev or full path that's returned is malloced, so needs to be free= d when > + * the caller is done about it. Unlike many other functions, we can retu= rn data > + * with an error code, so pay attention. > + */ > +int > +efivar_device_path_to_unix_path(const_efidp dp, char **dev, char **relpa= th, char > **abspath) +{ > + const_efidp walker; > + struct gmesh mesh; > + int rv =3D 0; > + > + /* > + * Sanity check args, fail early > + */ > + if (dp =3D=3D NULL || dev =3D=3D NULL || relpath =3D=3D NULL || abspath= =3D=3D NULL) > + return (EDOOFUS); > + > + *dev =3D NULL; > + *relpath =3D NULL; > + *abspath =3D NULL; > + > + /* > + * Find the first media device path we can. If we go too far, > + * assume the passed in device path is bogus. If we hit the end > + * then we didn't find a media device path, so signal that error. > + */ > + walker =3D dp; > + while (DevicePathType(walker) !=3D MEDIA_DEVICE_PATH && > + DevicePathType(walker) !=3D END_DEVICE_PATH_TYPE) { > + walker =3D (const_efidp)NextDevicePathNode(walker); > + if ((uintptr_t)walker - (uintptr_t)dp > MAX_DP_SANITY) > + return (EINVAL); > + } > + if (DevicePathType(walker) !=3D MEDIA_DEVICE_PATH) > + return (EINVAL); > + > + /* > + * There's several types of media paths. We're only interested in the > + * hard disk path, as it's really the only relevant one to booting. The > + * CD path just might also be relevant, and would be easy to add, but > + * isn't supported. A file path too is relevant, but at this stage, it's > + * premature because we're trying to translate a specification for a de= vice > + * and path on that device into a unix path, or at the very least, a > + * geom device : path-on-device. > + * > + * Also, ZFS throws a bit of a monkey wrench in here since it doesn't h= ave > + * a device path type (it creates a new virtual device out of one or mo= re > + * storage devices). > + * > + * For all of them, we'll need to know the geoms, so allocate / free the > + * geom mesh here since it's safer than doing it in each sub-function > + * which may have many error exits. > + */ > + if (geom_gettree(&mesh)) > + return (ENOMEM); > + > + rv =3D EINVAL; > + if (DevicePathSubType(walker) =3D=3D MEDIA_HARDDRIVE_DP) > + rv =3D efi_hd_to_unix(&mesh, walker, dev, relpath, abspath); > +#ifdef notyet > + else if (is_cdrom_device(walker)) > + rv =3D efi_cdrom_to_unix(&mesh, walker, dev, relpath, abspath); > + else if (is_floppy_device(walker)) > + rv =3D efi_floppy_to_unix(&mesh, walker, dev, relpath, abspath); > + else if (is_zpool_device(walker)) > + rv =3D efi_zpool_to_unix(&mesh, walker, dev, relpath, abspath); > +#endif > + geom_deletetree(&mesh); > + > + return (rv); > +} > + > +/* > + * Construct the EFI path to a current unix path as follows. > + * > + * The path may be of one of three forms: > + * 1) /path/to/file -- full path to a file. The file need not be present, > + * but /path/to must be. It must reside on a local filesystem > + * mounted on a GPT or MBR partition. > + * 2) //path/to/file -- Shorthand for 'On the EFI partition, \path\to\fi= le' > + * where 'The EFI Partition' is a partiton that's type is 'efi' > + * on the same disk that / is mounted from. If there are multiple > + * or no 'efi' parittions on that disk, or / isn't on a disk that > + * we can trace back to a physical device, an error will result > + * 3) [/dev/]geom-name:/path/to/file -- Use the specified partition > + * (and it must be a GPT or MBR partition) with the specified > + * path. The latter is not authenticated. > + * all path forms translate any \ characters to / before further process= ing. > + * When a file path node is created, all / characters are translated back > + * to \. > + * > + * For paths of the first form: > + * find where the filesystem is mount (either the file directly, or > + * its parent directory). > + * translate any logical device name (eg lable) to a physical one > + * If not possible, return ENXIO > + * If the physical path is unsupported (Eg not on a GPT or MBR disk), > + * return ENXIO > + * Create a media device path node. > + * append the relative path from the mountpoint to the media device node > + * as a file path. > + * > + * For paths matching the second form: > + * find the EFI partition corresponding to the root fileystem. > + * If none found, return ENXIO > + * Create a media device path node for the found partition > + * Append a File Path to the end for the rest of the file. > + * > + * For paths of the third form > + * Translate the geom-name passed in into a physical partition > + * name. > + * Return ENXIO if the translation fails > + * Make a media device path for it > + * append the part after the : as a File path node. > + */ > + > +static char * > +path_to_file_dp(const char *relpath) > +{ > + char *rv; > + > + asprintf(&rv, "File(%s)", relpath); > + return rv; > +} > + > +static char * > +find_geom_efi_on_root(struct gmesh *mesh) > +{ > + struct statfs buf; > + const char *dev; > + struct gprovider *pp; > +// struct ggeom *disk; > + struct gconsumer *cp; > + > + /* > + * Find /'s geom. Assume it's mounted on /dev/ and filter out all the > + * filesystems that aren't. > + */ > + if (statfs("/", &buf) !=3D 0) > + return (NULL); > + dev =3D buf.f_mntfromname; > + if (*dev !=3D '/' || strncmp(dev, _PATH_DEV, sizeof(_PATH_DEV) - 1) != =3D 0) > + return (NULL); > + dev +=3D sizeof(_PATH_DEV) -1; > + pp =3D find_provider_by_name(mesh, dev); > + if (pp =3D=3D NULL) > + return (NULL); > + > + /* > + * If the provider is a LABEL, find it's outer PART class, if any. We > + * only operate on partitions. > + */ > + if (strcmp(pp->lg_geom->lg_class->lg_name, G_LABEL) =3D=3D 0) { > + LIST_FOREACH(cp, &pp->lg_consumers, lg_consumer) { > + if (strcmp(cp->lg_provider->lg_geom->lg_class->lg_name, > G_PART) =3D=3D 0) { > + pp =3D cp->lg_provider; > + break; > + } > + } > + } > + if (strcmp(pp->lg_geom->lg_class->lg_name, G_PART) !=3D 0) > + return (NULL); > + > +#if 0 > + /* This doesn't work because we can't get the data to walk UP the tree = it > seems */ + > + /* > + * Now that we've found the PART that we have mounted as root, find the > + * first efi typed partition that's a peer, if any. > + */ > + LIST_FOREACH(cp, &pp->lg_consumers, lg_consumer) { > + if (strcmp(cp->lg_provider->lg_geom->lg_class->lg_name, G_DISK) =3D=3D= 0) { > + disk =3D cp->lg_provider->lg_geom; > + break; > + } > + } > + if (disk =3D=3D NULL) /* This is very bad -- old nested partitions -- no > support ? */ > + return (NULL); > +#endif > + > +#if 0 > + /* This doesn't work because we can't get the data to walk UP the tree = it > seems */ + > + /* > + * With the disk provider, we can look for its consumers to see if any = are the > proper type. > + */ > + LIST_FOREACH(pp, &disk->lg_consumer, lg_consumer) { > + type =3D geom_pp_attr(mesh, pp, "type"); > + if (type =3D=3D NULL) > + continue; > + if (strcmp(type, "efi") !=3D 0) > + continue; > + efimedia =3D geom_pp_attr(mesh, pp, "efimedia"); > + if (efimedia =3D=3D NULL) > + return (NULL); > + return strdup(efimedia); > + } > +#endif > + return (NULL); > +} > + > + > +static char * > +find_geom_efimedia(struct gmesh *mesh, const char *dev) > +{ > + struct gprovider *pp; > + const char *efimedia; > + > + pp =3D find_provider_by_name(mesh, dev); > + if (pp =3D=3D NULL) > + return (NULL); > + efimedia =3D geom_pp_attr(mesh, pp, "efimedia"); > + if (efimedia =3D=3D NULL) > + return (NULL); > + return strdup(efimedia); > +} > + > +static int > +build_dp(const char *efimedia, const char *relpath, efidp *dp) > +{ > + char *fp, *dptxt =3D NULL; > + int rv =3D 0; > + efidp out; > + size_t len; > + > + fp =3D path_to_file_dp(relpath); > + if (fp =3D=3D NULL) { > + rv =3D ENOMEM; > + goto errout; > + } > + > + asprintf(&dptxt, "%s/%s", efimedia, fp); > + out =3D malloc(8192); > + len =3D efidp_parse_device_path(dptxt, out, 8192); > + if (len > 8192) { > + rv =3D ENOMEM; > + goto errout; > + } > + if (len =3D=3D 0) { > + rv =3D EINVAL; > + goto errout; > + } > + > + *dp =3D out; > +errout: > + if (rv) { > + free(out); > + } > + free(dptxt); > + free(fp); > + > + return rv; > +} > + > +/* Handles //path/to/file */ > +/* > + * Which means: find the disk that has /. Then look for a EFI partition > + * and use that for the efimedia and /path/to/file as relative to that. > + * Not sure how ZFS will work here since we can't easily make the leap > + * to the geom from the zpool. > + */ > +static int > +efipart_to_dp(struct gmesh *mesh, char *path, efidp *dp) > +{ > + char *efimedia =3D NULL; > + int rv; > + > + efimedia =3D find_geom_efi_on_root(mesh); > +#ifdef notyet > + if (efimedia =3D=3D NULL) > + efimedia =3D find_efi_on_zfsroot(dev); > +#endif > + if (efimedia =3D=3D NULL) { > + rv =3D ENOENT; > + goto errout; > + } > + > + rv =3D build_dp(efimedia, path + 1, dp); > +errout: > + free(efimedia); > + > + return rv; > +} > + > +/* Handles [/dev/]geom:[/]path/to/file */ > +/* Handles zfs-dataset:[/]path/to/file (this may include / ) */ > +static int > +dev_path_to_dp(struct gmesh *mesh, char *path, efidp *dp) > +{ > + char *relpath, *dev, *efimedia =3D NULL; > + int rv =3D 0; > + > + relpath =3D strchr(path, ':'); > + assert(relpath !=3D NULL); > + *relpath++ =3D '\0'; > + > + dev =3D path; > + if (strncmp(dev, _PATH_DEV, sizeof(_PATH_DEV) - 1) =3D=3D 0) > + dev +=3D sizeof(_PATH_DEV) -1; > + > + efimedia =3D find_geom_efimedia(mesh, dev); > +#ifdef notyet > + if (efimedia =3D=3D NULL) > + find_zfs_efi_media(dev); > +#endif > + if (efimedia =3D=3D NULL) { > + rv =3D ENOENT; > + goto errout; > + } > + rv =3D build_dp(efimedia, relpath, dp); > +errout: > + free(efimedia); > + > + return rv; > +} > + > +/* Handles /path/to/file */ > +static int > +path_to_dp(struct gmesh *mesh, char *path, efidp *dp) > +{ > + struct statfs buf; > + char *rp =3D NULL, *ep, *dev, *efimedia =3D NULL; > + int rv =3D 0; > + > + rp =3D realpath(path, NULL); > + if (rp =3D=3D NULL) { > + rv =3D errno; > + goto errout; > + } > + > + if (statfs(rp, &buf) !=3D 0) { > + rv =3D errno; > + goto errout; > + } > + > + dev =3D buf.f_mntfromname; > + if (strncmp(dev, _PATH_DEV, sizeof(_PATH_DEV) - 1) =3D=3D 0) > + dev +=3D sizeof(_PATH_DEV) -1; > + ep =3D rp + strlen(buf.f_mntonname); > + > + efimedia =3D find_geom_efimedia(mesh, dev); > +#ifdef notyet > + if (efimedia =3D=3D NULL) > + find_zfs_efi_media(dev); > +#endif > + if (efimedia =3D=3D NULL) { > + rv =3D ENOENT; > + goto errout; > + } > + > + rv =3D build_dp(efimedia, ep, dp); > +errout: > + free(efimedia); > + free(rp); > + if (rv !=3D 0) { > + free(*dp); > + } > + return (rv); > +} > + > +int > +efivar_unix_path_to_device_path(const char *path, efidp *dp) > +{ > + char *modpath =3D NULL, *cp; > + int rv =3D ENOMEM; > + struct gmesh mesh; > + > + /* > + * Fail early for clearly bogus things > + */ > + if (path =3D=3D NULL || dp =3D=3D NULL) > + return (EDOOFUS); > + > + /* > + * We'll need the goem mesh to grovel through it to find the > + * efimedia attribute for any devices we find. Grab it here > + * and release it to simplify the error paths out of the > + * subordinate functions > + */ > + if (geom_gettree(&mesh)) > + return (errno); > + > + /* > + * Convert all \ to /. We'll convert them back again when > + * we encode the file. Boot loaders are expected to cope. > + */ > + modpath =3D strdup(path); > + if (modpath =3D=3D NULL) > + goto out; > + for (cp =3D modpath; *cp; cp++) > + if (*cp =3D=3D '\\') > + *cp =3D '/'; > + > + if (modpath[0] =3D=3D '/' && modpath[1] =3D=3D '/') /* Handle //foo/bar= /baz */ > + rv =3D efipart_to_dp(&mesh, modpath, dp); > + else if (strchr(modpath, ':')) /* Handle dev:/bar/baz */ > + rv =3D dev_path_to_dp(&mesh, modpath, dp); > + else /* Handle /a/b/c */ > + rv =3D path_to_dp(&mesh, modpath, dp); > + > +out: > + geom_deletetree(&mesh); > + free(modpath); > + > + return (rv); > +} >=20 > Modified: head/lib/libefivar/efivar-dp.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/lib/libefivar/efivar-dp.h Sat Dec 2 07:29:07 2017 (r326457) > +++ head/lib/libefivar/efivar-dp.h Sat Dec 2 07:29:19 2017 (r326458) > @@ -60,10 +60,13 @@ typedef const efidp_data *const_efidp; > */ > ssize_t efidp_format_device_path(char *buf, size_t len, const_efidp dp, > ssize_t max); > -ssize_t efidp_format_device_path_node(char *buf, size_t len, const_efidp= dp, > - ssize_t max); > +ssize_t efidp_format_device_path_node(char *buf, size_t len, const_efidp= dp); > ssize_t efidp_parse_device_path(char *path, efidp out, size_t max); > +char * efidp_extract_file_path(const_efidp dp); > =20 > size_t efidp_size(const_efidp); > + > +int efivar_device_path_to_unix_path(const_efidp dp, char **dev, char **r= elpath, char > **abspath); +int efivar_unix_path_to_device_path(const char *path, efidp = *dp); > =20 > #endif /* _EFIVAR_DP_H_ */ > _______________________________________________ > svn-src-head@freebsd.org mailing list > https://lists.freebsd.org/mailman/listinfo/svn-src-head > To unsubscribe, send any mail to "svn-src-head-unsubscribe@freebsd.org" It seems this broke buildworld, as my attempt to build fails with this erro= r on r326459: [...] Building /usr/obj/usr/src/amd64.amd64/usr.sbin/bsnmpd/modules/snmp_pf/pf_sn= mp.pico --- all_subdir_usr.sbin/efivar --- --- efivar --- /usr/obj/usr/src/amd64.amd64/tmp/usr/lib/libefivar.so: undefined reference = to `geom_deletetree' /usr/obj/usr/src/amd64.amd64/tmp/usr/lib/libefivar.so: un= defined reference to `g_device_path' /usr/obj/usr/src/amd64.amd64/tmp/usr/lib/libef= ivar.so: undefined reference to `geom_gettree' cc: error: linker command failed with= exit code 1 (use -v to see invocation) *** [efivar] Error code 1 make[4]: stopped in /usr/src/usr.sbin/efivar .ERROR_TARGET=3D'efivar' regards, Oliver --=20 O. Hartmann Ich widerspreche der Nutzung oder =C3=9Cbermittlung meiner Daten f=C3=BCr Werbezwecke oder f=C3=BCr die Markt- oder Meinungsforschung (=C2=A7 28 Abs.= 4 BDSG). --Sig_/AveLuR8PmdXW5NE4YkT/Zgu Content-Type: application/pgp-signature Content-Description: OpenPGP digital signature -----BEGIN PGP SIGNATURE----- iLUEARMKAB0WIQQZVZMzAtwC2T/86TrS528fyFhYlAUCWiKM6QAKCRDS528fyFhY lMQkAf9Na3V+e26DGH9GU7lArdaqltXbtYh08PEE4gCZ95ZCmBzNmPzPJcZUbRkz nrHpC7n4OjsuLEktxZiYGgXxcgg/Af0e5F3o3v8uc7jhPlJYpYKWSaXWDzaEq+ih SJz5qD11YUuQVqmXv1YOSho98yxwvX4xGTo6dhFuMF+uT8BI8dDl =Egq9 -----END PGP SIGNATURE----- --Sig_/AveLuR8PmdXW5NE4YkT/Zgu--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20171202122217.4e40a80f>