Skip site navigation (1)Skip section navigation (2)
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>