pax_global_header00006660000000000000000000000064125510143060014507gustar00rootroot0000000000000052 comment=aab6c2a64d90b6e5a63661fb5bd6be8d878b0784 efivar-0.21/000077500000000000000000000000001255101430600127055ustar00rootroot00000000000000efivar-0.21/.gitignore000066400000000000000000000002071255101430600146740ustar00rootroot00000000000000.*.sw? *~ *.a *.E *.o *.pc *.S !src/guids.S *.so *.so.* *.tar.* .*.c.P .*.h.P core.* *.spec src/efivar src/efivar-static src/makeguids efivar-0.21/COPYING000066400000000000000000000633161255101430600137510ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! efivar-0.21/Make.defaults000066400000000000000000000015161255101430600153160ustar00rootroot00000000000000INSTALL ?= install libdir ?= /usr/lib64/ mandir ?= /usr/share/man/ includedir ?= /usr/include/ bindir ?= /usr/bin/ PCDIR ?= $(libdir)/pkgconfig/ CC := $(if $(filter default,$(origin CC)),gcc,$(CC)) CCLD := $(if $(filter undefined,$(origin CCLD)),$(CC),$(CCLD)) CFLAGS ?= -O2 -g ARCH = $(shell uname -m) clang_cflags = gcc_cflags = -Wmaybe-uninitialized cflags := $(CFLAGS) \ -Werror -Wall -Wsign-compare -Wstrict-aliasing \ -std=gnu11 -fshort-wchar -fPIC \ -fvisibility=hidden \ -D_GNU_SOURCE -I${TOPDIR}/src/include/efivar/ \ $(if $(filter $(CC),clang),$(clang_cflags),) \ $(if $(filter $(CC),gcc),$(gcc_cflags),) clang_ccldflags = gcc_ccldflags = -fno-merge-constants ccldflags := $(cflags) $(CCLDFLAGS) $(LDFLAGS) \ $(if $(filter $(CCLD),clang),$(clang_ccldflags),) \ $(if $(filter $(CCLD),gcc),$(gcc_ccldflags),) LIBFLAGS += -shared efivar-0.21/Make.rules000066400000000000000000000012711255101430600146370ustar00rootroot00000000000000%.a : $(AR) -cvqs $@ $^ % : %.o $(CCLD) $(ccldflags) -o $@ $^ $(foreach lib,$(LIBS),-l$(lib)) %.so.$(VERSION) : $(CCLD) $(cflags) -Wl,-soname,$(patsubst %.so.$(VERSION),%.so.$(MAJOR_VERSION),$@) $(ccldflags) $(LIBFLAGS) $^ -o $@ $(foreach lib,$(LIBS),-l$(lib)) %.so : %.so.$(VERSION) ln -sf $< $@ %.so.$(MAJOR_VERSION) : %.so.$(VERSION) ln -sf $< $@ %.o: %.c $(CC) $(cflags) $(CPPFLAGS) -c -o $@ $< .%.c.P : %.c $(CC) $(cflags) $(CPPFLAGS) -DEFIVAR_BUILD_ENVIRONMENT -M -MM -MF $@ $^ .%.h.P : %.h $(CC) $(cflags) $(CPPFLAGS) -DEFIVAR_BUILD_ENVIRONMENT -M -MM -MF $@ $^ %.S: %.c $(CC) $(cflags) $(CPPFLAGS) -S $< -o $@ %.E: %.c $(CC) $(cflags) $(CPPFLAGS) -E $< -o $@ %.c : %.h efivar-0.21/Make.version000066400000000000000000000001211255101430600151630ustar00rootroot00000000000000MAJOR_VERSION = 0 MINOR_VERSION = 21 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION) efivar-0.21/Makefile000066400000000000000000000042071255101430600143500ustar00rootroot00000000000000TOPDIR = $(shell echo $$PWD) include $(TOPDIR)/Make.version SUBDIRS := src docs all : $(SUBDIRS) efivar.spec efivar efivar-static : $(MAKE) -C src TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/$@/ ARCH=$(ARCH) $@ $(SUBDIRS) : $(MAKE) -C $@ TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/$@/ ARCH=$(ARCH) clean : @set -e ; for x in $(SUBDIRS) ; do $(MAKE) -C $${x} TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/$@/ ARCH=$(ARCH) $@ ; done @rm -vf efivar.spec install : @set -e ; for x in $(SUBDIRS) ; do $(MAKE) -C $${x} TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/$@/ ARCH=$(ARCH) DESTDIR=$(DESTDIR) includedir=$(includedir) bindir=$(bindir) libdir=$(libdir) PCDIR=$(PCDIR) $@ ; done brick : all @set -e ; for x in $(SUBDIRS) ; do $(MAKE) -C $${x} TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/$@/ ARCH=$(ARCH) test ; done a : @if [ $${EUID} != 0 ]; then \ echo no 1>&2 ; \ exit 1 ; \ fi .PHONY: $(SUBDIRS) all clean install a brick include $(TOPDIR)/Make.defaults include $(TOPDIR)/Make.rules efivar.spec : efivar.spec.in Makefile @sed -e "s,@@VERSION@@,$(VERSION),g" $< > $@ GITTAG = $(VERSION) test-archive: efivar.spec @rm -rf /tmp/efivar-$(VERSION) /tmp/efivar-$(VERSION)-tmp @mkdir -p /tmp/efivar-$(VERSION)-tmp @git archive --format=tar $(shell git branch | awk '/^*/ { print $$2 }') | ( cd /tmp/efivar-$(VERSION)-tmp/ ; tar x ) @git diff | ( cd /tmp/efivar-$(VERSION)-tmp/ ; patch -s -p1 -b -z .gitdiff ) @mv /tmp/efivar-$(VERSION)-tmp/ /tmp/efivar-$(VERSION)/ @cp efivar.spec /tmp/efivar-$(VERSION)/ @dir=$$PWD; cd /tmp; tar -c --bzip2 -f $$dir/efivar-$(VERSION).tar.bz2 efivar-$(VERSION) @rm -rf /tmp/efivar-$(VERSION) @echo "The archive is in efivar-$(VERSION).tar.bz2" tag: git tag -s $(GITTAG) refs/heads/master archive: tag efivar.spec @rm -rf /tmp/efivar-$(VERSION) /tmp/efivar-$(VERSION)-tmp @mkdir -p /tmp/efivar-$(VERSION)-tmp @git archive --format=tar $(GITTAG) | ( cd /tmp/efivar-$(VERSION)-tmp/ ; tar x ) @mv /tmp/efivar-$(VERSION)-tmp/ /tmp/efivar-$(VERSION)/ @cp efivar.spec /tmp/efivar-$(VERSION)/ @dir=$$PWD; cd /tmp; tar -c --bzip2 -f $$dir/efivar-$(VERSION).tar.bz2 efivar-$(VERSION) @rm -rf /tmp/efivar-$(VERSION) @echo "The archive is in efivar-$(VERSION).tar.bz2" efivar-0.21/README.md000066400000000000000000000016441255101430600141710ustar00rootroot00000000000000efivar ====== Tools and libraries to manipulate EFI variables --------------------------------------------- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see [http://www.gnu.org/licenses/]. [http://www.gnu.org/licenses/]: http://www.gnu.org/licenses/ WARNING ======= You should probably not run "make a brick" *ever*, unless you're already reasonably sure it won't permanently corrupt your firmware. This is not a joke. efivar-0.21/TODO000066400000000000000000000015261255101430600134010ustar00rootroot00000000000000- lots of work still on device path generation and parsing in -lefiboot: - network paths of all kinds - fcoe - no idea - fc - no idea - iscsi - right now we write out HD paths that don't work because edk2 and similar don't put an HD() below iSCSI(), and there's no such thing as an "abbreviated iscsi device path" - but 9.3.5.21.2 actually /shows/ it having an HD() path. - so we need to write out: PciRoot(0x0)/Pci(0x3,0x0)/MAC(c0ffeec0ffee,1)/IPv4(192.168.100.182:0<->10.0.0.29:3260,6,0)/iSCSI(iqn.2012-07.lenovoemc:storage.pjones-iscsi.vol0,1,0x0,None,None,None,TCP) or something like that. - this is ugly :/ - not sure how to tell from the OS side what parts should be DHCP based - pretty ugly when ens3 changes addresses every time - would IPv4(0.0.0.0:0<->10.0.0.29:3260,6,0) be valid? - lots of man pages efivar-0.21/docs/000077500000000000000000000000001255101430600136355ustar00rootroot00000000000000efivar-0.21/docs/Makefile000066400000000000000000000025241255101430600153000ustar00rootroot00000000000000SRCDIR = . TOPDIR = $(SRCDIR)/.. include $(TOPDIR)/Make.defaults include $(TOPDIR)/Make.version MAN1TARGETS = efivar.1 MAN3TARGETS = efi_append_variable.3 \ efi_del_variable.3 \ efi_get_next_variable_name.3 \ efi_get_variable.3 \ efi_get_variable_attributes.3 \ efi_get_variable_size.3 \ efi_guid_to_id_guid.3 \ efi_guid_to_name.3 \ efi_guid_to_str.3 \ efi_guid_to_symbol.3 \ efi_name_to_guid.3 \ efi_set_variable.3 \ efi_str_to_guid.3 \ efi_symbol_to_guid.3 \ efi_variables_supported.3 \ efi_variable_t.3 \ efi_variable_import.3 \ efi_variable_export.3 \ efi_variable_alloc.3 \ efi_variable_free.3 \ efi_variable_set_name.3 \ efi_variable_get_name.3 \ efi_variable_set_guid.3 \ efi_variable_get_guid.3 \ efi_variable_set_data.3 \ efi_variable_get_data.3 \ efi_variable_get_attributes.3 \ efi_variable_set_attributes.3 \ efi_variable_realize.3 all : clean : test : install : $(INSTALL) -d -m 755 $(DESTDIR)$(mandir)/man1 $(foreach x, $(MAN1TARGETS), $(INSTALL) -m 644 $(x) $(DESTDIR)/$(mandir)/man1/;) $(INSTALL) -d -m 755 $(DESTDIR)$(mandir)/man3 $(foreach x, $(MAN3TARGETS), $(INSTALL) -m 644 $(x) $(DESTDIR)/$(mandir)/man3/;) .PHONY: all clean install include $(TOPDIR)/Make.rules efivar-0.21/docs/efi_append_variable.3000066400000000000000000000000341255101430600176550ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_del_variable.3000066400000000000000000000000341255101430600171520ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_get_next_variable_name.3000066400000000000000000000000341255101430600212230ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_get_variable.3000066400000000000000000000126361255101430600172000ustar00rootroot00000000000000.TH EFI_GET_VARIABLE 3 "Thu Aug 20 2012" .SH NAME efi_variables_supported, efi_del_variable, efi_get_variable, efi_get_variable_attributes, efi_get_variable_size, efi_set_variable \- manipulate UEFI variables .SH SYNOPSIS .nf .B #include .sp \fBint efi_variables_supported(void);\fR \fBint efi_del_variable(efi_guid_t\fR \fIguid\fR\fB, const char\fR \fI*name\fR\fB);\fR \fBint efi_get_variable(efi_guid_t\fR \fIguid\fR\fB, const char *\fR\fIname\fR\fB, void **\fR\fIdata\fR\fB, ssize_t *\fR\fIdata_size\fR\fB, uint32_t *\fR\fIattributes\fR\fB);\fR \fBint efi_get_variable_attributes(efi_guid_t \fR\fIguid\fR\fB, const char *\fR\fIname\fR\fB, uint32_t *\fR\fIattributes\fR\fB);\fR \fBint efi_get_variable_size(efi_guid_t \fR\fIguid\fR\fB, const char *\fR\fIname\fR\fB, size_t *\fR\fIsize\fR\fB);\fR \fBint efi_append_variable(efi_guid_t \fR\fIguid\fR\fB, const char *\fR\fIname\fR\fB, void *\fR\fIdata\fR\fB, size_t \fR\fIdata_size\fR\fB, uint32_t \fR\fIattributes\fR\fB);\fR \fBint efi_set_variable(efi_guid_t \fR\fIguid\fR\fB, const char *\fR\fIname\fR\fB, void *\fR\fIdata\fR\fB, size_t \fR\fIdata_size\fR\fB, uint32_t \fR\fIattributes\fR\fB);\fR \fBint efi_set_variable(efi_guid_t \fR\fIguid\fR\fB, const char *\fR\fIname\fR\fB, void *\fR\fIdata\fR\fB, size_t \fR\fIdata_size\fR\fB, uint32_t \fR\fIattributes\fR\fB, mode_t \fR\fImode\fR\fB);\fR \fBint efi_get_next_variable_name(efi_guid_t **\fR\fIguid\fR\fB, char **\fR\fIname\fR\fB);\fR \fBint efi_str_to_guid(const char *\fR\fIs\fR\fB, efi_guid_t *\fR\fIguid\fR\fB);\fR \fBint efi_guid_to_str(const efi_guid_t *\fR\fIguid\fR\fB, char **\fR\fIsp\fR\fB);\fR \fBint efi_name_to_guid(const char *\fR\fIname\fR\fB, efi_guid_t *\fR\fIguid\fR\fB);\fR \fBint efi_id_guid_to_guid(const char *\fR\fIid_guid\fR\fB, efi_guid_t *\fR\fIguid\fR\fB);\fR \fBint efi_guid_to_name(efi_guid_t *\fR\fIguid\fR\fB, char **\fR\fIname\fR\fB);\fR \fBint efi_guid_to_id_guid(efi_guid_t *\fR\fIguid\fR\fB, char **\fR\fIid_guid\fR\fB);\fR \fBint efi_guid_to_symbol(efi_guid_t *\fR\fIguid\fR\fB, char **\fR\fIsymbol\fR\fB);\fR \fBint efi_symbol_to_guid(const char *\fR\fIsymbol\fR\fB, efi_guid_t *\fR\fIguid\fR\fB);\fR .fi .SH DESCRIPTION .BR efi_variables_supported () tests if the UEFI variable facility is supported on the current machine. .PP .BR efi_del_variable () deletes the variable specified by \fIguid\fR and \fIname\fR. .PP .BR efi_get_variable () gets the variable specified by \fIguid\fR and \fIname\fR. The value is stored in \fIdata\fR, its size in \fIdata_size\fR, and its attributes are stored in \fIattributes\fR. .PP .BR efi_get_variable_attributes () gets attributes for the variable specified by \fIguid\fR and \fIname\fR. .PP .BR efi_get_variable_size () gets the size of the data for the variable specified by \fIguid\fR and \fIname\fR. .PP .BR efi_append_variable () appends \fIdata\fR of size \fIsize\fR to the variable specified by \fIguid\fR and \fIname\fR. .PP .BR efi_set_variable () sets the variable specified by \fIguid\fR and \fIname\fR. If the optional \fImode\fR parameter is given, it will use those permissions to create the file, subject to umask. .PP .BR efi_get_next_variable_name () iterates across the currently extant variables, passing back a guid and name. .PP .BR efi_str_to_guid () parses a UEFI GUID from string form to an efi_guid_t the caller provides .PP .BR efi_guid_to_str () Creates a string representation of a UEFI GUID. If sp is NULL, it returns how big the string would be. If sp is not NULL but *sp is NULL, it allocates a string and returns it with. It is the caller's responsibility to free this string. If sp is not NULL and *sp is not NULL, \fBefi_guid_to_str\fR() assumes there is an allocation of suitable size and uses it. .PP .BR efi_name_to_guid () translates from a well known name to an efi_guid_t the caller provides. .PP .BR efi_guid_to_name () translates from an efi_guid_t to a well known name. If the supplied GUID does not have a well known name, this function is equivalent to \fBefi_guid_to_str\fR(). .PP .BR efi_guid_to_id_guid () translates from an efi_guid_t to an {ID GUID}. If the supplied GUID has a well known name, the {ID GUID} will be of the form "{name_here}". If not, it will be of the form "{66b2af1c-6211-4082-95cb-9f73a4795a7e}". .PP .BR efi_id_guid_to_guid () translates from an {ID GUID} to an efi_guid_t the caller provides. .PP .BR efi_guid_to_symbol () translates from an efi_guid_t to a unique (within libefivar) C-sytle symbol name. These symbol names are useful for printing as a unique, easily parsed identifier, and are also provide by the library and its header files. .PP .BR efi_symbol_to_guid () translates from a libefivar efi_guid_$FOO symbol name to an efi_guid_t the caller provides. .PP .SH "RETURN VALUE" \fBefi_variables_supported\fR() returns true if variables are supported on the running hardware, and false if they are not. .PP \fBefi_get_next_variable_name\fR() returns 0 when iteration has completed, 1 when iteration has not completed, and -1 on error. In the event of an error, .IR errno (3) is set appropriately. .PP \fBefi_del_variable\fR(), \fBefi_get_variable\fR(), \fBefi_get_variable_attributes\fR(), \fBefi_get_variable_size\fR(), \fBefi_append_variable\fR(), \fBefi_set_variable\fR(), \fBefi_str_to_guid\fR(), \fBefi_guid_to_str\fR(), \fBefi_name_to_guid\fR(), and \fBefi_guid_to_name\fR() return negative on error and zero on success. .SH AUTHORS .nf Peter Jones .fi efivar-0.21/docs/efi_get_variable_attributes.3000066400000000000000000000000341255101430600214330ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_get_variable_size.3000066400000000000000000000000341255101430600202170ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_guid_to_id_guid.3000066400000000000000000000000341255101430600176570ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_guid_to_name.3000066400000000000000000000000341255101430600171730ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_guid_to_str.3000066400000000000000000000000341255101430600170630ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_guid_to_symbol.3000066400000000000000000000000341255101430600175600ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_id_guid_to_guid.3000066400000000000000000000000341255101430600176570ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_name_to_guid.3000066400000000000000000000000341255101430600171730ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_set_variable.3000066400000000000000000000000341255101430600172010ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_str_to_guid.3000066400000000000000000000000341255101430600170630ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_symbol_to_guid.3000066400000000000000000000000341255101430600175600ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efi_variable_alloc.3000066400000000000000000000000321255101430600174760ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_export.3000066400000000000000000000000321255101430600177250ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_free.3000066400000000000000000000000321255101430600173250ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_get_attributes.3000066400000000000000000000000321255101430600214310ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_get_data.3000066400000000000000000000000321255101430600201540ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_get_guid.3000066400000000000000000000000321255101430600201730ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_get_name.3000066400000000000000000000000321255101430600201630ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_import.3000066400000000000000000000000321255101430600177160ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_realize.3000066400000000000000000000000321255101430600200370ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_set_attributes.3000066400000000000000000000000321255101430600214450ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_set_data.3000066400000000000000000000000321255101430600201700ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_set_guid.3000066400000000000000000000000321255101430600202070ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_set_name.3000066400000000000000000000000321255101430600201770ustar00rootroot00000000000000.so man3/efi_variable_t.3 efivar-0.21/docs/efi_variable_t.3000066400000000000000000000174701255101430600166650ustar00rootroot00000000000000.TH EFI_VARIABLE_T 3 "Thu Nov 11 2014" .SH NAME efi_variable_import, efi_variable_export, efi_variable_alloc, efi_variable_free, efi_variable_set_name, efi_variable_get_name, efi_variable_set_guid, efi_variable_get_guid, efi_variable_set_data, efi_variable_get_data, efi_variable_set_attributes, efi_variable_get_attributes, efi_variable_realize \- utility functions to import and export UEFI variables to files. .SH SYNOPSIS .nf .B #include .sp \fItypedef struct efi_variable \fR\fBefi_variable_t\fR\fI;\fR \fIssize_t \fR\fBefi_variable_import\fR(\fIuint8_t *\fR\fBdata\fR, \fIsize_t\fR \fBsize\fR, \fIefi_variable_t **\fR\fBvar\fR); \fIssize_t \fR\fBefi_variable_export\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIuint8_t **\fR\fBdata\fR, \fIsize_t *\fR\fBsize\fR); \fIefi_variable_t *\fR\fBefi_variable_alloc\fR(\fIvoid\fR); \fIvoid \fR\fBefi_variable_free\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIint \fR\fBfree_data\fR); \fIint \fR\fBefi_variable_set_name\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIchar *\fR\fBname\fR); \fIchar *\fR\fBefi_variable_get_name\fR(\fIefi_variable_t *\fR\fBvar\fR); \fIint \fR\fBefi_variable_set_guid\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIefi_guid_t *\fR\fBguid\fR); \fIint \fR\fBefi_variable_get_guid\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIefi_guid_t **\fR\fBguid\fR); \fIint \fR\fBefi_variable_set_data\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIuint8_t *\fR\fBdata\fR, \fIsize_t \fR\fBsize\fR); \fIint \fR\fBefi_variable_get_data\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIuint8_t **\fR\fBdata\fR, \fIsize_t *\fR\fBsize\fR); \fI#define\fR \fBEFI_VARIABLE_NON_VOLATILE\fR \fI0x0000000000000001\fR \fI#define\fR \fBEFI_VARIABLE_BOOTSERVICE_ACCESS\fR \fI0x0000000000000002\fR \fI#define\fR \fBEFI_VARIABLE_RUNTIME_ACCESS\fR \fI0x0000000000000004\fR \fI#define\fR \fBEFI_VARIABLE_HARDWARE_ERROR_RECORD\fR \fI0x0000000000000008\fR \fI#define\fR \fBEFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\fR \fI0x0000000000000010\fR \fI#define\fR \fBEFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\fR \fI0x0000000000000020\fR \fI#define\fR \fBEFI_VARIABLE_APPEND_WRITE\fR \fI0x0000000000000040\fR \fI#define\fR \fBEFI_VARIABLE_HAS_AUTH_HEADER\fR \fI0x0000000100000000\fR \fI#define\fR \fBEFI_VARIABLE_HAS_SIGNATURE\fR \fI0x0000000200000000\fR \fIint \fR\fBefi_variable_set_attributes\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIuint64_t \fR\fBattrs\fR); \fIint \fR\fBefi_variable_get_attributes\fR(\fIefi_variable_t *\fR\fBvar\fR, \fIuint64_t *\fR\fBattrs\fR); \fIint \fR\fBefi_variable_realize\fR(\fIefi_variable_t *\fR\fBvar\fR); .fi .SH DESCRIPTION \fBefi_variable_t\fR is an opaque data type used to store variables in-memory for use with this API. .PP \fBefi_variable_import\fR() is used to import raw data read from a file. This function returns the amount of data consumed with this variable, and may be used successively, using its return code as an offset, to parse a list of variables. Note that the internal guid, name, and data values are allocated separately, and must be freed either individually or using the \fBfree_data\fR parameter of \fBefi_variable_free\fR(). \fB_get\fR() accessors for those values return data suitable for freeing individually, except in such cases where a \fB_set\fR() accessor has been passed an object already unsuitable for that. .PP \fBefi_variable_export\fR() is used to marshall \fBefi_variable_t\fR objects into linear data which can be written to a file. If \fBdata\fR or \fBsize\fR parameters are not provided, this function will return how much storage a caller must allocate. Otherwise, \fBefi_variable_export\fR() will use the storage referred to as its buffer; if \fBsize\fR is smaller than the amount of needed storage , the buffer will not be modified, and the difference between the needed space and \fBsize\fR will be returned. .PP \fBefi_variable_alloc\fR() is used to allocate an unpopulated \fBefi_variable_t\fR object suitable to be used throughout this API. \fBefi_variable_free\fR() is used to free an \fBefi_variable_t\fR object, and if \fBfree_data\fR is nonzero, to free its constituent data. .PP Each pair of \fB_set\fR() and \fB_get\fR() accessors have essentially the same semantics. Neither operation performs any memory management, including freeing of previously set values or values set by \fBefi_variable_import\fR(), and so in some cases it may be necessary to use a \fB_get\fR() accessor to retrieve an object to be freed. In cases where no value has been set, \fB_get\fR() accessors will set \fBerrno\fR to \fBENOENT\fR and return a negative value or NULL. .PP \fBefi_variable_set_name\fR() and \fBefi_variable_get_name\fR() are used to set and retrieve the name of the variable referred to by the \fBefi_variable_t\fR object. .PP \fBefi_variable_set_guid\fR() and \fBefi_variable_get_guid\fR() are used to set and retrieve the Vendor GUID value of the variable referred to by the \fBefi_variable_t\fR object. .PP \fBefi_variable_set_data\fR() and \fBefi_variable_get_data\fR() are used to set and retrieve an \fBefi_variable_t\fR object's variable data. .PP \fBefi_variable_set_attributes\fR() and \fBefi_variable_get_attributes\fR are used to set and retrieve an \fBefi_variable_t\fR object's attributes. All bits except \fBEFI_VARIABLE_HAS_AUTH_HEADER\fR and \fBEFI_VARIABLE_HAS_SIGNATURE\fR are defined in the UEFI specification and should be used accordingly. \fBEFI_VARIABLE_HAS_AUTH_HEADER\fR should be used by applications to track whether the variable data contents include an authentication header. \fBEFI_VARIABLE_HAS_SIGNATURE\fR should be used by applications to track if the variable's data contents include a signature, and should not be set unless \fBEFI_VARIABLE_HAS_AUTH_HEADER\fR is also set. These attributes are used to track if an exported variable is in a state of partial construction, for example if an authenticated variable has been created but is intended to be signed at a later date. .PP \fBefi_variable_realize\fR() is a convenience function to set or append a UEFI variable on the running system from an \fBefi_variable_t\fR object. its return codes are the same as \fBefi_append_variable\fR(3) if EFI_VARIABLE_APPEND_WRITE is set, and \fBefi_set_variable\fR() if that bit is not set. Additionally, in the case that any of the authentication bits are set, \fBefi_variable_realize\fR() will return error and set \fBerrno\fR to \fBEPERM\fR unless both \fBEFI_VARIABLE_HAS_AUTH_HEADER\fR and \fBEFI_VARIABLE_HAS_SIGNATURE\fR attribute bits are been set. .PP .SH "RETURN VALUE" \fBefi_variable_import\fR() returns 0 on success, and -1 on failure. In cases where it cannot parse the data, \fBerrno\fR will be set to \fBEINVAL\fR. In cases where memory has been exhausted, \fBerrno\fR will be set to \fBENOMEM\fR. .PP \fBefi_variable_import\fR() returns the size of the buffer data on success, or a negative value in the case of an error. If \fBdata\fR or \fBsize\fR parameters are not provided, this function will return how much storage is a caller must allocate. Otherwise, this function will use the storage provided in \fBdata\fR; if \fBsize\fR is less than the needed space, the buffer will not be modified, and the return value will be the difficiency in size. .PP \fBefi_variable_alloc\fR() returns a newly allocated \fBefi_variable_t\fR object, but does not peform any allocation for that object's \fBname\fR, \fBguid\fR, or \fBdata\fR. In the case that memory is exhausted, \fBNULL\fR will be returned, and \fBerrno\fR will be set to \fBENOMEM\fR. .PP \fBefi_variable_get_name\fR() returns a pointer the NUL-terminated string containing the \fBefi_variable_t\fR object's name information. .PP \fBefi_variable_set_name\fR(), \fBefi_variable_set_guid\fR(), \fBefi_variable_get_guid\fR(), \fBefi_variable_set_data\fR(), \fBefi_variable_get_data\fR(), \fBefi_variable_set_attributes\fR(), \fBefi_variable_get_attributes\fR(), and \fBefi_variable_realize\fR() return 0 on success and -1 on error. .SH AUTHORS .nf Peter Jones .fi efivar-0.21/docs/efi_variables_supported.3000066400000000000000000000000341255101430600206160ustar00rootroot00000000000000.so man3/efi_get_variable.3 efivar-0.21/docs/efidp_make_generic.3000066400000000000000000000131031255101430600174770ustar00rootroot00000000000000.TH EFIDP_MAKE_GENERIC 3 "Mon 11 May 2015" .SH NAME efidp_make_generic, efidp_make_end_instance, efidp_make_end_entire, efidp_make_vendor, efidp_make_file, efidp_make_hd, efidp_make_nvme, efidp_make_sas, efidp_make_ipv4, efidp_make_mac_addr, efidp_make_sata, efidp_make_scsi, efidp_make_acpi_hid, efidp_make_acpi_hid_ex, efidp_make_edd10, efidp_make_pci, efidp_make_hw_vendor, efidp_make_msg_vendor, efidp_make_media_vendor \- Create EFI Device Path node data structures for specific device types efidp_set_node_data, efidp_duplicate_path, efidp_append_path, efidp_append_node, efidp_append_instance \- Manipulate EFI Device Path and node relationships. efidp_is_valid, efidp_instance_size, efidp_size, efidp_get_next_end, efidp_is_multiinstance, efidp_next_instance, efidp_next_node, efidp_node_size, efidp_type, efidp_subtype \- Inspect EFI Device Path data structures efidp_parse_device_node, efidp_parse_device_path \- Create EFI Device Path structures from printable strings. efidp_format_device_path \- Format EFI Device Path structures as printable strings. .SH SYNOPSIS .nf .B #include .sp \fBssize_t \fRefidp_make_generic\fB(\kZuint8_t *\fIbuf\fP, ssize_t \fIsize\fB, .ta \nZu uint8_t \fItype\fB, uint8_t \fIsubtype\fB, ssize_t \fItotal_size\fB);\fR \fBssize_t \fRefidp_make_end_instance\fB(uint8_t *\fIbuf\fB, ssize_t \fIsize\fB);\fR \fBssize_t \fRefidp_make_end_entire\fB(uint8_t *\fIbuf\fB, ssize_t \fIsize\fR\fB);\fR \fBssize_t \fRefidp_make_vendor\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint8_t \fItype\fB, .ta \nZu uint8_t \fIsubtype\fB, efi_guid_t \fIvendor_guid\fB, void *\fIdata\fB, size_t \fIdata_size\fB);\fR \fBssize_t \fRefidp_make_file\fB(uint8_t *\fIbuf\fB, ssize_t \fIsize\fB, char *\fIfilename\fB);\fR .ta \fBssize_t \fRefidp_make_hd\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint32_t \fInum\fB, .ta \nZu uint64_t \fIpart_start\fB, uint64_t \fIpart_size\fB, uint8_t *\fIsignature\fB, uint8_t \fIformat\fB, uint8_t \fIsignature_type\fB);\fR \fBssize_t \fRefidp_make_nvme\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu uint32_t \fInamespace_id\fB, uint8_t *\fIieee_eui_64\fB);\fR \fBssize_t \fRefidp_make_sas\fB(uint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint64_t \fIsas_address\fB);\fR \fBssize_t \fRefidp_make_ipv4\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu uint32_t \fIlocal\fB, uint32_t \fIremote\fB, uint32_t \fIgateway\fB, uint32_t \fInetmask\fB, uint16_t \fIlocal_port\fB, uint16_t \fIremote_port\fB, uint16_t \fIprotocol\fB, int \fIis_static\fB);\fR \fBssize_t \fRefidp_make_mac_addr\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu uint8_t \fIif_type\fB, const uint8_t const *\fImac_addr\fB, ssize_t \fImac_addr_size\fB);\fR \fBssize_t \fRefidp_make_sata\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint16_t \fIhba_port\fB, .ta \nZu uint16_t \fIport_multiplier_port\fB, uint16_t \fIlun\fB);\fR \fBssize_t \fRefidp_make_scsi\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint16_t \fItarget\fB, .ta \nZu uint16_t \fIlun\fB);\fR \fBssize_t \fRefidp_make_acpi_hid\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint32_t \fIhid\fB, .ta \nZu uint32_t \fIuid\fB);\fR \fBssize_t \fRefidp_make_acpi_hid_ex\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint32_t \fIhid\fB, .ta \nZu uint32_t \fIuid\fB, uint32_t \fIcid\fB, char *\fIhidstr\fB, char *\fIuidstr\fB, char *\fIcidstr\fB);\fR \fBssize_t \fRefidp_make_edd10\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu uint32_t \fIhardware_device\fB);\fR \fBssize_t \fRefidp_make_pci\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, uint8_t \fIdevice\fB, .ta \nZu uint8_t \fIfunction\fR); \fBssize_t \fRefidp_make_hw_vendor\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu efi_guid_t \fIguid\fB, void *\fIdata\fB, size_t \fIdata_size\fB);\fR \fBssize_t \fRefidp_make_msg_vendor\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu efi_guid_t \fIguid\fB, void *\fIdata\fB, size_t \fIdata_size\fB);\fR \fBssize_t \fRefidp_make_media_vendor\fB(\kZuint8_t *\fIbuf\fB, ssize_t \fIsize\fB, .ta \nZu efi_guid_t \fIguid\fB, void *\fIdata\fB, size_t \fIdata_size\fB);\fR \fBint \fRefidp_set_node_data\fB(\kZconst_efidp \fIdn\fB, void *\fIbuf\fB, size_t \fIbufsize\fB); \fBint \fRefidp_duplicate_path\fB(\kZconst_efidp \fIdp\fB, efidp *\fIout\fB);\fR \fBint \fRefidp_append_path\fB(\kZconst_efidp \fIdp0\fB, const_efidp \fIdp1\fB, efidp *\fIout\fB); \fBint \fRefidp_append_node\fB(\kZconst_efidp \fIdp\fB, const_efidp \fIdn\fB, efidp *\fIout\fB);\fR \fBint \fRefidp_append_instance\fB(\kZconst_efidp \fIdp\fB, const_efidp \fIdpi\fB, efidp *\fIout\fB); \fBint16_t \fRefidp_type\fB(const_efidp \fIdp\fB);\fR \fBint16_t \fRefidp_subtype\fB(const_efidp \fIdp\fB);\fR \fBssize_t \fRefidp_node_size\fB(const_efidp \fIdn\fB);\fR \fBint \fRefidp_next_node\fB(const_efidp \fIin\fB, const_efidp *\fIout\fB);\fR \fBint \fRefidp_next_instance\fB(const_efidp \fIin\fB, const_efidp *\fIout\fB);\fR \fBint \fRefidp_is_multiinstance\fB(const_efidp \fIdn\fB);\fR \fBint \fRefidp_get_next_end\fB(const_efidp \fIin\fB, const_efidp *\fIout\fB);\fR \fBssize_t \fRefidp_size\fB(const_efidp \fIdp\fB);\fR \fBssize_t \fRefidp_instance_size\fB(const_efidp \fIdpi\fB);\fR \fBint \fRefidp_is_valid\fB(const_efidp \fIdp\fB, ssize_t \fIlimit\fB);\fR \fBssize_t \fRefidp_parse_device_node\fB(char *\fIpath\fB, efidp \fIout\fB, size_t \fIsize\fB);\fR \fBssize_t \fRefidp_parse_device_path\fB(char *\fIpath\fB, efidp \fIout\fB, size_t \fIsize\fB);\fR \fBssize_t \fRefidp_format_device_path\fB(\kZchar *\fIbuf\fB, size_t \fIsize\fB, .ta \nZu const_efidp \fIdp\fB, ssize_t \fIlimit\fB);\fR .fi .SH AUTHORS .nf Peter Jones .fi efivar-0.21/docs/efivar.1000066400000000000000000000015771255101430600152050ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.45.1. .TH EFIVAR "1" "June 2014" "efivar 0.10" "User Commands" .SH NAME efivar \- Tool to manipulate UEFI variables .SH SYNOPSIS .B efivar [\fI\,OPTION\/\fR...] .SH DESCRIPTION .TP \fB\-L\fR, \fB\-\-list\-guids\fR list guids efivar knows about .TP \fB\-l\fR, \fB\-\-list\fR list current variables .TP \fB\-p\fR, \fB\-\-print\fR print variable specified by \fB\-\-name\fR .TP \fB\-n\fR, \fB\-\-name=\fR variable to manipulate, in the form 8be4df61\-93ca\-11d2\-aa0d\-00e098032b8c\-Boot0000 .TP \fB\-a\fR, \fB\-\-append\fR append to variable specified by \fB\-\-name\fR .TP \fB\-f\fR, \fB\-\-fromfile=\fR use data from .TP \fB\-t\fR, \fB\-\-attributes=\fR attributes to use on append .SS "Help options:" .TP \-?, \fB\-\-help\fR Show this help message .TP \fB\-\-usage\fR Display brief usage message efivar-0.21/efivar.spec.in000066400000000000000000000104141255101430600154420ustar00rootroot00000000000000Name: efivar Version: @@VERSION@@ Release: 1%{?dist} Summary: Tools to manage UEFI variables License: LGPLv2.1 URL: https://github.com/rhinstaller/efivar Requires: %{name}-libs = %{version}-%{release} ExclusiveArch: %{ix86} x86_64 aarch64 BuildRequires: popt-devel git Source0: https://github.com/rhinstaller/efivar/releases/download/efivar-%{version}/efivar-%{version}.tar.bz2 %description efivar provides a simple command line interface to the UEFI variable facility. %package libs Summary: Library to manage UEFI variables %description libs Library to allow for the simple manipulation of UEFI variables. %package devel Summary: Development headers for libefivar Requires: %{name}-libs = %{version}-%{release} %description devel development headers required to use libefivar. %prep %setup -q -n %{name}-%{version} git init git config user.email "%{name}-owner@fedoraproject.org" git config user.name "Fedora Ninjas" git add . git commit -a -q -m "%{version} baseline." git am %{patches} - 0.21-1 - Rename "make test" so packagers don't think it's a good idea to run it during builds. - Error check sizes in vars_get_variable() - Fix some file size comparisons - make SONAME reflect the correct values. - Fix some uses of "const" - Compile with -O2 by default - Fix some strict-aliasing violations - Fix some of the .pc files and how we do linking to work better. * Tue Jun 02 2015 Peter Jones - 0.20-1 - Update to 0.20 - Make sure tester is build with the right link order for libraries. - Adjust linker order for pkg-config - Work around LocateDevicePath() not grokking PcieRoot() devices properly. - Rectify some missing changelog entries * Thu May 28 2015 Peter Jones - 0.19-1 - Update to 0.19 - add API from efibootmgr so fwupdate and other tools can use it. * Wed Oct 15 2014 Peter Jones - 0.15-1 - Update to 0.15 - Make 32-bit builds set variables' DataSize correctly. * Wed Oct 08 2014 Peter Jones - 0.14-1 - Update to 0.14 - add efi_id_guid_to_guid() and efi_guid_to_id_guid(), which support {ID GUID} as a concept. - Add some vendor specific guids to our guid list. - Call "empty" "zero" now, as many other places do. References to efi_guid_is_empty() and efi_guid_empty still exist for ABI compatibility. - add "efivar -L" to the man page. * Tue Oct 07 2014 Peter Jones - 0.13-1 - Update to 0.13: - add efi_symbol_to_guid() - efi_name_to_guid() will now fall back on efi_symbol_to_guid() as a last resort - "efivar -L" to list all the guids we know about - better namespacing on libefivar.so (rename well_known_* -> efi_well_known_*) * Thu Sep 25 2014 Peter Jones - 0.12-1 - Update to 0.12 * Wed Aug 20 2014 Peter Jones - 0.11-1 - Update to 0.11 * Fri May 02 2014 Peter Jones - 0.10-1 - Update package to 0.10. - Fixes a build error due to different cflags in the builders vs updstream makefile. * Fri May 02 2014 Peter Jones - 0.9-0.1 - Update package to 0.9. * Tue Apr 01 2014 Peter Jones - 0.8-0.1 - Update package to 0.8 as well. * Fri Oct 25 2013 Peter Jones - 0.7-1 - Update package to 0.7 - adds --append support to the binary. * Fri Sep 06 2013 Peter Jones - 0.6-1 - Update package to 0.6 - fixes to documentation from lersek - more validation of uefi guids - use .xz for archives * Thu Sep 05 2013 Peter Jones - 0.5-0.1 - Update to 0.5 * Mon Jun 17 2013 Peter Jones - 0.4-0.2 - Fix ldconfig invocation * Mon Jun 17 2013 Peter Jones - 0.4-0.1 - Initial spec file efivar-0.21/src/000077500000000000000000000000001255101430600134745ustar00rootroot00000000000000efivar-0.21/src/.gitignore000066400000000000000000000000251255101430600154610ustar00rootroot00000000000000*.bin efivar-guids.h efivar-0.21/src/Makefile000066400000000000000000000074411255101430600151420ustar00rootroot00000000000000SRCDIR = $(realpath .) TOPDIR = $(realpath ..) include $(TOPDIR)/Make.defaults include $(TOPDIR)/Make.version LIBTARGETS = $(foreach x,libefivar libefiboot,$(x).so.$(VERSION) $(x).so.$(MAJOR_VERSION)) PCTARGETS = efivar.pc efiboot.pc BINTARGETS = efivar INCTARGETS = include/efivar/efivar-guids.h all : $(EFIVAR_DEPS) $(INCTARGETS) deps all : $(LIBTARGETS) $(PCTARGETS) $(BINTARGETS) libefiboot.so @$(MAKE) -C test TOPDIR=$(TOPDIR) SRCDIR=$(SRCDIR)/test $@ EFIVAR_OBJECTS = dp.o dp-acpi.o dp-hw.o dp-media.o dp-message.o \ efivarfs.o export.o guid.o guidlist.o guid-symbols.o \ lib.o vars.o # c files (alphabetically), then local headers (alphabetically), # then target headers (again alphabetically) EFIVAR_DEPS = .dp.c.P .dp-acpi.c.P .dp-hw.c.P .dp-media.c.P .dp-message.c.P \ .efivar.c.P .efivarfs.c.P .export.c.P .guid.c.P .lib.c.P .vars.c.P \ .dp.h.P .generics.h.P .guid.h.P .lib.h.P \ include/efivar/.efivar.h.P include/efivar/.efivar-dp.h.P \ include/efivar/.efivar-guids.h.P EFIVAR_LIBS = dl MAKEGUIDS_DEPS = .makeguids.c.P include/efivar/.efivar.h.P .util.h.P .guid.h.P EFIBOOT_OBJECTS = \ crc32.o creator.o disk.o gpt.o linux.o loadopt.o EFIBOOT_DEPS = \ .crc32.c.P .crc32.h.P .creator.c.P .disk.c.P .disk.h.P \ .gpt.c.P .gpt.h.P .linux.c.P .linux.h.P .loadopt.c.P \ include/efivar/.efiboot-creator.h.P \ include/efivar/.efiboot-loadopt.h.P libefivar.a :: $(EFIVAR_OBJECTS) libefivar.so.$(VERSION) : LIBS = $(EFIVAR_LIBS) libefivar.so.$(VERSION) : $(EFIVAR_OBJECTS) libefiboot.a :: $(EFIBOOT_OBJECTS) libefiboot.so.$(VERSION) : $(EFIBOOT_OBJECTS) libefivar.so efivar : efivar.o libefivar.so $(CCLD) $(ccldflags) -L. -lefivar -o $@ $^ \ -lpopt $(foreach lib,$(EFIVAR_LIBS),-l$(lib)) efivar-static : efivar.o libefivar.a $(CCLD) $(ccldflags) -static -L. -o $@ $^ \ -lpopt $(foreach lib,$(EFIVAR_LIBS),-l$(lib)) %.pc : %.pc.in sed -e "s,@@VERSION@@,$(VERSION),g" \ -e "s,@@LIBDIR@@,$(libdir),g" \ $< > $@ include/efivar/efivar.h : include/efivar/efivar-guids.h fakeguid.o : guid.c $(CC) $(cflags) -DEFIVAR_BUILD_ENVIRONMENT -c -o $@ $< makeguids.o : makeguids.c $(CC) $(cflags) -DEFIVAR_BUILD_ENVIRONMENT -c -o $@ $< makeguids : makeguids.o fakeguid.o $(CC) $(cflags) -o $@ $^ -ldl include/efivar/efivar-guids.h : makeguids guids.txt ./makeguids guids.txt guids.bin names.bin guid-symbols.S $@ guidlist.o : guids.S include/efivar/efivar-guids.h $(CC) $(cflags) -c -o guidlist.o guids.S guid-symbols.o : guid-symbols.S $(CC) $(cflags) -c -o $@ $< .INTERMEDIATE: guids.bin names.bin guid-symbols.S deps : $(EFIVAR_DEPS) $(EFIBOOT_DEPS) $(MAKEGUIDS_DEPS) -include $(EFIVAR_DEPS) -include $(EFIBOOT_DEPS) -include $(MAKEGUIDS_DEPS) clean : @rm -rfv *~ *.o *.a *.so *.so.$(MAJOR_VERSION) *.so.$(VERSION) .*.c.P .*.h.P $(PCTARGETS) $(BINTARGETS) $(INCTARGETS) *.bin guid-symbols.S makeguids include/efivar/.*.h.P $(LIBTARGETS) @$(MAKE) -C test TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/src/ $@ install : all $(INSTALL) -d -m 755 $(DESTDIR)$(libdir) $(foreach x, $(LIBTARGETS), $(INSTALL) -m 755 $(x) $(DESTDIR)$(libdir);) $(INSTALL) -d -m 755 $(DESTDIR)$(PCDIR) $(foreach x, $(PCTARGETS), $(INSTALL) -m 644 $(x) $(DESTDIR)$(PCDIR) ;) $(INSTALL) -d -m 755 $(DESTDIR)$(includedir)/efivar $(foreach x, $(wildcard $(TOPDIR)/src/include/efivar/*.h), $(INSTALL) -m 644 $(x) $(DESTDIR)$(includedir)/efivar/$(notdir $(x));) $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) $(foreach x, $(BINTARGETS), $(INSTALL) -m 755 $(x) $(DESTDIR)$(bindir);) $(foreach x, $(wildcard *.so.$(VERSION)), ln -fs $(x) $(patsubst %.so.$(VERSION),%.so,$(DESTDIR)$(libdir)/$(x));) $(foreach x, $(wildcard *.so.$(VERSION)), ln -fs $(x) $(patsubst %.so.$(VERSION),%.so.$(MAJOR_VERSION),$(DESTDIR)$(libdir)/$(x));) test :all $(MAKE) -C test TOPDIR=$(TOPDIR) SRCDIR=$(TOPDIR)/src/ $@ .PHONY: all deps clean install test include $(TOPDIR)/Make.rules efivar-0.21/src/crc32.c000066400000000000000000000164051255101430600145620ustar00rootroot00000000000000/* * Dec 5, 2000 Matt Domsch * - Copied crc32.c from the linux/drivers/net/cipe directory. * - Now pass seed as an arg * - changed len to be an unsigned long * - changed crc32val to be a register * - License remains unchanged! It's still GPL-compatable! */ /* ============================================================= */ /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ /* code or tables extracted from it, as desired without restriction. */ /* */ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ /* polynomial $edb88320 */ /* */ /* -------------------------------------------------------------------- */ #include static uint32_t crc32_tab[] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; /* Return a 32-bit CRC of the contents of the buffer. */ uint32_t crc32(const void *buf, unsigned long len, uint32_t seed) { unsigned long i; register uint32_t crc32val; const unsigned char *s = buf; crc32val = seed; for (i = 0; i < len; i ++) { crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); } return crc32val; } efivar-0.21/src/crc32.h000066400000000000000000000021611255101430600145610ustar00rootroot00000000000000/* libparted - a library for manipulating disk partitions Copyright (C) 1998-2000 Free Software Foundation, Inc. crc32.h This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CRC32_H #define _CRC32_H #include /* * This computes a 32 bit CRC of the data in the buffer, and returns the CRC. * The polynomial used is 0xedb88320. */ extern uint32_t crc32 (const void *buf, unsigned long len, uint32_t seed); #endif /* _CRC32_H */ efivar-0.21/src/creator.c000066400000000000000000000175451255101430600153130ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "disk.h" #include "dp.h" #include "linux.h" #include "list.h" #include "util.h" static int __attribute__((__nonnull__ (1,2,3))) find_file(const char * const filepath, char **devicep, char **relpathp) { struct stat fsb = { 0, }; int rc; int ret = -1; FILE *mounts = NULL; char linkbuf[PATH_MAX+1] = ""; ssize_t linklen = 0; if (!filepath || !devicep || !relpathp) { errno = EINVAL; return -1; } linklen = strlen(filepath); if (linklen > PATH_MAX) { errno = ENAMETOOLONG; return -1; } strcpy(linkbuf, filepath); do { rc = stat(linkbuf, &fsb); if (rc < 0) return rc; if (S_ISLNK(fsb.st_mode)) { char tmp[PATH_MAX+1] = ""; ssize_t l; l = readlink(linkbuf, tmp, PATH_MAX); if (l < 0) return -1; tmp[l] = '\0'; linklen = l; strcpy(linkbuf, tmp); } else { break; } } while (1); mounts = fopen("/proc/self/mounts", "r"); if (mounts == NULL) return rc; struct mntent *me; while (1) { struct stat dsb = { 0, }; errno = 0; me = getmntent(mounts); if (!me) { if (feof(mounts)) errno = ENOENT; goto err; } if (me->mnt_fsname[0] != '/') continue; rc = stat(me->mnt_fsname, &dsb); if (rc < 0) { if (errno == ENOENT) continue; goto err; } if (!S_ISBLK(dsb.st_mode)) continue; if (dsb.st_rdev == fsb.st_dev) { ssize_t mntlen = strlen(me->mnt_dir); if (mntlen >= linklen) { errno = ENAMETOOLONG; goto err; } *devicep = strdup(me->mnt_fsname); if (!*devicep) goto err; *relpathp = strdup(linkbuf + mntlen); if (!*relpathp) { free(*devicep); *devicep = NULL; goto err; } ret = 0; break; } } err: if (mounts) endmntent(mounts); return ret; } static int open_disk(struct disk_info *info, int flags) { char *diskpath = NULL; int rc; rc = asprintfa(&diskpath, "/dev/%s", info->disk_name); if (rc < 0) return -1; return open(diskpath, flags); } static char * tilt_slashes(char *s) { char *p; for (p = s; *p; p++) if (*p == '/') *p = '\\'; return s; } ssize_t efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, va_list ap) { int rc; ssize_t ret = -1, off=0, sz; struct disk_info info = { 0, }; int fd = -1; int saved_errno; fd = open(devpath, O_RDONLY); if (fd < 0) goto err; rc = eb_disk_info_from_fd(fd, &info); if (rc < 0 && errno != ENOSYS) goto err; if (partition > 0) info.part = partition; if (options & EFIBOOT_ABBREV_EDD10) { va_list aq; va_copy(aq, ap); info.edd10_devicenum = va_arg(aq, uint32_t); va_end(aq); } if ((options & EFIBOOT_ABBREV_EDD10) && (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD))) { sz = efidp_make_edd10(buf, size, info.edd10_devicenum); if (sz < 0) return -1; off = sz; } else if (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD)) { /* * We're probably on a modern kernel, so just parse the * symlink from /sys/dev/block/$major:$minor and get it * from there. */ sz = make_blockdev_path(buf, size, fd, &info); if (sz < 0) return -1; off += sz; } if (!(options & EFIBOOT_ABBREV_FILE)) { int disk_fd; int saved_errno; int rc; rc = set_disk_and_part_name(&info); if (rc < 0) goto err; disk_fd = open_disk(&info, (options& EFIBOOT_OPTIONS_WRITE_SIGNATURE)?O_RDWR:O_RDONLY); if (disk_fd < 0) goto err; sz = make_hd_dn(buf, size, off, disk_fd, info.part, options); saved_errno = errno; close(disk_fd); errno = saved_errno; if (sz < 0) goto err; off += sz; } char *filepath = strdupa(relpath); tilt_slashes(filepath); sz = efidp_make_file(buf+off, size?size-off:0, filepath); if (sz < 0) goto err; off += sz; sz = efidp_make_end_entire(buf+off, size?size-off:0); if (sz < 0) goto err; off += sz; ret = off; err: saved_errno = errno; if (info.disk_name) { free(info.disk_name); info.disk_name = NULL; } if (info.part_name) { free(info.part_name); info.part_name = NULL; } if (fd >= 0) close(fd); errno = saved_errno; return ret; } ssize_t __attribute__((__nonnull__ (3, 5))) __attribute__((__visibility__ ("default"))) efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, ...) { ssize_t ret; int saved_errno; va_list ap; va_start(ap, options); ret = efi_va_generate_file_device_path_from_esp(buf, size, devpath, partition, relpath, options, ap); saved_errno = errno; va_end(ap); errno = saved_errno; return ret; } ssize_t __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))) efi_generate_file_device_path(uint8_t *buf, ssize_t size, const char * const filepath, uint32_t options, ...) { int rc; ssize_t ret = -1; char *devpath = NULL; char *relpath = NULL; va_list ap; int saved_errno; rc = find_file(filepath, &devpath, &relpath); if (rc < 0) return -1; rc = get_partition_number(devpath); if (rc < 0) goto err; va_start(ap, options); ret = efi_va_generate_file_device_path_from_esp(buf, size, devpath, 0, relpath, options, ap); saved_errno = errno; va_end(ap); errno = saved_errno; err: saved_errno = errno; if (devpath) free(devpath); if (relpath) free(relpath); errno = saved_errno; return ret; } static ssize_t __attribute__((__nonnull__ (3,4,5,6))) make_ipv4_path(uint8_t *buf, ssize_t size, const char * const local_addr, const char * const remote_addr, const char * const gateway_addr, const char * const netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, uint8_t addr_origin) { #if 0 if (local_addr == NULL || remote_addr == NULL || gateway_addr == NULL || netmask == NULL) { errno = EINVAL; return -1; } #endif return efidp_make_ipv4(buf, size, 0, 0, 0, 0, 0, 0, 0, 0); } ssize_t __attribute__((__nonnull__ (3,4,5,6,7))) __attribute__((__visibility__ ("default"))) efi_generate_ipv4_device_path(uint8_t *buf, ssize_t size, const char * const ifname, const char * const local_addr, const char * const remote_addr, const char * const gateway_addr, const char * const netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, uint8_t addr_origin) { ssize_t off = 0; ssize_t sz; sz = make_mac_path(buf, size, ifname); if (sz < 0) return -1; off += sz; sz = make_ipv4_path(buf+off, size?size-off:0, local_addr, remote_addr, gateway_addr, netmask, local_port, remote_port, protocol, addr_origin); if (sz < 0) return -1; off += sz; sz = efidp_make_end_entire(buf+off, size?size-off:0); if (sz < 0) return -1; off += sz; return off; } efivar-0.21/src/disk.c000066400000000000000000000151471255101430600146020ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2000-2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "crc32.h" #include "disk.h" #include "gpt.h" static int report_errors; /** * is_mbr_valid(): test MBR for validity * @mbr: pointer to a legacy mbr structure * * Description: Returns 1 if MBR is valid, 0 otherwise. * Validity depends on one thing: * 1) MSDOS signature is in the last two bytes of the MBR */ static inline int is_mbr_valid(legacy_mbr *mbr) { if (!mbr) return 0; return (mbr->signature == MSDOS_MBR_SIGNATURE); } /************************************************************ * msdos_disk_get_extended partition_info() * Requires: * - open file descriptor fd * - start, size * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ static int msdos_disk_get_extended_partition_info (int fd, legacy_mbr *mbr, uint32_t num, uint64_t *start, uint64_t *size) { /* Until I can handle these... */ //fprintf(stderr, "Extended partition info not supported.\n"); return -1; } /************************************************************ * msdos_disk_get_partition_info() * Requires: * - mbr * - open file descriptor fd (for extended partitions) * - start, size, signature, mbr_type, signature_type * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ static int msdos_disk_get_partition_info (int fd, int write_signature, legacy_mbr *mbr, uint32_t num, uint64_t *start, uint64_t *size, uint8_t *signature, uint8_t *mbr_type, uint8_t *signature_type) { int rc; long disk_size=0; struct stat stat; struct timeval tv; if (!mbr) return -1; if (!is_mbr_valid(mbr)) return -1; *mbr_type = 0x01; *signature_type = 0x01; if (!mbr->unique_mbr_signature && !write_signature && report_errors) { printf("\n\n******************************************************\n"); printf("Warning! This MBR disk does not have a unique signature.\n"); printf("If this is not the first disk found by EFI, you may not be able\n"); printf("to boot from it without a unique signature.\n"); printf("Run efibootmgr with the -w flag to write a unique signature\n"); printf("to the disk.\n"); printf("******************************************************\n\n"); } else if (!mbr->unique_mbr_signature && write_signature) { /* MBR Signatures must be unique for the EFI Boot Manager to find the right disk to boot from */ rc = fstat(fd, &stat); if (rc < 0) { if (report_errors) perror("stat disk"); return rc; } rc = gettimeofday(&tv, NULL); if (rc < 0) { if (report_errors) perror("gettimeofday"); return rc; } /* Write the device type to the signature. This should be unique per disk per system */ mbr->unique_mbr_signature = tv.tv_usec << 16; mbr->unique_mbr_signature |= stat.st_rdev & 0xFFFF; /* Write it to the disk */ lseek(fd, 0, SEEK_SET); rc = write(fd, mbr, sizeof(*mbr)); } *(uint32_t *)signature = mbr->unique_mbr_signature; if (num > 4) { /* Extended partition */ return msdos_disk_get_extended_partition_info(fd, mbr, num, start, size); } else if (num == 0) { /* Whole disk */ *start = 0; ioctl(fd, BLKGETSIZE, &disk_size); *size = disk_size; } else if (num >= 1 && num <= 4) { /* Primary partition */ *start = mbr->partition[num-1].starting_lba; *size = mbr->partition[num-1].size_in_lba; } return 0; } static int get_partition_info(int fd, uint32_t options, uint32_t part, uint64_t *start, uint64_t *size, uint8_t *signature, uint8_t *mbr_type, uint8_t *signature_type) { legacy_mbr *mbr; void *mbr_sector; size_t mbr_size; off_t offset __attribute__((unused)); int this_bytes_read = 0; int gpt_invalid=0, mbr_invalid=0; int rc=0; int sector_size = get_sector_size(fd); mbr_size = lcm(sizeof(*mbr), sector_size); if ((rc = posix_memalign(&mbr_sector, sector_size, mbr_size)) != 0) goto error; memset(mbr_sector, '\0', mbr_size); offset = lseek(fd, 0, SEEK_SET); this_bytes_read = read(fd, mbr_sector, mbr_size); if (this_bytes_read < (ssize_t)sizeof(*mbr)) { rc=1; goto error_free_mbr; } mbr = (legacy_mbr *)mbr_sector; gpt_invalid = gpt_disk_get_partition_info(fd, part, start, size, signature, mbr_type, signature_type, (options & EFIBOOT_OPTIONS_IGNORE_PMBR_ERR)?1:0); if (gpt_invalid) { mbr_invalid = msdos_disk_get_partition_info(fd, (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE)?1:0, mbr, part, start, size, signature, mbr_type, signature_type); if (mbr_invalid) { rc=1; goto error_free_mbr; } } error_free_mbr: free(mbr_sector); error: return rc; } ssize_t __attribute__((__visibility__ ("hidden"))) _make_hd_dn(uint8_t *buf, ssize_t size, int fd, uint32_t partition, uint32_t options) { uint64_t part_start=0, part_size = 0; uint8_t signature[16]="", format=0, signature_type=0; int rc; char *report=getenv("LIBEFIBOOT_REPORT_GPT_ERRORS"); if (report) report_errors = 1; errno = 0; rc = get_partition_info(fd, options, partition>0?partition:1, &part_start, &part_size, signature, &format, &signature_type); if (rc < 0) return rc; return efidp_make_hd(buf, size, partition>0?partition:1, part_start, part_size, signature, format, signature_type); } efivar-0.21/src/disk.h000066400000000000000000000022761255101430600146060ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #ifndef _EFIBOOT_DISK_H #define _EFIBOOT_DISK_H extern ssize_t _make_hd_dn(uint8_t *buf, ssize_t size, int fd, uint32_t partition, uint32_t options) __attribute__((__visibility__ ("hidden"))); #define make_hd_dn(buf, size, off, fd, partition, option) \ _make_hd_dn(((buf)+(off)), ((size)?((size)-(off)):0), (fd),\ (partition), (options)) #endif /* _EFIBOOT_DISK_H */ efivar-0.21/src/dp-acpi.c000066400000000000000000000132141255101430600151560ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include "dp.h" static ssize_t _format_acpi_adr(char *buf, size_t size, const_efidp dp) { ssize_t o = 0; o += format(buf, size, o, "AcpiAdr("); o += format_array(buf, size, o, "%"PRIu32, typeof(dp->acpi_adr.adr[0]), dp->acpi_adr.adr, (efidp_node_size(dp)-4)/sizeof (dp->acpi_adr.adr[0])); o += format(buf, size, o, ")"); return o; } #define format_acpi_adr(buf, size, off, dp) \ _format_acpi_adr(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) ssize_t __attribute__((__visibility__ ("default"))) _format_acpi_dn(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; const char *hidstr = NULL; size_t hidlen = 0; const char *uidstr = NULL; size_t uidlen = 0; const char *cidstr = NULL; size_t cidlen = 0; if (dp->subtype == EFIDP_ACPI_ADR) return format_acpi_adr(buf, size, off, dp); if (dp->subtype != EFIDP_ACPI_HID_EX && dp->subtype != EFIDP_ACPI_HID) { off += format(buf, size, off, "AcpiPath(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, (efidp_node_size(dp)-4) / 2); off += format(buf, size, off, ")"); return off; } if (dp->subtype == EFIDP_ACPI_HID_EX) { ssize_t limit = efidp_node_size(dp) - offsetof(efidp_acpi_hid_ex, hidstr); hidstr = dp->acpi_hid_ex.hidstr; hidlen = strnlen(hidstr, limit); limit -= hidlen + 1; uidstr = hidstr + hidlen + 1; uidlen = strnlen(uidstr, limit); limit -= uidlen + 1; cidstr = uidstr + uidlen + 1; cidlen = strnlen(cidstr, limit); limit -= cidlen + 1; if (uidstr) { switch (dp->acpi_hid.hid) { case EFIDP_ACPI_PCI_ROOT_HID: off += format(buf, size, off, "PciRoot(%s)", uidstr); return off; case EFIDP_ACPI_PCIE_ROOT_HID: off += format(buf, size, off, "PcieRoot(%s)", uidstr); return off; } } } switch (dp->acpi_hid.hid) { case EFIDP_ACPI_PCI_ROOT_HID: off += format(buf, size, off, "PciRoot(0x%"PRIx32")", dp->acpi_hid.uid); return off; case EFIDP_ACPI_PCIE_ROOT_HID: off += format(buf, size, off, "PcieRoot(0x%"PRIx32")", dp->acpi_hid.uid); return off; case EFIDP_ACPI_FLOPPY_HID: off += format(buf, size, off, "Floppy(0x%"PRIx32")", dp->acpi_hid.uid); return off; case EFIDP_ACPI_KEYBOARD_HID: off += format(buf, size, off, "Keyboard(0x%"PRIx32")", dp->acpi_hid.uid); return off; case EFIDP_ACPI_SERIAL_HID: off += format(buf, size, off, "Serial(0x%"PRIx32")", dp->acpi_hid.uid); return off; default: switch (dp->subtype) { case EFIDP_ACPI_HID_EX: if (!hidstr && !cidstr && (uidstr || dp->acpi_hid_ex.uid)){ off += format(buf, size, off, "AcpiExp(0x%"PRIx32",0x%"PRIx32",", dp->acpi_hid_ex.hid, dp->acpi_hid_ex.cid); if (uidstr) off += format(buf, size, off, "%s)", uidstr); else off += format(buf, size, off, "0x%"PRIx32")", dp->acpi_hid.uid); return off; } off += format(buf, size, off, "AcpiEx("); if (hidstr) off += format(buf, size, off, "%s,", hidstr); else off += format(buf, size, off, "0x%"PRIx32",", dp->acpi_hid.hid); if (cidstr) off += format(buf, size, off, "%s,", cidstr); else off += format(buf, size, off, "0x%"PRIx32",", dp->acpi_hid_ex.cid); if (uidstr) off += format(buf, size, off, "%s)", uidstr); else off += format(buf, size, off, "0x%"PRIx32")", dp->acpi_hid.uid); return off; case EFIDP_ACPI_HID: off += format(buf, size, off, "Acpi(0x%"PRIx32",0x%"PRIx32")", dp->acpi_hid.hid, dp->acpi_hid.uid); return off; } } return off; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_acpi_hid(uint8_t *buf, ssize_t size, uint32_t hid, uint32_t uid) { efidp_acpi_hid *acpi_hid = (efidp_acpi_hid *)buf; ssize_t req = sizeof (*acpi_hid); ssize_t sz; sz = efidp_make_generic(buf, size, EFIDP_ACPI_TYPE, EFIDP_ACPI_HID, sizeof (*acpi_hid)); if (size && sz == req) { acpi_hid->uid = uid; acpi_hid->hid = hid; } return sz; } ssize_t __attribute__((__visibility__ ("default"))) __attribute__((__nonnull__ (6,7,8))) efidp_make_acpi_hid_ex(uint8_t *buf, ssize_t size, uint32_t hid, uint32_t uid, uint32_t cid, char *hidstr, char *uidstr, char *cidstr) { efidp_acpi_hid_ex *acpi_hid = (efidp_acpi_hid_ex *)buf; ssize_t req; ssize_t sz; if (!hidstr || !uidstr || !cidstr) { errno = EINVAL; return -1; } req = sizeof (*acpi_hid) + 3 + strlen(hidstr) + strlen(uidstr) + strlen(cidstr); sz = efidp_make_generic(buf, size, EFIDP_ACPI_TYPE, EFIDP_ACPI_HID_EX, req); if (size && sz == req) { acpi_hid->uid = uid; acpi_hid->hid = hid; acpi_hid->cid = cid; char *next = (char *)buf+offsetof(efidp_acpi_hid_ex, hidstr); strcpy(next, hidstr); next += strlen(hidstr) + 1; strcpy(next, uidstr); next += strlen(uidstr) + 1; strcpy(next, cidstr); } return sz; } efivar-0.21/src/dp-hw.c000066400000000000000000000065011255101430600146610ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include "dp.h" ssize_t __attribute__((__visibility__ ("default"))) format_edd10_guid(char *buf, size_t size, const_efidp dp) { size_t off = 0; efidp_edd10 const *edd_dp = (efidp_edd10 *)dp; off = format(buf, size, off, "EDD10(0x%"PRIx32")", edd_dp->hardware_device); return off; } ssize_t __attribute__((__visibility__ ("default"))) _format_hw_dn(char *buf, size_t size, const_efidp dp) { efi_guid_t edd10_guid = EDD10_HARDWARE_VENDOR_PATH_GUID; off_t off = 0; switch (dp->subtype) { case EFIDP_HW_PCI: off += format(buf, size, off, "Pci(0x%"PRIx32",0x%"PRIx32")", dp->pci.device, dp->pci.function); break; case EFIDP_HW_PCCARD: off += format(buf, size, off, "PcCard(0x%"PRIx32")", dp->pccard.function); break; case EFIDP_HW_MMIO: off += format(buf, size, off, "MemoryMapped(%"PRIu32",0x%"PRIx64",0x%"PRIx64")", dp->mmio.memory_type, dp->mmio.starting_address, dp->mmio.ending_address); break; case EFIDP_HW_VENDOR: if (!efi_guid_cmp(&dp->hw_vendor.vendor_guid, &edd10_guid)) { off += format_helper(format_edd10_guid, buf, size, off, dp); } else { off += format_vendor(buf, size, off, "VenHw", dp); } break; case EFIDP_HW_CONTROLLER: off += format(buf, size, off, "Ctrl(0x%"PRIx32")", dp->controller.controller); break; case EFIDP_HW_BMC: off += format(buf, size, off, "BMC(%d,0x%"PRIx64")", dp->bmc.interface_type, dp->bmc.base_addr); break; default: off += format(buf, size, off, "HardwarePath(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, efidp_node_size(dp)-4); off += format(buf,size,off,")"); break; } return off; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_pci(uint8_t *buf, ssize_t size, uint8_t device, uint8_t function) { efidp_pci *pci = (efidp_pci *)buf; ssize_t sz; ssize_t req = sizeof (*pci); sz = efidp_make_generic(buf, size, EFIDP_HARDWARE_TYPE, EFIDP_HW_PCI, req); if (size && sz == req) { pci->device = device; pci->function = function; } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_edd10(uint8_t *buf, ssize_t size, uint32_t hardware_device) { efi_guid_t edd10_guid = EDD10_HARDWARE_VENDOR_PATH_GUID; efidp_edd10 *edd_dp = (efidp_edd10 *)buf; ssize_t sz; ssize_t req = sizeof (*edd_dp); sz = efidp_make_generic(buf, size, EFIDP_HARDWARE_TYPE, EFIDP_HW_VENDOR, req); if (size && sz == req) { memcpy(&edd_dp->vendor_guid, &edd10_guid, sizeof (edd10_guid)); edd_dp->hardware_device = hardware_device; } return sz; } efivar-0.21/src/dp-media.c000066400000000000000000000130521255101430600153210ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include "dp.h" ssize_t __attribute__((__visibility__ ("default"))) _format_media_dn(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; switch (dp->subtype) { case EFIDP_MEDIA_HD: off += format(buf, size, off, "HD(%d,", dp->hd.partition_number); switch (dp->hd.signature_type) { case EFIDP_HD_SIGNATURE_MBR: off += format(buf, size, off, "MBR,0x%"PRIu32",0x%"PRIx64",0x%"PRIx64")", *(char *)dp->hd.signature, dp->hd.start, dp->hd.size); break; case EFIDP_HD_SIGNATURE_GUID: off += format(buf, size, off, "GPT,"); off += format_guid(buf, size, off, (efi_guid_t *)dp->hd.signature); off += format(buf, size, off, ",0x%"PRIx64",0x%"PRIx64")", dp->hd.start, dp->hd.size); break; default: off += format(buf, size, off, "%d,", dp->hd.signature_type); off += format_hex(buf, size, off, dp->hd.signature, sizeof(dp->hd.signature)); off += format(buf, size, off, ",0x%"PRIx64",0x%"PRIx64")", dp->hd.start, dp->hd.size); break; } break; case EFIDP_MEDIA_CDROM: off += format(buf, size, off, "CDROM(%d,0x%"PRIx64",0x%"PRIx64")", dp->cdrom.boot_catalog_entry, dp->cdrom.partition_rba, dp->cdrom.sectors); break; case EFIDP_MEDIA_VENDOR: off += format_vendor(buf, size, off, "VenMedia", dp); break; case EFIDP_MEDIA_FILE: off += format(buf, size, off, "File("); off += format_ucs2(buf, size, off, dp->file.name, (efidp_node_size(dp) - offsetof(efidp_file, name)) / 2); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_PROTOCOL: off += format(buf, size, off, "Media("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_FIRMWARE_FILE: off += format(buf, size, off, "FvFile("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_FIRMWARE_VOLUME: off += format(buf, size, off, "FvVol("); off += format_guid(buf, size, off, &dp->protocol.protocol_guid); off += format(buf, size, off, ")"); break; case EFIDP_MEDIA_RELATIVE_OFFSET: off = format(buf, size, off, "Offset(0x%"PRIx64",0x%"PRIx64")", dp->relative_offset.first_byte, dp->relative_offset.last_byte); break; case EFIDP_MEDIA_RAMDISK: { struct { efi_guid_t guid; char label[40]; } subtypes[] = { { EFIDP_VIRTUAL_DISK_GUID, "VirtualDisk" }, { EFIDP_VIRTUAL_CD_GUID, "VirtualCD" }, { EFIDP_PERSISTENT_VIRTUAL_DISK_GUID, "PersistentVirtualDisk" }, { EFIDP_PERSISTENT_VIRTUAL_CD_GUID, "PersistentVirtualCD" }, { efi_guid_empty, "" } }; char *label = NULL; for (int i = 0; !efi_guid_is_zero(&subtypes[i].guid); i++) { if (efi_guid_cmp(&subtypes[i].guid, &dp->ramdisk.disk_type_guid)) continue; label = subtypes[i].label; break; } if (label) { off += format(buf, size, off, "%s(0x%"PRIx64",0x%"PRIx64",%d)", label, dp->ramdisk.start_addr, dp->ramdisk.end_addr, dp->ramdisk.instance_number); break; } off += format(buf, size, off, "Ramdisk(0x%"PRIx64",0x%"PRIx64",%d,", dp->ramdisk.start_addr, dp->ramdisk.end_addr, dp->ramdisk.instance_number); off += format_guid(buf, size, off, &dp->ramdisk.disk_type_guid); off += format(buf, size, off, ")"); break; } default: off += format(buf, size, off, "MediaPath(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, (efidp_node_size(dp)-4) / 2); off += format(buf,size,off,")"); break; } return off; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_file(uint8_t *buf, ssize_t size, char *filepath) { efidp_file *file = (efidp_file *)buf; unsigned char *lf = (unsigned char *)filepath; ssize_t sz; ssize_t len = utf8len(lf, -1) + 1; ssize_t req = sizeof (*file) + len * sizeof (uint16_t); sz = efidp_make_generic(buf, size, EFIDP_MEDIA_TYPE, EFIDP_MEDIA_FILE, req); if (size && sz == req) { memset(buf+4, 0, req-4); utf8_to_ucs2(file->name, req-4, 1, lf); } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_hd(uint8_t *buf, ssize_t size, uint32_t num, uint64_t part_start, uint64_t part_size, uint8_t *signature, uint8_t format, uint8_t signature_type) { efidp_hd *hd = (efidp_hd *)buf; ssize_t sz; ssize_t req = sizeof (*hd); sz = efidp_make_generic(buf, size, EFIDP_MEDIA_TYPE, EFIDP_MEDIA_HD, req); if (size && sz == req) { hd->partition_number = num; hd->start = part_start; hd->size = part_size; if (signature) memcpy(hd->signature, signature, sizeof (hd->signature)); hd->format = format; hd->signature_type = signature_type; } return sz; } efivar-0.21/src/dp-message.c000066400000000000000000000474101255101430600156730ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include "endian.h" #include "dp.h" static ssize_t format_ipv6_port_helper(char *buffer, size_t buffer_size, uint8_t const *ipaddr, uint16_t port) { uint16_t *ip = (uint16_t *)ipaddr; off_t offset = 0; ssize_t needed; needed = snprintf(buffer, buffer_size, "["); if (needed < 0) return -1; offset += needed; // deciding how to print an ipv6 ip requires 2 passes, because // RFC5952 says we have to use :: a) only once and b) to maximum effect. int largest_zero_block_size = 0; int largest_zero_block_offset = -1; int this_zero_block_size = 0; int this_zero_block_offset = -1; int in_zero_block = 0; int i; for (i = 0; i < 8; i++) { if (ip[i] != 0 && in_zero_block) { if (this_zero_block_size > largest_zero_block_size) { largest_zero_block_size = this_zero_block_size; largest_zero_block_offset = this_zero_block_offset; this_zero_block_size = 0; this_zero_block_offset = -1; in_zero_block = 0; } } if (ip[i] == 0) { if (in_zero_block == 0) { in_zero_block = 1; this_zero_block_offset = i; } this_zero_block_size++; } } if (this_zero_block_size > largest_zero_block_size) { largest_zero_block_size = this_zero_block_size; largest_zero_block_offset = this_zero_block_offset; this_zero_block_size = 0; this_zero_block_offset = -1; in_zero_block = 0; } if (largest_zero_block_size == 1) largest_zero_block_offset = -1; for (i = 0; i < 8; i++) { if (largest_zero_block_offset == i) { needed = snprintf(buffer + offset, buffer_size == 0 ? 0 : buffer_size - offset, "::"); if (needed < 0) return -1; offset += needed; i += largest_zero_block_size -1; continue; } else if (i > 0) { needed = snprintf(buffer + offset, buffer_size == 0 ? 0 : buffer_size - offset, ":"); if (needed < 0) return -1; offset += needed; } needed = snprintf(buffer + offset, buffer_size == 0 ? 0 : buffer_size - offset, "%x", ip[i]); if (needed < 0) return -1; offset += needed; } needed = snprintf(buffer + offset, buffer_size == 0 ? 0 : buffer_size - offset, "]:%d", port); if (needed < 0) return -1; offset += needed; return offset; } #define format_ipv6_port(buf, size, off, ipaddr, port) \ format_helper(format_ipv6_port_helper, buf, size, off, ipaddr, port) static ssize_t format_uart(char *buf, size_t size, const_efidp dp) { uint32_t value; ssize_t off = 0; char *labels[] = {"None", "Hardware", "XonXoff", ""}; value = dp->uart_flow_control.flow_control_map; if (value > 2) { return format(buf, size, off, "UartFlowcontrol(%d)", value); } return format(buf, size, off, "UartFlowControl(%s)", labels[value]); } static ssize_t format_sas(char *buf, size_t size, const_efidp dp) { size_t off = 0; const efidp_sas * const s = &dp->sas; int more_info = 0; int sassata = 0; int location = 0; int connect = 0; int drive_bay = -1; const char * const sassata_label[] = {"NoTopology", "SAS", "SATA"}; const char * const location_label[] = {"Internal", "External" }; const char * const connect_label[] = {"Direct", "Expanded" }; more_info = s->device_topology_info & EFIDP_SAS_TOPOLOGY_MASK; if (more_info) { sassata = (s->device_topology_info & EFIDP_SAS_DEVICE_MASK) >> EFIDP_SAS_DEVICE_SHIFT; if (sassata == EFIDP_SAS_DEVICE_SATA_EXTERNAL || sassata == EFIDP_SAS_DEVICE_SAS_EXTERNAL) location = 1; if (sassata == EFIDP_SAS_DEVICE_SAS_INTERNAL || sassata == EFIDP_SAS_DEVICE_SATA_INTERNAL) sassata = 1; else sassata = 2; connect = (s->device_topology_info & EFIDP_SAS_CONNECT_MASK) >> EFIDP_SAS_CONNECT_SHIFT; if (more_info == EFIDP_SAS_TOPOLOGY_NEXTBYTE) drive_bay = s->drive_bay_id + 1; } off += format(buf, size, off, "SAS(%"PRIx64",%"PRIx64",%"PRIx16",%s", dp->subtype == EFIDP_MSG_SAS_EX ? be64_to_cpu(s->sas_address) : le64_to_cpu(s->sas_address), dp->subtype == EFIDP_MSG_SAS_EX ? be64_to_cpu(s->lun) : le64_to_cpu(s->lun), s->rtp, sassata_label[sassata]); if (more_info) off += format(buf, size, off, ",%s,%s", location_label[location], connect_label[connect]); if (more_info == 2 && drive_bay >= 0) off += format(buf, size, off, ",%d", drive_bay); off += format(buf, size, off, ")"); return off; } #define class_helper(buf, size, off, label, dp) ({ \ off += format(buf, size, off, \ "%s(0x%"PRIx16",0x%"PRIx16",%d,%d)", \ label, \ dp->usb_class.vendor_id, \ dp->usb_class.product_id, \ dp->usb_class.device_subclass, \ dp->usb_class.device_protocol); \ off; \ }) static ssize_t format_usb_class(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; switch (dp->usb_class.device_class) { case EFIDP_USB_CLASS_AUDIO: off += class_helper(buf, size, off, "UsbAudio", dp); break; case EFIDP_USB_CLASS_CDC_CONTROL: off += class_helper(buf, size, off, "UsbCDCControl", dp); break; case EFIDP_USB_CLASS_HID: off += class_helper(buf, size, off, "UsbHID", dp); break; case EFIDP_USB_CLASS_IMAGE: off += class_helper(buf, size, off, "UsbImage", dp); break; case EFIDP_USB_CLASS_PRINTER: off += class_helper(buf, size, off, "UsbPrinter", dp); break; case EFIDP_USB_CLASS_MASS_STORAGE: off += class_helper(buf, size, off, "UsbMassStorage", dp); break; case EFIDP_USB_CLASS_HUB: off += class_helper(buf, size, off, "UsbHub", dp); break; case EFIDP_USB_CLASS_CDC_DATA: off += class_helper(buf, size, off, "UsbCDCData", dp); break; case EFIDP_USB_CLASS_SMARTCARD: off += class_helper(buf, size, off, "UsbSmartCard", dp); break; case EFIDP_USB_CLASS_VIDEO: off += class_helper(buf, size, off, "UsbVideo", dp); break; case EFIDP_USB_CLASS_DIAGNOSTIC: off += class_helper(buf, size, off, "UsbDiagnostic", dp); break; case EFIDP_USB_CLASS_WIRELESS: off += class_helper(buf, size, off, "UsbWireless", dp); break; case EFIDP_USB_CLASS_254: switch (dp->usb_class.device_subclass) { case EFIDP_USB_SUBCLASS_FW_UPDATE: off += format(buf, size, off, "UsbDeviceFirmwareUpdate(0x%"PRIx16",0x%"PRIx16",%d)", dp->usb_class.vendor_id, dp->usb_class.product_id, dp->usb_class.device_protocol); break; case EFIDP_USB_SUBCLASS_IRDA_BRIDGE: off += format(buf, size, off, "UsbIrdaBridge(0x%"PRIx16",0x%"PRIx16",%d)", dp->usb_class.vendor_id, dp->usb_class.product_id, dp->usb_class.device_protocol); break; case EFIDP_USB_SUBCLASS_TEST_AND_MEASURE: off += format(buf, size, off, "UsbTestAndMeasurement(0x%"PRIx16",0x%"PRIx16",%d)", dp->usb_class.vendor_id, dp->usb_class.product_id, dp->usb_class.device_protocol); break; } break; default: off += format(buf, size, off, "UsbClass(%"PRIx16",%"PRIx16",%d,%d)", dp->usb_class.vendor_id, dp->usb_class.product_id, dp->usb_class.device_subclass, dp->usb_class.device_protocol); break; } return off; } ssize_t __attribute__((__visibility__ ("default"))) _format_message_dn(char *buf, size_t size, const_efidp dp) { ssize_t off = 0; ssize_t sz; switch (dp->subtype) { case EFIDP_MSG_ATAPI: off += format(buf, size, off, "Ata(%d,%d,%d)", dp->atapi.primary, dp->atapi.slave, dp->atapi.lun); break; case EFIDP_MSG_SCSI: off += format(buf, size, off, "SCSI(%d,%d)", dp->scsi.target, dp->scsi.lun); break; case EFIDP_MSG_FIBRECHANNEL: off += format(buf, size, off, "Fibre(%"PRIx64",%"PRIx64")", le64_to_cpu(dp->fc.wwn), le64_to_cpu(dp->fc.lun)); break; case EFIDP_MSG_FIBRECHANNELEX: off += format(buf, size, off, "Fibre(%"PRIx64",%"PRIx64")", be64_to_cpu(dp->fc.wwn), be64_to_cpu(dp->fc.lun)); break; case EFIDP_MSG_1394: off += format(buf, size, off, "I1394(0x%"PRIx64")", dp->firewire.guid); break; case EFIDP_MSG_USB: off += format(buf, size, off, "USB(%d,%d)", dp->usb.parent_port, dp->usb.interface); break; case EFIDP_MSG_I2O: off += format(buf, size, off, "I2O(%d)", dp->i2o.target); break; case EFIDP_MSG_INFINIBAND: if (dp->infiniband.resource_flags & EFIDP_INFINIBAND_RESOURCE_IOC_SERVICE) { off += format(buf, size, off, "Infiniband(%08x,%"PRIx64"%"PRIx64",%"PRIx64",%"PRIu64",%"PRIu64")", dp->infiniband.resource_flags, dp->infiniband.port_gid[1], dp->infiniband.port_gid[0], dp->infiniband.service_id, dp->infiniband.target_port_id, dp->infiniband.device_id); } else { off += format(buf, size, off, "Infiniband(%08x,%"PRIx64"%"PRIx64",", dp->infiniband.resource_flags, dp->infiniband.port_gid[1], dp->infiniband.port_gid[0]); off += format_guid(buf, size, off, (efi_guid_t *) &dp->infiniband.ioc_guid); off += format(buf, size, off, ",%"PRIu64",%"PRIu64")", dp->infiniband.target_port_id, dp->infiniband.device_id); } break; case EFIDP_MSG_MAC_ADDR: off += format(buf, size, off, "MAC("); off += format_hex(buf, size, off, dp->mac_addr.mac_addr, dp->mac_addr.if_type < 2 ? 6 : sizeof(dp->mac_addr.mac_addr)); off += format(buf, size, off, ",%d)", dp->mac_addr.if_type); break; case EFIDP_MSG_IPv4: { efidp_ipv4_addr const *a = &dp->ipv4_addr; off += format(buf, size, off, "IPv4(%hhu.%hhu.%hhu.%hhu:%hu<->%hhu.%hhu.%hhu.%hhu:%hu,%hx,%hhx)", a->local_ipv4_addr[0], a->local_ipv4_addr[1], a->local_ipv4_addr[2], a->local_ipv4_addr[3], a->local_port, a->remote_ipv4_addr[0], a->remote_ipv4_addr[1], a->remote_ipv4_addr[2], a->remote_ipv4_addr[3], a->remote_port, a->protocol, a->static_ip_addr); break; } case EFIDP_MSG_VENDOR: { struct { efi_guid_t guid; char label[40]; ssize_t (*formatter)(char *buf, size_t size, const_efidp dp); } subtypes[] = { { EFIDP_PC_ANSI_GUID, "VenPcAnsi" }, { EFIDP_VT_100_GUID, "VenVt100" }, { EFIDP_VT_100_PLUS_GUID, "VenVt100Plus" }, { EFIDP_VT_UTF8_GUID, "VenUtf8" }, { EFIDP_MSG_DEBUGPORT_GUID, "DebugPort" }, { EFIDP_MSG_UART_GUID, "", format_uart }, { EFIDP_MSG_SAS_GUID, "", format_sas }, { efi_guid_empty, "" } }; char *label = NULL; ssize_t (*formatter)(char *buf, size_t size, const_efidp dp) = NULL; for (int i = 0; !efi_guid_is_zero(&subtypes[i].guid); i++) { if (efi_guid_cmp(&subtypes[i].guid, &dp->msg_vendor.vendor_guid)) continue; label = subtypes[i].label; formatter = subtypes[i].formatter; break; } if (!label && !formatter) { off += format_vendor(buf, size, off, "VenMsg", dp); break; } else if (formatter) { off += format_helper(formatter, buf, size, off, dp); break; } off += format(buf, size, off, "%s(", label); if (efidp_node_size(dp) > (ssize_t)(sizeof (efidp_header) + sizeof (efi_guid_t))) { off += format_hex(buf, size, off, dp->msg_vendor.vendor_data, efidp_node_size(dp) - sizeof (efidp_header) - sizeof (efi_guid_t)); } break; } case EFIDP_MSG_IPv6: { efidp_ipv6_addr const *a = &dp->ipv6_addr; char *addr0 = NULL; char *addr1 = NULL; sz = format_ipv6_port(addr0, 0, 0, a->local_ipv6_addr, a->local_port); if (sz < 0) return sz; addr0 = alloca(sz+1); sz = format_ipv6_port(addr0, sz, 0, a->local_ipv6_addr, a->local_port); if (sz < 0) return sz; sz = format_ipv6_port(addr1, 0, 0, a->remote_ipv6_addr, a->remote_port); if (sz < 0) return sz; addr1 = alloca(sz+1); sz = format_ipv6_port(addr1, sz, 0, a->remote_ipv6_addr, a->remote_port); if (sz < 0) return sz; off += format(buf, size, off, "IPv6(%s<->%s,%hx,%hhx)", addr0, addr1, a->protocol, a->ip_addr_origin); break; } case EFIDP_MSG_UART: { int parity = dp->uart.parity; char parity_label[] = "DNEOMS"; int stop_bits = dp->uart.stop_bits; char *sb_label[] = {"D", "1", "1.5", "2"}; off += format(buf, size, off, "Uart(%"PRIu64",%d,", dp->uart.baud_rate ? dp->uart.baud_rate : 115200, dp->uart.data_bits ? dp->uart.data_bits : 8); off += format(buf, size, off, parity > 5 ? "%d," : "%c,", parity > 5 ? parity : parity_label[parity]); if (stop_bits > 3) off += format(buf, size, off, "%d)", stop_bits); else off += format(buf, size, off, "%s)", sb_label[stop_bits]); break; } case EFIDP_MSG_USB_CLASS: off += format_helper(format_usb_class, buf, size, off, dp); break; case EFIDP_MSG_USB_WWID: off += format(buf, size, off, "UsbWwid(%"PRIx16",%"PRIx16",%d,", dp->usb_wwid.vendor_id, dp->usb_wwid.product_id, dp->usb_wwid.interface); off += format_ucs2(buf, size, off, dp->usb_wwid.serial_number, (efidp_node_size(dp) - offsetof(efidp_usb_wwid, serial_number)) / 2 + 1); off += format(buf, size, off, ")"); break; case EFIDP_MSG_LUN: off += format(buf, size, off, "Unit(%d)", dp->lun.lun); break; case EFIDP_MSG_SATA: off += format(buf, size, off, "Sata(%d,%d,%d)", dp->sata.hba_port, dp->sata.port_multiplier_port, dp->sata.lun); break; case EFIDP_MSG_ISCSI: { size_t sz = efidp_node_size(dp) - offsetof(efidp_iscsi, target_name); if (sz > EFIDP_ISCSI_MAX_TARGET_NAME_LEN) sz = EFIDP_ISCSI_MAX_TARGET_NAME_LEN; char target_name[sz + 1]; memcpy(target_name, dp->iscsi.target_name, sz); target_name[sz] = '\0'; uint64_t lun; memcpy(&lun, dp->iscsi.lun, sizeof (lun)); off += format(buf, size, off, "iSCSI(%s,%d,0x%"PRIx64",%s,%s,%s,%s)", target_name, dp->iscsi.tpgt, be64_to_cpu(lun), (dp->iscsi.options >> EFIDP_ISCSI_HEADER_DIGEST_SHIFT) & EFIDP_ISCSI_HEADER_CRC32 ? "CRC32" : "None", (dp->iscsi.options >> EFIDP_ISCSI_DATA_DIGEST_SHIFT) & EFIDP_ISCSI_DATA_CRC32 ? "CRC32" : "None", (dp->iscsi.options >> EFIDP_ISCSI_AUTH_SHIFT) & EFIDP_ISCSI_AUTH_NONE ? "None" : \ (dp->iscsi.options >> EFIDP_ISCSI_CHAP_SHIFT) & EFIDP_ISCSI_CHAP_UNI ? "CHAP_UNI" : "CHAP_BI", dp->iscsi.protocol == 0 ? "TCP" : "Unknown"); break; } case EFIDP_MSG_VLAN: off += format(buf, size, off, "Vlan(%d)", dp->vlan.vlan_id); break; case EFIDP_MSG_SAS_EX: off += format_sas(buf, size, dp); break; case EFIDP_MSG_NVME: off += format(buf, size, off, "NVMe(0x%"PRIx32"," "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X)", dp->nvme.namespace_id, dp->nvme.ieee_eui_64[0], dp->nvme.ieee_eui_64[1], dp->nvme.ieee_eui_64[2], dp->nvme.ieee_eui_64[3], dp->nvme.ieee_eui_64[4], dp->nvme.ieee_eui_64[5], dp->nvme.ieee_eui_64[6], dp->nvme.ieee_eui_64[7]); break; case EFIDP_MSG_URI: { size_t sz = efidp_node_size(dp) - offsetof(efidp_uri, uri); char uri[sz + 1]; memcpy(uri, dp->uri.uri, sz); uri[sz] = '\0'; off += format(buf, size, off, "Uri(%s)", uri); break; } case EFIDP_MSG_UFS: off += format(buf, size, off, "UFS(%d,0x%02x)", dp->ufs.target_id, dp->ufs.lun); break; case EFIDP_MSG_SD: off += format(buf, size, off, "SD(%d)", dp->sd.slot_number); break; default: off += format(buf, size, off, "Msg(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, efidp_node_size(dp)-4); off += format(buf,size,off,")"); break; } return off; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_mac_addr(uint8_t *buf, ssize_t size, uint8_t if_type, const uint8_t * const mac_addr, ssize_t mac_addr_size) { efidp_mac_addr *mac = (efidp_mac_addr *)buf; ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_MAC_ADDR, sizeof (*mac)); ssize_t req = sizeof (*mac); if (size && sz == req) { mac->if_type = if_type; memcpy(mac->mac_addr, mac_addr, mac_addr_size > 32 ? 32 : mac_addr_size); } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_ipv4(uint8_t *buf, ssize_t size, uint32_t local, uint32_t remote, uint32_t gateway, uint32_t netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, int is_static) { efidp_ipv4_addr *ipv4 = (efidp_ipv4_addr *)buf; ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_IPv4, sizeof (*ipv4)); ssize_t req = sizeof (*ipv4); if (size && sz == req) { *((char *)ipv4->local_ipv4_addr) = htonl(local); *((char *)ipv4->remote_ipv4_addr) = htonl(remote); ipv4->local_port = htons(local_port); ipv4->remote_port = htons(remote_port); ipv4->protocol = htons(protocol); ipv4->static_ip_addr = 0; if (is_static) ipv4->static_ip_addr = 1; *((char *)ipv4->gateway) = htonl(gateway); *((char *)ipv4->netmask) = htonl(netmask); } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_scsi(uint8_t *buf, ssize_t size, uint16_t target, uint16_t lun) { efidp_scsi *scsi = (efidp_scsi *)buf; ssize_t req = sizeof (*scsi); ssize_t sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_SCSI, sizeof (*scsi)); if (size && sz == req) { scsi->target = target; scsi->lun = lun; } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_nvme(uint8_t *buf, ssize_t size, uint32_t namespace_id, uint8_t *ieee_eui_64) { efidp_nvme *nvme = (efidp_nvme *)buf; ssize_t req = sizeof (*nvme); ssize_t sz; sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_NVME, sizeof (*nvme)); if (size && sz == req) { nvme->namespace_id = namespace_id; if (ieee_eui_64) memcpy(nvme->ieee_eui_64, ieee_eui_64, sizeof (nvme->ieee_eui_64)); else memset(nvme->ieee_eui_64, '\0', sizeof (nvme->ieee_eui_64)); } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_sata(uint8_t *buf, ssize_t size, uint16_t hba_port, uint16_t port_multiplier_port, uint16_t lun) { efidp_sata *sata = (efidp_sata *)buf; ssize_t req = sizeof (*sata); ssize_t sz; sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_SATA, sizeof (*sata)); if (size && sz == req) { sata->hba_port = hba_port; sata->port_multiplier_port = port_multiplier_port; sata->lun = lun; } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_atapi(uint8_t *buf, ssize_t size, uint16_t primary, uint16_t slave, uint16_t lun) { efidp_atapi *atapi = (efidp_atapi *)buf; ssize_t req = sizeof (*atapi); ssize_t sz; sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_ATAPI, sizeof (*atapi)); if (size && sz == req) { atapi->primary = primary; atapi->slave = slave; atapi->lun = lun; } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address) { efidp_sas *sas = (efidp_sas *)buf; ssize_t req = sizeof (*sas); ssize_t sz; sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, EFIDP_MSG_VENDOR, sizeof (*sas)); if (size && sz == req) { sas->vendor_guid = EFIDP_MSG_SAS_GUID; sas->reserved = 0; sas->sas_address = sas_address; sas->lun = 0; sas->device_topology_info = 0; sas->drive_bay_id = 0; sas->rtp = 0; } return sz; } efivar-0.21/src/dp.c000066400000000000000000000205321255101430600142450ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include "dp.h" static const efidp_header end_entire = { .type = EFIDP_END_TYPE, .subtype = EFIDP_END_ENTIRE, .length = 4 }; static const efidp_header end_instance = { .type = EFIDP_END_TYPE, .subtype = EFIDP_END_INSTANCE, .length = 4 }; static inline void * efidp_data_address(const_efidp dp) { if (dp->length <= 4) { errno = ENOSPC; return NULL; } return (void *)((uint8_t *)dp + sizeof (dp)); } int __attribute__((__visibility__ ("default"))) efidp_set_node_data(const_efidp dn, void *buf, size_t bufsize) { if (dn->length < 4 || bufsize > (size_t)dn->length - 4) { errno = ENOSPC; return -1; } void *data = efidp_data_address(dn); if (!data) return -1; memcpy(data, buf, bufsize); return 0; } static inline int efidp_duplicate_extra(const_efidp dp, efidp *out, size_t extra) { ssize_t sz; size_t plus; efidp new; sz = efidp_size(dp); if (sz < 0) return sz; plus = (size_t)sz + extra; if (plus < (size_t)sz || plus < extra) { errno = ENOSPC; return -1; } new = calloc(1, plus); if (!new) return -1; memcpy(new, dp, sz); *out = new; return 0; } int __attribute__((__visibility__ ("default"))) efidp_duplicate_path(const_efidp dp, efidp *out) { return efidp_duplicate_extra(dp, out, 0); } int __attribute__((__visibility__ ("default"))) efidp_append_path(const_efidp dp0, const_efidp dp1, efidp *out) { ssize_t lsz, rsz; const_efidp le; int rc; if (!dp0 && !dp1) return efidp_duplicate_path((const_efidp)&end_entire, out); if (dp0 && !dp1) return efidp_duplicate_path(dp0, out); if (!dp0 && dp1) return efidp_duplicate_path(dp1, out); lsz = efidp_size(dp0); if (lsz < 0) return -1; rsz = efidp_size(dp1); if (rsz < 0) return -1; le = dp0; while (1) { if (efidp_type(le) == EFIDP_END_TYPE && efidp_subtype(le) == EFIDP_END_ENTIRE) { ssize_t lesz = efidp_size(le); if (lesz < 0) return -1; lsz -= lesz; break; } rc = efidp_get_next_end(le, &le); if (rc < 0) return -1; } efidp new; new = malloc(lsz + rsz); if (!new) return -1; *out = new; memcpy(new, dp0, lsz); memcpy((uint8_t *)new + lsz, dp1, rsz); return 0; } int __attribute__((__visibility__ ("default"))) efidp_append_node(const_efidp dp, const_efidp dn, efidp *out) { ssize_t lsz, rsz; int rc; if (!dp && !dn) return efidp_duplicate_path((const_efidp)(const efidp_header * const)&end_entire, out); if (dp && !dn) return efidp_duplicate_path(dp, out); if (!dp && dn) { efidp new = malloc(efidp_node_size(dn) + sizeof (end_entire)); if (!new) return -1; memcpy(new, dn, dn->length); memcpy((uint8_t *)new + dn->length, &end_entire, sizeof (end_entire)); *out = new; return 0; } lsz = efidp_size(dp); if (lsz < 0) return -1; rsz = efidp_node_size(dn); if (rsz < 0) return -1; const_efidp le; le = dp; while (1) { if (efidp_type(le) == EFIDP_END_TYPE && efidp_subtype(le) == EFIDP_END_ENTIRE) { ssize_t lesz = efidp_size(le); if (lesz < 0) return -1; lsz -= lesz; break; } rc = efidp_get_next_end(le, &le); if (rc < 0) return -1; } efidp new = malloc(lsz + rsz + sizeof (end_entire)); if (!new) return -1; *out = new; memcpy(new, dp, lsz); memcpy((uint8_t *)new + lsz, dn, rsz); memcpy((uint8_t *)new + lsz + rsz, &end_entire, sizeof (end_entire)); return 0; } int __attribute__((__visibility__ ("default"))) efidp_append_instance(const_efidp dp, const_efidp dpi, efidp *out) { ssize_t lsz, rsz; int rc; if (!dp && !dpi) { errno = EINVAL; return -1; } if (!dp && dpi) return efidp_duplicate_path(dpi, out); lsz = efidp_size(dp); if (lsz < 0) return -1; rsz = efidp_node_size(dpi); if (rsz < 0) return -1; efidp le; le = (efidp)dp; while (1) { if (le->type == EFIDP_END_TYPE && le->subtype == EFIDP_END_ENTIRE) break; rc = efidp_get_next_end(le, (const_efidp *)&le); if (rc < 0) return -1; } le->subtype = EFIDP_END_INSTANCE; efidp new = malloc(lsz + rsz + sizeof (end_entire)); if (!new) return -1; *out = new; memcpy(new, dp, lsz); memcpy((uint8_t *)new + lsz, dpi, rsz); return 0; } ssize_t __attribute__((__visibility__ ("default"))) efidp_format_device_path(char *buf, size_t size, const_efidp dp, ssize_t limit) { ssize_t sz; ssize_t off = 0; int first = 1; while (1) { if (limit && (limit < 4 || efidp_node_size(dp) > limit)) return off+1; if (first) { first = 0; } else { if (dp->type == EFIDP_END_TYPE) { if (dp->type == EFIDP_END_INSTANCE) off += format(buf, size, off, ","); else return off+1; } else { off += format(buf, size, off, "/"); } } switch (dp->type) { case EFIDP_HARDWARE_TYPE: sz = format_hw_dn(buf, size, off, dp); if (sz < 0) return -1; off += sz; break; case EFIDP_ACPI_TYPE: sz = format_acpi_dn(buf, size, off, dp); if (sz < 0) return -1; off += sz; break; case EFIDP_MESSAGE_TYPE: sz = format_message_dn(buf, size, off, dp); if (sz < 0) return -1; off += sz; break; case EFIDP_MEDIA_TYPE: sz = format_media_dn(buf, size, off, dp); if (sz < 0) return -1; off += sz; break; case EFIDP_BIOS_BOOT_TYPE: { char *types[] = {"", "Floppy", "HD", "CDROM", "PCMCIA", "USB", "Network", "" }; if (dp->subtype != EFIDP_BIOS_BOOT) { off += format(buf, size, off, "BbsPath(%d,", dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp+4, efidp_node_size(dp)-4); off += format(buf,size,off,")"); break; } if (dp->bios_boot.device_type > 0 && dp->bios_boot.device_type < 7) { off += format(buf, size, off, "BBS(%s,%s,0x%"PRIx32")", types[dp->bios_boot.device_type], dp->bios_boot.description, dp->bios_boot.status); } else { off += format(buf, size, off, "BBS(%d,%s,0x%"PRIx32")", dp->bios_boot.device_type, dp->bios_boot.description, dp->bios_boot.status); } break; } case EFIDP_END_TYPE: if (dp->subtype == EFIDP_END_INSTANCE) { off += format(buf, size, off, ","); break; } return off; default: off += format(buf, size, off, "Path(%d,%d,", dp->type, dp->subtype); off += format_hex(buf, size, off, (uint8_t *)dp + 4, efidp_node_size(dp) - 4); off += format(buf, size, off, ")"); break; } if (limit) limit -= efidp_node_size(dp); int rc = efidp_next_node(dp, &dp); if (rc < 0) return rc; } return off+1; } ssize_t __attribute__((__visibility__ ("default"))) efidp_parse_device_node(char *path, efidp out, size_t size) { errno = -ENOSYS; return -1; } ssize_t __attribute__((__visibility__ ("default"))) efidp_parse_device_path(char *path, efidp out, size_t size) { errno = -ENOSYS; return -1; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_vendor(uint8_t *buf, ssize_t size, uint8_t type, uint8_t subtype, efi_guid_t vendor_guid, void *data, size_t data_size) { efidp_hw_vendor *vend = (efidp_hw_vendor *)buf; ssize_t sz; ssize_t req = sizeof (*vend) + data_size; sz = efidp_make_generic(buf, size, type, subtype, req); if (size && sz == req) { vend->vendor_guid = vendor_guid; memcpy(vend->vendor_data, data, data_size); } return sz; } ssize_t __attribute__((__visibility__ ("default"))) efidp_make_generic(uint8_t *buf, ssize_t size, uint8_t type, uint8_t subtype, ssize_t total_size) { efidp_header *head = (efidp_header *)buf; if (!size) return total_size; if (size < total_size) { errno = ENOSPC; return -1; } head->type = type; head->subtype = subtype; head->length = total_size; return head->length; } efivar-0.21/src/dp.h000066400000000000000000000111021255101430600142430ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #ifndef _EFIVAR_INTERNAL_DP_H #define _EFIVAR_INTERNAL_DP_H #include #include #include #include #include "ucs2.h" #define format(buf, size, off, fmt, args...) ({ \ ssize_t _x; \ _x = snprintf(((buf)+(off)), \ ((size)?((size)-(off)):0), \ fmt, ## args); \ if (_x < 0) \ return _x; \ _x; \ }) #define format_helper(fn, buf, size, off, args...) ({ \ ssize_t _x; \ _x = (fn)(((buf)+(off)), \ ((size)?((size)-(off)):0), \ ## args); \ if (_x < 0) \ return _x; \ _x; \ }) #define onstack(buf, len) ({ \ char *__newbuf = alloca(len); \ memcpy(__newbuf, buf, len); \ free(buf); \ (void *)__newbuf; \ }) #define format_guid(buf, size, off, guid) ({ \ int _rc; \ char *_guidstr = NULL; \ \ _rc = efi_guid_to_str(guid, &_guidstr); \ if (_rc < 0) \ return _rc; \ _guidstr = onstack(_guidstr, strlen(_guidstr)+1); \ format(buf, size, off, "%s", _guidstr); \ }) static inline ssize_t __attribute__((__unused__)) format_hex_helper(char *buf, size_t size, const void * const addr, const size_t len) { ssize_t off = 0; ssize_t sz; for (size_t i = 0; i < len; i++) { sz = format(buf, size, off, "%02x", *((const unsigned char * const )addr+i)); if (sz < 0) return -1; off += sz; } return off; } #define format_hex(buf, size, off, addr, len) \ format_helper(format_hex_helper, buf, size, off, addr, len) static inline ssize_t __attribute__((__unused__)) format_vendor_helper(char *buf, size_t size, char *label, const_efidp dp) { ssize_t off = 0; size_t bytes = efidp_node_size(dp) - sizeof (efidp_header) - sizeof (efi_guid_t); off = format(buf, size, off, "%s(", label); off += format_guid(buf, size, off, &dp->hw_vendor.vendor_guid); if (bytes) { off += format(buf, size, off, ","); off += format_hex(buf, size, off, dp->hw_vendor.vendor_data, bytes); } off += format(buf, size, off, ")"); return off; } #define format_vendor(buf, size, off, label, dp) \ format_helper(format_vendor_helper, buf, size, off, label, dp) #define format_ucs2(buf, size, off, str, len) ({ \ uint16_t _ucs2buf[(len)]; \ memset(_ucs2buf, '\0', sizeof (_ucs2buf)); \ memcpy(_ucs2buf, str, sizeof (_ucs2buf) \ - sizeof (_ucs2buf[0])); \ unsigned char *_asciibuf; \ _asciibuf = ucs2_to_utf8(_ucs2buf, (len) - 1); \ if (_asciibuf == NULL) \ return -1; \ _asciibuf = onstack(_asciibuf, (len)); \ format(buf, size, off, "%s", _asciibuf); \ }) #define format_array(buf, size, off, fmt, type, addr, len) ({ \ ssize_t _off = 0; \ for (size_t _i = 0; _i < len; _i++) { \ if (_i != 0) \ _off += format(buf, size, off+_off, ",");\ _off += format(buf, size, off+_off, fmt, \ ((type *)addr)[_i]); \ } \ _off+off; \ }) extern ssize_t _format_hw_dn(char *buf, size_t size, const_efidp dp); extern ssize_t _format_acpi_dn(char *buf, size_t size, const_efidp dp); extern ssize_t _format_message_dn(char *buf, size_t size, const_efidp dp); extern ssize_t _format_media_dn(char *buf, size_t size, const_efidp dp); extern ssize_t _format_bios_boot_dn(char *buf, size_t size, const_efidp dp); #define format_hw_dn(buf, size, off, dp) \ _format_hw_dn(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) #define format_acpi_dn(buf, size, off, dp) \ _format_acpi_dn(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) #define format_message_dn(buf, size, off, dp) \ _format_message_dn(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) #define format_media_dn(buf, size, off, dp) \ _format_media_dn(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) #define format_bios_boot_dn(buf, size, off, dp) \ _format_bios_boot_dn(((buf)+(off)), ((size)?((size)-(off)):0), (dp)) #endif /* _EFIVAR_INTERNAL_DP_H */ efivar-0.21/src/efiboot.pc.in000066400000000000000000000003471255101430600160600ustar00rootroot00000000000000prefix=/usr exec_prefix=/usr libdir=@@LIBDIR@@ includedir=/usr/include Name: efiboot Description: UEFI Boot variable support Version: @@VERSION@@ Requires.private: efivar Libs: -L${libdir} -lefiboot Cflags: -I${includedir}/efivar efivar-0.21/src/efivar.c000066400000000000000000000203571255101430600151230ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include "efivar.h" #include "guid.h" #define ACTION_LIST 0x1 #define ACTION_PRINT 0x2 #define ACTION_APPEND 0x4 #define ACTION_LIST_GUIDS 0x8 static const char *attribute_names[] = { "Non-Volatile", "Boot Service Access", "Runtime Service Access", "Hardware Error Record", "Authenticated Write Access", "Time-Based Authenticated Write Access", "Append Write", "" }; static void list_all_variables(void) { efi_guid_t *guid = NULL; char *name = NULL; int rc; while ((rc = efi_get_next_variable_name(&guid, &name)) > 0) printf(GUID_FORMAT "-%s\n", guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5], name); if (rc < 0) { fprintf(stderr, "efivar: error listing variables: %m\n"); exit(1); } } static void parse_name(const char *guid_name, char **name, efi_guid_t *guid) { unsigned int guid_len = sizeof("84be9c3e-8a32-42c0-891c-4cd3b072becc"); char guid_buf[guid_len + 2]; int rc; off_t name_pos = 0; const char *left, *right; left = strchr(guid_name, '{'); right = strchr(guid_name, '}'); if (left && right) { if (right[1] != '-' || right[2] == '\0') { bad_name: errno = -EINVAL; fprintf(stderr, "efivar: invalid name \"%s\"\n", guid_name); exit(1); } name_pos = right + 1 - guid_name; strncpy(guid_buf, guid_name, name_pos); guid_buf[name_pos++] = '\0'; rc = efi_id_guid_to_guid(guid_buf, guid); if (rc < 0) goto bad_name; } else { /* it has to be at least the length of the guid, a dash, and * one more character */ if (strlen(guid_name) < guid_len + 2) goto bad_name; name_pos = guid_len - 1; if (guid_name[name_pos] != '-' || guid_name[name_pos+1] == '\0') goto bad_name; name_pos++; memset(guid_buf, 0, sizeof(guid_buf)); strncpy(guid_buf, guid_name, guid_len - 1); rc = text_to_guid(guid_buf, guid); if (rc < 0) goto bad_name; } char *name_buf = NULL; int name_len; name_len = strlen(guid_name + name_pos) + 1; name_buf = calloc(1, name_len); if (!name_buf) { fprintf(stderr, "efivar: %m\n"); exit(1); } strncpy(name_buf, guid_name + name_pos, name_len); *name = name_buf; } static void show_variable(char *guid_name) { efi_guid_t guid; char *name = NULL; int rc; uint8_t *data = NULL; size_t data_size = 0; uint32_t attributes; parse_name(guid_name, &name, &guid); errno = 0; rc = efi_get_variable(guid, name, &data, &data_size, &attributes); if (rc < 0) { fprintf(stderr, "efivar: show variable: %m\n"); exit(1); } printf("GUID: "GUID_FORMAT "\n", guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); printf("Name: \"%s\"\n", name); printf("Attributes:\n"); for (int i = 0; attribute_names[i][0] != '\0'; i++) { if(attributes & (1 << i)) printf("\t%s\n", attribute_names[i]); } printf("Value:\n"); uint32_t index = 0; while (index < data_size) { char charbuf[] = "................"; printf("%08x ", index); /* print the hex values, and render the ascii bits into * charbuf */ while (index < data_size) { printf("%02x ", data[index]); if (index % 8 == 7) printf(" "); if (isprint(data[index])) charbuf[index % 16] = data[index]; index++; if (index % 16 == 0) break; } /* If we're above data_size, finish out the line with space, * and also finish out charbuf with space */ while (index >= data_size && index % 16 != 0) { if (index % 8 == 7) printf(" "); printf(" "); charbuf[index % 16] = ' '; index++; if (index % 16 == 0) break; } printf("|%s|\n", charbuf); } } static void append_variable(const char *guid_name, void *data, size_t data_size, int attrib) { efi_guid_t guid; char *name = NULL; int rc; uint8_t *old_data = NULL; size_t old_data_size = 0; uint32_t old_attributes = 0; parse_name(guid_name, &name, &guid); rc = efi_get_variable(guid, name, &old_data, &old_data_size, &old_attributes); if (attrib != 0) old_attributes = attrib; rc = efi_append_variable(guid, name, data, data_size, old_attributes); if (rc < 0) { fprintf(stderr, "efivar: %m\n"); exit(1); } } static void validate_name(const char *name) { if (name == NULL) { fprintf(stderr, "Invalid variable name\n"); exit(1); } } static void prepare_data(const char *filename, void **data, size_t *data_size) { int fd = -1; void *buf; size_t buflen = 0; struct stat statbuf; int rc; fd = open(filename, O_RDONLY); if (fd < 0) goto err; memset(&statbuf, '\0', sizeof (statbuf)); rc = fstat(fd, &statbuf); if (rc < 0) goto err; buflen = statbuf.st_size; buf = mmap(NULL, buflen, PROT_READ, MAP_PRIVATE|MAP_POPULATE, fd, 0); if (!buf) goto err; *data = buf; *data_size = buflen; close(fd); return; err: if (fd >= 0) close(fd); fprintf(stderr, "Could not use \"%s\": %m\n", filename); exit(1); } int main(int argc, char *argv[]) { int action = 0; char *name = NULL; char *file = NULL; int attributes = 0; poptContext optCon; struct poptOption options[] = { {NULL, '\0', POPT_ARG_INTL_DOMAIN, "efivar" }, {"list", 'l', POPT_ARG_VAL, &action, ACTION_LIST, "list current variables", NULL }, {"print", 'p', POPT_ARG_VAL, &action, ACTION_PRINT, "print variable specified by --name", NULL }, {"name", 'n', POPT_ARG_STRING, &name, 0, "variable to manipulate, in the form 8be4df61-93ca-11d2-aa0d-00e098032b8c-Boot0000", "" }, {"append", 'a', POPT_ARG_VAL, &action, ACTION_APPEND, "append to variable specified by --name", NULL }, {"fromfile", 'f', POPT_ARG_STRING, &file, 0, "use data from ", "" }, {"attributes", 't', POPT_ARG_INT, &attributes, 0, "attributes to use on append", "" }, {"list-guids", 'L', POPT_ARG_VAL, &action, ACTION_LIST_GUIDS, "show internal guid list", NULL }, POPT_AUTOALIAS POPT_AUTOHELP POPT_TABLEEND }; int rc; void *data = NULL; size_t data_size = 0; optCon = poptGetContext("efivar", argc, (const char **)argv, options,0); rc = poptReadDefaultConfig(optCon, 0); if (rc < 0 && !(rc == POPT_ERROR_ERRNO && errno == ENOENT)) { fprintf(stderr, "efivar: poptReadDefaultConfig failed: %s\n", poptStrerror(rc)); exit(1); } while ((rc = poptGetNextOpt(optCon)) > 0) ; if (rc < -1) { fprintf(stderr, "efivar: Invalid argument: %s: %s\n", poptBadOption(optCon, 0), poptStrerror(rc)); exit(1); } if (poptPeekArg(optCon)) { fprintf(stderr, "efivar: Invalid Argument: \"%s\"\n", poptPeekArg(optCon)); exit(1); } poptFreeContext(optCon); if (name) action |= ACTION_PRINT; switch (action) { case ACTION_LIST: list_all_variables(); break; case ACTION_PRINT: validate_name(name); show_variable(name); break; case ACTION_APPEND | ACTION_PRINT: validate_name(name); prepare_data(file, &data, &data_size); append_variable(name, data, data_size, attributes); case ACTION_LIST_GUIDS: { extern struct guidname efi_well_known_guids; extern struct guidname efi_well_known_guids_end; for (struct guidname *guid = &efi_well_known_guids; guid != &efi_well_known_guids_end; guid++) { printf("{"GUID_FORMAT"} {%s} %s %s\n", guid->guid.a, guid->guid.b, guid->guid.c, bswap_16(guid->guid.d), guid->guid.e[0], guid->guid.e[1], guid->guid.e[2], guid->guid.e[3], guid->guid.e[4], guid->guid.e[5], guid->symbol + strlen("efi_guid_"), guid->symbol, guid->name); } } }; return 0; } efivar-0.21/src/efivar.pc.in000066400000000000000000000003351255101430600157020ustar00rootroot00000000000000prefix=/usr exec_prefix=/usr libdir=@@LIBDIR@@ includedir=/usr/include Name: efivar Description: UEFI Variable Management Version: @@VERSION@@ Libs: -L${libdir} -lefivar Libs.private: -ldl Cflags: -I${includedir}/efivar efivar-0.21/src/efivarfs.c000066400000000000000000000132231255101430600154460ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "lib.h" #include "generics.h" #include "util.h" #define EFIVARS_PATH "/sys/firmware/efi/efivars/" #ifndef EFIVARFS_MAGIC # define EFIVARFS_MAGIC 0xde5e81e4 #endif static int efivarfs_probe(void) { if (!access(EFIVARS_PATH, F_OK)) { int rc = 0; struct statfs buf; memset(&buf, '\0', sizeof (buf)); rc = statfs(EFIVARS_PATH, &buf); if (rc == 0) { typeof(buf.f_type) magic = EFIVARFS_MAGIC; if (!memcmp(&buf.f_type, &magic, sizeof (magic))) return 1; } } return 0; } #define make_efivarfs_path(str, guid, name) ({ \ asprintf(str, EFIVARS_PATH "%s-" GUID_FORMAT, \ name, (guid).a, (guid).b, (guid).c, \ bswap_16((guid).d), \ (guid).e[0], (guid).e[1], (guid).e[2], \ (guid).e[3], (guid).e[4], (guid).e[5]); \ }) static int efivarfs_get_variable_size(efi_guid_t guid, const char *name, size_t *size) { char *path = NULL; int rc = 0; int ret = -1; typeof(errno) errno_value; rc = make_efivarfs_path(&path, guid, name); if (rc < 0) goto err; struct stat statbuf = { 0, }; rc = stat(path, &statbuf); if (rc < 0) goto err; ret = 0; /* Compensate for the size of the Attributes field. */ *size = statbuf.st_size - sizeof (uint32_t); err: errno_value = errno; if (path) free(path); errno = errno_value; return ret; } static int efivarfs_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t *attributes) { int ret = -1; uint8_t *data; size_t data_size; uint32_t attribs; ret = efi_get_variable(guid, name, &data, &data_size, &attribs); if (ret < 0) return ret; *attributes = attribs; if (data) free(data); return ret; } static int efivarfs_get_variable(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes) { typeof(errno) errno_value; int ret = -1; size_t size = 0; uint32_t ret_attributes = 0; uint8_t *ret_data; char *path; int rc = make_efivarfs_path(&path, guid, name); if (rc < 0) return -1; int fd = open(path, O_RDONLY); if (fd < 0) goto err; rc = read(fd, &ret_attributes, sizeof (ret_attributes)); if (rc < 0) goto err; rc = read_file(fd, &ret_data, &size); if (rc < 0) goto err; *attributes = ret_attributes; *data = ret_data; *data_size = size - 1; // read_file pads out 1 extra byte to NUL it */ ret = 0; err: errno_value = errno; if (fd >= 0) close(fd); if (path) free(path); errno = errno_value; return ret; } static int efivarfs_del_variable(efi_guid_t guid, const char *name) { char *path; int rc = make_efivarfs_path(&path, guid, name); if (rc < 0) return -1; rc = unlink(path); typeof(errno) errno_value = errno; free(path); errno = errno_value; return rc; } static int efivarfs_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) { uint8_t buf[sizeof (attributes) + data_size]; typeof(errno) errno_value; int ret = -1; if (strlen(name) > 1024) { errno = EINVAL; return -1; } char *path; int rc = make_efivarfs_path(&path, guid, name); if (rc < 0) return -1; int fd = -1; if (!access(path, F_OK) && !(attributes & EFI_VARIABLE_APPEND_WRITE)) { rc = efi_del_variable(guid, name); if (rc < 0) goto err; } fd = open(path, O_WRONLY|O_CREAT, mode); if (fd < 0) goto err; memcpy(buf, &attributes, sizeof (attributes)); memcpy(buf + sizeof (attributes), data, data_size); rc = write(fd, buf, sizeof (attributes) + data_size); if (rc >= 0) { ret = 0; } else { unlink(path); } err: errno_value = errno; if (path) free(path); if (fd >= 0) close(fd); errno = errno_value; return ret; } static int efivarfs_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { attributes |= EFI_VARIABLE_APPEND_WRITE; return efivarfs_set_variable(guid, name, data, data_size, attributes, 0); } static int efivarfs_get_next_variable_name(efi_guid_t **guid, char **name) { return generic_get_next_variable_name(EFIVARS_PATH, guid, name); } static int efivarfs_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { char *path; int rc = make_efivarfs_path(&path, guid, name); if (rc < 0) return -1; rc = chmod(path, mode); int saved_errno = errno; free(path); errno = saved_errno; return -1; } struct efi_var_operations efivarfs_ops = { .name = "efivarfs", .probe = efivarfs_probe, .set_variable = efivarfs_set_variable, .append_variable = efivarfs_append_variable, .del_variable = efivarfs_del_variable, .get_variable = efivarfs_get_variable, .get_variable_attributes = efivarfs_get_variable_attributes, .get_variable_size = efivarfs_get_variable_size, .get_next_variable_name = efivarfs_get_next_variable_name, .chmod_variable = efivarfs_chmod_variable, }; efivar-0.21/src/endian.h000066400000000000000000000031131255101430600151010ustar00rootroot00000000000000/* * Copyright 2009-2015 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Peter Jones */ #ifndef _EFIVAR_ENDIAN_H #define _EFIVAR_ENDIAN_H #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_le16(x) (x) #define cpu_to_le32(x) (x) #define cpu_to_le64(x) (x) #define le16_to_cpu(x) (x) #define le32_to_cpu(x) (x) #define le64_to_cpu(x) (x) #define cpu_to_be16(x) __bswap_16(x) #define cpu_to_be32(x) __bswap_32(x) #define cpu_to_be64(x) __bswap_64(x) #define be16_to_cpu(x) __bswap_16(x) #define be32_to_cpu(x) __bswap_32(x) #define be64_to_cpu(x) __bswap_64(x) #else #define cpu_to_be16(x) (x) #define cpu_to_be32(x) (x) #define cpu_to_be64(x) (x) #define be16_to_cpu(x) (x) #define be32_to_cpu(x) (x) #define be64_to_cpu(x) (x) #define cpu_to_le16(x) __bswap_16(x) #define cpu_to_le32(x) __bswap_32(x) #define cpu_to_le64(x) __bswap_64(x) #define le16_to_cpu(x) __bswap_16(x) #define le32_to_cpu(x) __bswap_32(x) #define le64_to_cpu(x) __bswap_64(x) #endif #endif /* _EFIVAR_ENDIAN_H */ efivar-0.21/src/export.c000066400000000000000000000211511255101430600151610ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include "lib.h" #define EFIVAR_MAGIC 0xf3df1597 #define ATTRS_UNSET 0xa5a5a5a5a5a5a5a5 #define ATTRS_MASK 0xffffffff struct efi_variable { uint64_t attrs; efi_guid_t *guid; char *name; uint8_t *data; size_t data_size; }; /* The exported structure is: * struct { * uint32_t magic; * uint32_t version; * uint64_t attr; * efi_guid_t guid; * uint32_t name_len; * uint32_t data_len; * char16_t name[]; * uint8_t data[]; * uint32_t magic; * } */ ssize_t __attribute__((__nonnull__ (1, 3))) __attribute__((__visibility__ ("default"))) efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var_out) { efi_variable_t var; size_t min = sizeof (uint32_t) * 2 /* magic */ + sizeof (uint32_t) /* version */ + sizeof (uint64_t) /* attr */ + sizeof (efi_guid_t) /* guid */ + sizeof (uint32_t) * 2 /* name_len and data_len */ + sizeof (char16_t) /* two bytes of name */ + 1; /* one byte of data */ errno = EINVAL; if (size <= min) return -1; if (!var_out) return -1; uint8_t *ptr = data; uint32_t magic = EFIVAR_MAGIC; if (memcmp(data, &magic, sizeof (uint32_t)) || memcmp(data + size - sizeof (uint32_t), &magic, sizeof (uint32_t))) return -1; size -= sizeof (uint32_t); ptr += sizeof (uint32_t); if (*(uint32_t *)ptr == 1) { ptr += sizeof (uint32_t); var.attrs = *(uint64_t *)ptr; ptr += sizeof (uint32_t); var.guid = malloc(sizeof (efi_guid_t)); if (!var.guid) return -1; *var.guid = *(efi_guid_t *)ptr; ptr += sizeof (efi_guid_t); uint32_t name_len = *(uint32_t *)ptr; ptr += sizeof (uint32_t); uint32_t data_len = *(uint32_t *)ptr; ptr += sizeof (uint32_t); if (name_len < 1 || name_len != ((data + size) - ptr - data_len)) return -1; if (data_len < 1 || data_len != ((data + size) - ptr - name_len)) return -1; var.name = calloc(1, name_len + 1); if (!var.name) { int saved_errno = errno; free(var.guid); errno = saved_errno; return -1; } char16_t *wname = (char16_t *)ptr; for (uint32_t i = 0; i < name_len; i++) var.name[i] = wname[i] & 0xff; ptr += name_len * 2; var.data = malloc(data_len); if (!var.data) { int saved_errno = errno; free(var.guid); free(var.name); errno = saved_errno; return -1; } memcpy(var.data, ptr, data_len); if (!*var_out) { *var_out =malloc(sizeof (var)); if (!*var_out) { int saved_errno = errno; free(var.guid); free(var.name); free(var.data); errno = saved_errno; return -1; } } memcpy(*var_out, &var, sizeof (var)); } else { return -1; } return size; } ssize_t __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_variable_export(efi_variable_t *var, uint8_t *data, size_t size) { if (!var) { errno = EINVAL; return -1; } size_t name_len = strlen(var->name); size_t needed = sizeof (uint32_t) /* magic */ + sizeof (uint32_t) /* version */ + sizeof (uint64_t) /* attr */ + sizeof (efi_guid_t) /* guid */ + sizeof (uint32_t) /* name_len */ + sizeof (uint32_t) /* data_len */ + sizeof (char16_t) * name_len /* name */ + var->data_size /* data */ + sizeof (uint32_t); /* magic again */ if (!data || size == 0) { return needed; } else if (size < needed) { return needed - size; } uint8_t *ptr = data; *(uint32_t *)ptr = EFIVAR_MAGIC; ptr += sizeof (uint32_t); *(uint32_t *)ptr = 1; ptr += sizeof (uint32_t); *(uint64_t *)ptr = var->attrs; ptr += sizeof (uint64_t); memcpy(ptr, var->guid, sizeof (efi_guid_t)); ptr += sizeof (efi_guid_t); *(uint32_t *)ptr = (uint32_t)(sizeof (char16_t) * name_len); ptr += sizeof (uint32_t); *(uint32_t *)ptr = var->data_size; ptr += sizeof (uint32_t); for (uint32_t i = 0; i < name_len; i++) { *(char16_t *)ptr = var->name[i]; ptr += sizeof (char16_t); } memcpy(ptr, var->data, var->data_size); ptr += var->data_size; *(uint32_t *)ptr = EFIVAR_MAGIC; return needed; } efi_variable_t * #if 0 /* we get it from the decl instead of the defn here, because GCC gets * confused and thinks we're saying the /return type/ has visibility * and that makes no sense at all except in C++ where it's a class type. */ __attribute__((__visibility__ ("default"))) #endif efi_variable_alloc(void) { efi_variable_t *var = calloc(1, sizeof (efi_variable_t)); if (!var) return NULL; var->attrs = ATTRS_UNSET; return var; } void __attribute__((__visibility__ ("default"))) efi_variable_free(efi_variable_t *var, int free_data) { if (!var) return; if (free_data) { if (var->guid) free(var->guid); if (var->name) free(var->name); if (var->data && var->data_size) free(var->data); } memset(var, '\0', sizeof (*var)); free(var); } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_variable_set_name(efi_variable_t *var, char *name) { if (!var || !name) { errno = EINVAL; return -1; } var->name = name; return 0; } char * __attribute__((__nonnull__ (1))) #if 0 /* we get it from the decl instead of the defn here, because GCC gets * confused and thinks we're saying the /return type/ has visibility * and that makes no sense at all except in C++ where it's a class type. */ __attribute__((__visibility__ ("default"))) #endif efi_variable_get_name(efi_variable_t *var) { if (!var) { errno = EINVAL; return NULL; } if (!var->name) { errno = ENOENT; } else { errno = 0; } return var->name; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_variable_set_guid(efi_variable_t *var, efi_guid_t *guid) { if (!var || !guid) { errno = EINVAL; return -1; } var->guid = guid; return 0; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_variable_get_guid(efi_variable_t *var, efi_guid_t **guid) { if (!var || !guid) { errno = EINVAL; return -1; } if (!var->guid) { errno = ENOENT; return -1; } *guid = var->guid; return 0; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_variable_set_data(efi_variable_t *var, uint8_t *data, size_t size) { if (!var || !data || !size) { errno = EINVAL; return -1; } var->data = data; var->data_size = size; return 0; } ssize_t __attribute__((__nonnull__ (1, 2, 3))) __attribute__((__visibility__ ("default"))) efi_variable_get_data(efi_variable_t *var, uint8_t **data, size_t *size) { if (!var || !data || !size) { errno = EINVAL; return -1; } if (var->data || !var->data_size) { errno = ENOENT; return -1; } *data = var->data; *size = var->data_size; return 0; } int __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_variable_set_attributes(efi_variable_t *var, uint64_t attrs) { if (!var) { errno = -EINVAL; return -1; } var->attrs = attrs; return 0; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_variable_get_attributes(efi_variable_t *var, uint64_t *attrs) { if (!var || !attrs) { errno = -EINVAL; return -1; } if (var->attrs == ATTRS_UNSET) { errno = ENOENT; return -1; } *attrs = var->attrs; return 0; } int __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_variable_realize(efi_variable_t *var) { if (!var) { errno = -EINVAL; return -1; } if (!var->name || !var->data || !var->data_size || var->attrs == ATTRS_UNSET) { errno = -EINVAL; return -1; } if (var->attrs & EFI_VARIABLE_HAS_AUTH_HEADER && !(var->attrs & EFI_VARIABLE_HAS_SIGNATURE)) { errno = -EPERM; return -1; } uint32_t attrs = var->attrs & ATTRS_MASK; if (attrs & EFI_VARIABLE_APPEND_WRITE) { return efi_append_variable(*var->guid, var->name, var->data, var->data_size, attrs); } return efi_set_variable(*var->guid, var->name, var->data, var->data_size, attrs); } efivar-0.21/src/generics.h000066400000000000000000000070731255101430600154530ustar00rootroot00000000000000#ifndef LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H #define LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H 1 #include #include #include #include #include #include #include #include #include "guid.h" static DIR *dir; static inline int __attribute__((unused)) generic_get_next_variable_name(char *path, efi_guid_t **guid, char **name) { static char ret_name[NAME_MAX+1]; static efi_guid_t ret_guid; if (!guid || !name) { errno = EINVAL; return -1; } /* if only one of guid and name are null, there's no "next" variable, * because the current variable is invalid. */ if ((*guid == NULL && *name != NULL) || (*guid != NULL && *name == NULL)) { errno = EINVAL; return -1; } /* if dir is NULL, we're also starting over */ if (!dir) { dir = opendir(path); if (!dir) return -1; int fd = dirfd(dir); if (fd < 0) { typeof(errno) errno_value = errno; closedir(dir); errno = errno_value; return -1; } int flags = fcntl(fd, F_GETFD); if (flags < 0) { warn("fcntl(fd, F_GETFD) failed"); } else { flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) < 0) warn("fcntl(fd, F_SETFD, " "flags | FD_CLOEXEC) failed"); } *guid = NULL; *name = NULL; } struct dirent *de = NULL; char *guidtext = "8be4df61-93ca-11d2-aa0d-00e098032b8c"; size_t guidlen = strlen(guidtext); while (1) { de = readdir(dir); if (de == NULL) { closedir(dir); dir = NULL; return 0; } /* a proper entry must have space for a guid, a dash, and * the variable name */ size_t namelen = strlen(de->d_name); if (namelen < guidlen + 2) continue; int rc = text_to_guid(de->d_name +namelen -guidlen, &ret_guid); if (rc < 0) { closedir(dir); dir = NULL; errno = EINVAL; return -1; } strncpy(ret_name, de->d_name, sizeof(ret_name)); ret_name[namelen - guidlen - 1] = '\0'; *guid = &ret_guid; *name = ret_name; break; } return 1; } static void __attribute__((destructor)) close_dir(void); static void close_dir(void) { if (dir != NULL) { closedir(dir); dir = NULL; } } /* this is a simple read/delete/write implementation of "update". Good luck. * -- pjones */ static int __attribute__((__unused__)) __attribute__((__flatten__)) generic_append_variable(efi_guid_t guid, const char *name, uint8_t *new_data, size_t new_data_size, uint32_t new_attributes) { int rc; uint8_t *data = NULL; size_t data_size = 0; uint32_t attributes = 0; rc = efi_get_variable(guid, name, &data, &data_size, &attributes); if (rc >= 0) { if ((attributes | EFI_VARIABLE_APPEND_WRITE) != (new_attributes | EFI_VARIABLE_APPEND_WRITE)) { free(data); errno = EINVAL; return -1; } uint8_t *d = malloc(data_size + new_data_size); size_t ds = data_size + new_data_size; memcpy(d, data, data_size); memcpy(d + data_size, new_data, new_data_size); attributes &= ~EFI_VARIABLE_APPEND_WRITE; rc = efi_del_variable(guid, name); if (rc < 0) { free(data); free(d); return rc; } /* if this doesn't work, we accidentally deleted. There's * really not much to do about it, so return the error and * let our caller attempt to clean up :/ */ rc = _efi_set_variable(guid, name, d, ds, attributes, 0); free(d); free(data); return rc; } else if (errno == ENOENT) { data = new_data; data_size = new_data_size; attributes = new_attributes & ~EFI_VARIABLE_APPEND_WRITE; rc = _efi_set_variable(guid, name, data, data_size, attributes, 0); return rc; } return rc; } #endif /* LIBEFIVAR_GENERIC_NEXT_VARIABLE_NAME_H */ efivar-0.21/src/gpt.c000066400000000000000000000444601255101430600144420ustar00rootroot00000000000000/* gpt.[ch] Copyright (C) 2000-2001 Dell Computer Corporation EFI GUID Partition Table handling Per Intel EFI Specification v1.02 http://developer.intel.com/technology/efi/efi.htm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "crc32.h" #include "disk.h" #include "gpt.h" #include "util.h" #ifndef BLKGETLASTSECT #define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ #endif struct blkdev_ioctl_param { unsigned int block; size_t content_length; char * block_contents; }; static int report_errors; /** * efi_crc32() - EFI version of crc32 function * @buf: buffer to calculate crc32 of * @len - length of buf * * Description: Returns EFI-style CRC32 value for @buf * * This function uses the little endian Ethernet polynomial * but seeds the function with ~0, and xor's with ~0 at the end. * Note, the EFI Specification, v1.02, has a reference to * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). */ static inline uint32_t efi_crc32(const void *buf, unsigned long len) { return (crc32(buf, len, ~0L) ^ ~0L); } /** * is_pmbr_valid(): test Protective MBR for validity * @mbr: pointer to a legacy mbr structure * * Description: Returns 1 if PMBR is valid, 0 otherwise. * Validity depends on two things: * 1) MSDOS signature is in the last two bytes of the MBR * 2) One partition of type 0xEE is found */ static int is_pmbr_valid(legacy_mbr *mbr) { int i, found = 0, signature = 0; if (!mbr) return 0; signature = (__le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE); for (i = 0; signature && i < 4; i++) { if (mbr->partition[i].os_type == EFI_PMBR_OSTYPE_EFI_GPT) { found = 1; break; } } return (signature && found); } /** * kernel_has_blkgetsize64() * * Returns: 0 on false, 1 on true * True means kernel is 2.4.x, x>=18, or * is 2.5.x, x>4, or * is > 2.5 */ static int kernel_has_blkgetsize64(void) { int major=0, minor=0, patch=0, parsed; int rc; struct utsname u; memset(&u, 0, sizeof(u)); rc = uname(&u); if (rc) return 0; parsed = sscanf(u.release, "%d.%d.%d", &major, &minor, &patch); /* If the kernel is 2.4.15-2.4.18 and 2.5.0-2.5.3, i.e. the problem * kernels, then this will get 3 answers. If it doesn't, it isn't. */ if (parsed != 3) return 1; if (major == 2 && minor == 5 && patch < 4) return 0; if (major == 2 && minor == 4 && patch >= 15 && patch <= 18) return 0; return 1; } /************************************************************ * _get_num_sectors * Requires: * - filedes is an open file descriptor, suitable for reading * Modifies: nothing * Returns: * Last LBA value on success * 0 on error * * Try getting BLKGETSIZE64 and BLKSSZGET first, * then BLKGETSIZE if necessary. * Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64 * which returns the number of 512-byte sectors, not the size of * the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3. ************************************************************/ static uint64_t _get_num_sectors(int filedes) { unsigned long sectors=0; uint64_t bytes=0; int rc; if (kernel_has_blkgetsize64()) { rc = ioctl(filedes, BLKGETSIZE64, &bytes); if (!rc) return bytes / get_sector_size(filedes); } rc = ioctl(filedes, BLKGETSIZE, §ors); if (rc) return 0; return sectors; } /************************************************************ * last_lba(): return number of last logical block of device * * @fd * * Description: returns Last LBA value on success, 0 on error. * Notes: The value st_blocks gives the size of the file * in 512-byte blocks, which is OK if * EFI_BLOCK_SIZE_SHIFT == 9. ************************************************************/ static uint64_t last_lba(int filedes) { int rc; uint64_t sectors = 0; struct stat s; memset(&s, 0, sizeof (s)); rc = fstat(filedes, &s); if (rc == -1) { fprintf(stderr, "last_lba() could not stat: %s\n", strerror(errno)); return 0; } if (S_ISBLK(s.st_mode)) { sectors = _get_num_sectors(filedes); } else { fprintf(stderr, "last_lba(): I don't know how to handle files with mode %x\n", s.st_mode); sectors = 1; } return sectors - 1; } static ssize_t read_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count) { int rc; struct blkdev_ioctl_param ioctl_param; if (!buffer) return 0; ioctl_param.block = 0; /* read the last sector */ ioctl_param.content_length = count; ioctl_param.block_contents = buffer; rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param); if (rc == -1 && report_errors) perror("read failed"); return !rc; } static ssize_t read_lba(int fd, uint64_t lba, void *buffer, size_t bytes) { int sector_size = get_sector_size(fd); off_t offset = lba * sector_size; ssize_t bytesread; void *iobuf; size_t iobuf_size; int rc; off_t new_offset; iobuf_size = lcm(bytes, sector_size); rc = posix_memalign(&iobuf, sector_size, iobuf_size); if (rc) return rc; memset(iobuf, 0, bytes); new_offset = lseek(fd, offset, SEEK_SET); if (new_offset == (off_t)-1) { free(iobuf); return 0; } bytesread = read(fd, iobuf, iobuf_size); memcpy(buffer, iobuf, bytes); free(iobuf); /* Kludge. This is necessary to read/write the last block of an odd-sized disk, until Linux 2.5.x kernel fixes. This is only used by gpt.c, and only to read one sector, so we don't have to be fancy. */ if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) { bytesread = read_lastoddsector(fd, lba, buffer, bytes); } return bytesread; } /** * alloc_read_gpt_entries(): reads partition entries from disk * @fd is an open file descriptor to the whole disk * @gpt is a buffer into which the GPT will be put * Description: Returns ptes on success, NULL on error. * Allocates space for PTEs based on information found in @gpt. * Notes: remember to free pte when you're done! */ static gpt_entry * alloc_read_gpt_entries(int fd, gpt_header * gpt) { gpt_entry *pte; size_t count = __le32_to_cpu(gpt->num_partition_entries) * __le32_to_cpu(gpt->sizeof_partition_entry); if (!count) return NULL; pte = (gpt_entry *)malloc(count); if (!pte) return NULL; memset(pte, 0, count); if (!read_lba(fd, __le64_to_cpu(gpt->partition_entry_lba), pte, count)) { free(pte); return NULL; } return pte; } /** * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk * @fd is an open file descriptor to the whole disk * @lba is the Logical Block Address of the partition table * * Description: returns GPT header on success, NULL on error. Allocates * and fills a GPT header starting at @ from @bdev. * Note: remember to free gpt when finished with it. */ static gpt_header * alloc_read_gpt_header(int fd, uint64_t lba) { gpt_header *gpt; gpt = (gpt_header *) malloc(sizeof (gpt_header)); if (!gpt) return NULL; memset(gpt, 0, sizeof (*gpt)); if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) { free(gpt); return NULL; } return gpt; } /** * is_gpt_valid() - tests one GPT header and PTEs for validity * @fd is an open file descriptor to the whole disk * @lba is the logical block address of the GPT header to test * @gpt is a GPT header ptr, filled on return. * @ptes is a PTEs ptr, filled on return. * * Description: returns 1 if valid, 0 on error. * If valid, returns pointers to newly allocated GPT header and PTEs. */ static int is_gpt_valid(int fd, uint64_t lba, gpt_header ** gpt, gpt_entry ** ptes) { int rc = 0; /* default to not valid */ uint32_t crc, origcrc; if (!gpt || !ptes) return 0; if (!(*gpt = alloc_read_gpt_header(fd, lba))) return 0; /* Check the GUID Partition Table signature */ if (__le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { if (report_errors) fprintf(stderr, "GUID Partition Table Header signature is wrong" ": %" PRIx64" != %" PRIx64 "\n", (uint64_t)__le64_to_cpu((*gpt)->signature), GPT_HEADER_SIGNATURE); free(*gpt); *gpt = NULL; return rc; } /* Check the GUID Partition Table Header CRC */ origcrc = __le32_to_cpu((*gpt)->header_crc32); (*gpt)->header_crc32 = 0; crc = efi_crc32(*gpt, __le32_to_cpu((*gpt)->header_size)); if (crc != origcrc) { if (report_errors) fprintf(stderr, "GPTH CRC check failed, %x != %x.\n", origcrc, crc); (*gpt)->header_crc32 = __cpu_to_le32(origcrc); free(*gpt); *gpt = NULL; return 0; } (*gpt)->header_crc32 = __cpu_to_le32(origcrc); /* Check that the my_lba entry points to the LBA * that contains the GPT we read */ if (__le64_to_cpu((*gpt)->my_lba) != lba) { if (report_errors) fprintf(stderr, "my_lba %"PRIx64 "x != lba %"PRIx64 "x.\n", (uint64_t)__le64_to_cpu((*gpt)->my_lba), lba); free(*gpt); *gpt = NULL; return 0; } if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) { free(*gpt); *gpt = NULL; return 0; } /* Check the GUID Partition Entry Array CRC */ crc = efi_crc32(*ptes, __le32_to_cpu((*gpt)->num_partition_entries) * __le32_to_cpu((*gpt)->sizeof_partition_entry)); if (crc != __le32_to_cpu((*gpt)->partition_entry_array_crc32)) { if (report_errors) fprintf(stderr, "GUID Partitition Entry Array CRC check failed.\n"); free(*gpt); *gpt = NULL; free(*ptes); *ptes = NULL; return 0; } /* We're done, all's well */ return 1; } /** * compare_gpts() - Search disk for valid GPT headers and PTEs * @pgpt is the primary GPT header * @agpt is the alternate GPT header * @lastlba is the last LBA number * Description: Returns nothing. Sanity checks pgpt and agpt fields * and prints warnings on discrepancies. * */ static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba) { int error_found = 0; if (!pgpt || !agpt) return; if (!report_errors) return; if (__le64_to_cpu(pgpt->my_lba) != __le64_to_cpu(agpt->alternate_lba)) { fprintf(stderr, "GPT:Primary header LBA != Alt. header alternate_lba\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(pgpt->my_lba), (uint64_t)__le64_to_cpu(agpt->alternate_lba)); error_found++; } if (__le64_to_cpu(pgpt->alternate_lba) != __le64_to_cpu(agpt->my_lba)) { fprintf(stderr, "GPT:Primary header alternate_lba != Alt. header my_lba\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(pgpt->alternate_lba), (uint64_t)__le64_to_cpu(agpt->my_lba)); error_found++; } if (__le64_to_cpu(pgpt->first_usable_lba) != __le64_to_cpu(agpt->first_usable_lba)) { fprintf(stderr, "GPT:first_usable_lbas don't match.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(pgpt->first_usable_lba), (uint64_t)__le64_to_cpu(agpt->first_usable_lba)); error_found++; } if (__le64_to_cpu(pgpt->last_usable_lba) != __le64_to_cpu(agpt->last_usable_lba)) { fprintf(stderr, "GPT:last_usable_lbas don't match.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(pgpt->last_usable_lba), (uint64_t)__le64_to_cpu(agpt->last_usable_lba)); error_found++; } if (memcmp(&pgpt->disk_guid, &agpt->disk_guid, sizeof (pgpt->disk_guid))) { fprintf(stderr, "GPT:disk_guids don't match.\n"); error_found++; } if (__le32_to_cpu(pgpt->num_partition_entries) != __le32_to_cpu(agpt->num_partition_entries)) { fprintf(stderr, "GPT:num_partition_entries don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->num_partition_entries), __le32_to_cpu(agpt->num_partition_entries)); error_found++; } if (__le32_to_cpu(pgpt->sizeof_partition_entry) != __le32_to_cpu(agpt->sizeof_partition_entry)) { fprintf(stderr, "GPT:sizeof_partition_entry values don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->sizeof_partition_entry), __le32_to_cpu(agpt->sizeof_partition_entry)); error_found++; } if (__le32_to_cpu(pgpt->partition_entry_array_crc32) != __le32_to_cpu(agpt->partition_entry_array_crc32)) { fprintf(stderr, "GPT:partition_entry_array_crc32 values don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->partition_entry_array_crc32), __le32_to_cpu(agpt->partition_entry_array_crc32)); error_found++; } if (__le64_to_cpu(pgpt->alternate_lba) != lastlba) { fprintf(stderr, "GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(pgpt->alternate_lba), lastlba); error_found++; } if (__le64_to_cpu(agpt->my_lba) != lastlba) { fprintf(stderr, "GPT:Alternate GPT header not at the end of the disk.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", (uint64_t)__le64_to_cpu(agpt->my_lba), lastlba); error_found++; } if (error_found) fprintf(stderr, "GPT: Use GNU Parted to correct GPT errors.\n"); } /** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @fd is an open file descriptor to the whole disk * @gpt is a GPT header ptr, filled on return. * @ptes is a PTEs ptr, filled on return. * Description: Returns 1 if valid, 0 on error. * If valid, returns pointers to newly allocated GPT header and PTEs. * Validity depends on finding either the Primary GPT header and PTEs valid, * or the Alternate GPT header and PTEs valid, and the PMBR valid. */ static int find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes, int ignore_pmbr_err) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr = NULL; uint64_t lastlba; int ret = -1; errno = EINVAL; if (!gpt || !ptes) return -1; lastlba = last_lba(fd); good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { good_agpt = is_gpt_valid(fd, __le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt) { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } } else { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) { goto fail; } /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = malloc(sizeof (*legacymbr)); if (legacymbr) { memset(legacymbr, 0, sizeof (*legacymbr)); read_lba(fd, 0, (uint8_t *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); free(legacymbr); legacymbr=NULL; } /* Failure due to bad PMBR */ if ((good_pgpt || good_agpt) && !good_pmbr && !ignore_pmbr_err) { if (report_errors) fprintf(stderr, "Primary GPT is invalid, using alternate GPT.\n"); goto fail; } /* Would fail due to bad PMBR, but force GPT anyhow */ if ((good_pgpt || good_agpt) && !good_pmbr && ignore_pmbr_err && report_errors) { fprintf(stderr, " Warning: Disk has a valid GPT signature but invalid PMBR.\n" " Use GNU Parted to correct disk.\n" " gpt option taken, disk treated as GPT.\n"); } compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt && (good_pmbr || ignore_pmbr_err)) { *gpt = pgpt; *ptes = pptes; } else if (good_agpt && (good_pmbr || ignore_pmbr_err)) { *gpt = agpt; *ptes = aptes; } ret = 0; errno = 0; fail: if (pgpt && (pgpt != *gpt || ret < 0)) { free(pgpt); pgpt=NULL; } if (pptes && (pptes != *ptes || ret < 0)) { free(pptes); pptes=NULL; } if (agpt && (agpt != *gpt || ret < 0)) { free(agpt); agpt=NULL; } if (aptes && (aptes != *ptes || ret < 0)) { free(aptes); aptes=NULL; } if (ret < 0) { *gpt = NULL; *ptes = NULL; } return ret; } /************************************************************ * gpt_disk_get_partition_info() * Requires: * - open file descriptor fd * - start, size, signature, mbr_type, signature_type * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ int __attribute__((__nonnull__ (3, 4, 5, 6, 7))) __attribute__((__visibility__ ("hidden"))) gpt_disk_get_partition_info(int fd, uint32_t num, uint64_t * start, uint64_t * size, uint8_t *signature, uint8_t * mbr_type, uint8_t * signature_type, int ignore_pmbr_error) { gpt_header *gpt = NULL; gpt_entry *ptes = NULL, *p; int rc = 0; char *report=getenv("LIBEFIBOOT_REPORT_GPT_ERRORS"); if (report) report_errors = 1; rc = find_valid_gpt(fd, &gpt, &ptes, ignore_pmbr_error); if (rc < 0) return rc; *mbr_type = 0x02; *signature_type = 0x02; if (num > 0 && num <= __le32_to_cpu(gpt->num_partition_entries)) { p = &ptes[num - 1]; *start = __le64_to_cpu(p->starting_lba); *size = __le64_to_cpu(p->ending_lba) - __le64_to_cpu(p->starting_lba) + 1; memcpy(signature, &p->unique_partition_guid, sizeof (p->unique_partition_guid)); } else { if (report_errors) fprintf(stderr, "partition %d is not valid\n", num); errno = EINVAL; return -1; } if (ptes) free(ptes); if (gpt) free(gpt); return rc; } /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */ efivar-0.21/src/gpt.h000066400000000000000000000141041255101430600144370ustar00rootroot00000000000000/* gpt.[ch] Copyright (C) 2000-2001 Dell Computer Corporation EFI GUID Partition Table handling Per Intel EFI Specification v1.02 http://developer.intel.com/technology/efi/efi.htm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _EFIBOOT_GPT_H #define _EFIBOOT_GPT_H #include #define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE #define MSDOS_MBR_SIGNATURE 0xaa55 #define GPT_BLOCK_SIZE 512 #define GPT_HEADER_SIGNATURE ((uint64_t)(0x5452415020494645LL)) #define GPT_HEADER_REVISION_V1_02 0x00010200 #define GPT_HEADER_REVISION_V1_00 0x00010000 #define GPT_HEADER_REVISION_V0_99 0x00009900 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 #define PARTITION_SYSTEM_GUID \ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, 0xBA4B, \ 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) #define LEGACY_MBR_PARTITION_GUID \ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, 0x9D69, \ 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) #define PARTITION_MSFT_RESERVED_GUID \ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, 0x817D, \ 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) #define PARTITION_BASIC_DATA_GUID \ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, 0x87C0, \ 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) #define PARTITION_LINUX_RAID_GUID \ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, 0xA006, \ 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) #define PARTITION_LINUX_SWAP_GUID \ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, 0x84E5, \ 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) #define PARTITION_LINUX_LVM_GUID \ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, 0xa23c, \ 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) typedef struct _gpt_header { uint64_t signature; uint32_t revision; uint32_t header_size; uint32_t header_crc32; uint32_t reserved1; uint64_t my_lba; uint64_t alternate_lba; uint64_t first_usable_lba; uint64_t last_usable_lba; efi_guid_t disk_guid; uint64_t partition_entry_lba; uint32_t num_partition_entries; uint32_t sizeof_partition_entry; uint32_t partition_entry_array_crc32; uint8_t reserved2[GPT_BLOCK_SIZE - 92]; } __attribute__ ((packed)) gpt_header; typedef struct _gpt_entry_attributes { uint64_t required_to_function:1; uint64_t reserved:47; uint64_t type_guid_specific:16; } __attribute__ ((packed)) gpt_entry_attributes; typedef struct _gpt_entry { efi_guid_t partition_type_guid; efi_guid_t unique_partition_guid; uint64_t starting_lba; uint64_t ending_lba; gpt_entry_attributes attributes; uint16_t partition_name[72 / sizeof(uint16_t)]; } __attribute__ ((packed)) gpt_entry; /* These values are only defaults. The actual on-disk structures may define different sizes, so use those unless creating a new GPT disk! */ #define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384 /* Number of actual partition entries should be calculated as: */ #define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \ (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \ sizeof(gpt_entry)) typedef struct _partition_record { uint8_t boot_indicator; /* Not used by EFI firmware. Set to 0x80 to indicate that this is the bootable legacy partition. */ uint8_t start_head; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t start_sector; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t start_track; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t os_type; /* OS type. A value of 0xEF defines an EFI system partition. Other values are reserved for legacy operating systems, and allocated independently of the EFI specification. */ uint8_t end_head; /* End of partition in CHS address, not used by EFI firmware. */ uint8_t end_sector; /* End of partition in CHS address, not used by EFI firmware. */ uint8_t end_track; /* End of partition in CHS address, not used by EFI firmware. */ uint32_t starting_lba; /* Starting LBA address of the partition on the disk. Used by EFI firmware to define the start of the partition. */ uint32_t size_in_lba; /* Size of partition in LBA. Used by EFI firmware to determine the size of the partition. */ } __attribute__ ((packed)) partition_record; /* Protected Master Boot Record & Legacy MBR share same structure */ /* Needs to be packed because the u16s force misalignment. */ typedef struct _legacy_mbr { uint8_t bootcode[440]; uint32_t unique_mbr_signature; uint16_t unknown; partition_record partition[4]; uint16_t signature; } __attribute__ ((packed)) legacy_mbr; #define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1 /* Functions */ extern int gpt_disk_get_partition_info (int fd, uint32_t num, uint64_t *start, uint64_t *size, uint8_t *signature, uint8_t *mbr_type, uint8_t *signature_type, int ignore_pmbr_error) __attribute__((__nonnull__ (3, 4, 5, 6, 7))) __attribute__((__visibility__ ("hidden"))); #endif /* _EFIBOOT_GPT_H */ /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */ efivar-0.21/src/guid.c000066400000000000000000000151671255101430600146020ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2014 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include "efivar.h" #include "guid.h" #define GUID_LENGTH_WITH_NUL 37 int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_str_to_guid(const char *s, efi_guid_t *guid) { return text_to_guid(s, guid); } int __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_guid_to_str(const efi_guid_t *guid, char **sp) { char *ret = NULL; int rc = -1; if (!sp) { return snprintf(NULL, 0, GUID_FORMAT, guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); } else if (sp && *sp) { return snprintf(*sp, GUID_LENGTH_WITH_NUL, GUID_FORMAT, guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); } else { rc = asprintf(&ret, GUID_FORMAT, guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); if (rc >= 0) *sp = ret; } return rc; } extern struct guidname efi_well_known_guids[], efi_well_known_names[]; extern char efi_well_known_guids_end, efi_well_known_names_end; static int __attribute__((__nonnull__ (1, 2))) cmpguidp(const void *p1, const void *p2) { struct guidname *gn1 = (struct guidname *)p1; struct guidname *gn2 = (struct guidname *)p2; return memcmp(&gn1->guid, &gn2->guid, sizeof (gn1->guid)); } static int __attribute__((__nonnull__ (1, 2))) cmpnamep(const void *p1, const void *p2) { struct guidname *gn1 = (struct guidname *)p1; struct guidname *gn2 = (struct guidname *)p2; return memcmp(gn1->name, gn2->name, sizeof (gn1->name)); } static int __attribute__((__nonnull__ (1, 2))) _get_common_guidname(const efi_guid_t *guid, struct guidname **result) { intptr_t end = (intptr_t)&efi_well_known_guids_end; intptr_t start = (intptr_t)&efi_well_known_guids; size_t nmemb = (end - start) / sizeof (efi_well_known_guids[0]); struct guidname key; memset(&key, '\0', sizeof (key)); memcpy(&key.guid, guid, sizeof (*guid)); struct guidname *tmp; tmp = bsearch(&key, efi_well_known_guids, nmemb, sizeof (efi_well_known_guids[0]), cmpguidp); if (!tmp) { *result = NULL; errno = ENOENT; return -1; } *result = tmp; return 0; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_guid_to_name(efi_guid_t *guid, char **name) { struct guidname *result; int rc = _get_common_guidname(guid, &result); if (rc >= 0) { *name = strndup(result->name, sizeof (result->name) -1); return *name ? (int)strlen(*name) : -1; } return efi_guid_to_str(guid, name); } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_guid_to_symbol(efi_guid_t *guid, char **symbol) { struct guidname *result; int rc = _get_common_guidname(guid, &result); if (rc >= 0) { *symbol = strndup(result->symbol, sizeof (result->symbol) -1); return *symbol ? (int)strlen(*symbol) : -1; } errno = EINVAL; return -1; } int __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_guid_to_id_guid(const efi_guid_t *guid, char **sp) { struct guidname *result = NULL; char *ret = NULL; int rc; rc = _get_common_guidname(guid, &result); if (rc >= 0) { if (!sp) { return snprintf(NULL, 0, "{%s}", result->symbol + strlen("efi_guid_")); } else if (sp && *sp) { return snprintf(*sp, GUID_LENGTH_WITH_NUL + 2, "{%s}", result->symbol + strlen("efi_guid_")); } rc = asprintf(&ret, "{%s}", result->symbol + strlen("efi_guid_")); if (rc >= 0) *sp = ret; return rc; } if (!sp) { return snprintf(NULL, 0, "{"GUID_FORMAT"}", guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); } else if (sp && *sp) { return snprintf(*sp, GUID_LENGTH_WITH_NUL+2, "{"GUID_FORMAT"}", guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); } rc = asprintf(&ret, "{"GUID_FORMAT"}", guid->a, guid->b, guid->c, bswap_16(guid->d), guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); if (rc >= 0) *sp = ret; return rc; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_symbol_to_guid(const char *symbol, efi_guid_t *guid) { void *dlh = dlopen(NULL, RTLD_LAZY); if (!dlh) return -1; void *sym = dlsym(dlh, symbol); dlclose(dlh); if (!sym) return -1; memcpy(guid, sym, sizeof(*guid)); return 0; } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_name_to_guid(const char *name, efi_guid_t *guid) { intptr_t end = (intptr_t)&efi_well_known_names_end; intptr_t start = (intptr_t)&efi_well_known_names; size_t nmemb = (end - start) / sizeof (efi_well_known_names[0]); size_t namelen; if (!name || !guid) return -1; namelen = strnlen(name, 39); struct guidname key; memset(&key, '\0', sizeof (key)); memcpy(key.name, name, namelen); if (namelen > 2 && name[0] == '{' && name[namelen - 1] == '}') { namelen -= 2; memcpy(key.name, name + 1, namelen); memset(key.name + namelen, '\0', sizeof(key.name) - namelen); } key.name[sizeof(key.name) - 1] = '\0'; struct guidname *result; result = bsearch(&key, efi_well_known_names, nmemb, sizeof (efi_well_known_names[0]), cmpnamep); if (result != NULL) { memcpy(guid, &result->guid, sizeof (*guid)); return 0; } int rc = efi_str_to_guid(key.name, guid); if (rc >= 0) return 0; char tmpname[sizeof(key.name) + 9]; strcpy(tmpname, "efi_guid_"); memmove(tmpname+9, key.name, sizeof (key.name) - 9); rc = efi_symbol_to_guid(tmpname, guid); if (rc >= 0) return rc; errno = ENOENT; return -1; } int efi_id_guid_to_guid(const char *name, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) __attribute__ ((weak, alias ("efi_name_to_guid"))); efivar-0.21/src/guid.h000066400000000000000000000114111255101430600145730ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #ifndef LIBEFIVAR_GUID_H #define LIBEFIVAR_GUID_H 1 #include #include #include #include #include #define GUID_FORMAT "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x" static inline int real_isspace(char c) { char spaces[] = " \f\n\r\t\v"; for (int i = 0; spaces[i] != '\0'; i++) if (c == spaces[i]) return 1; return 0; } static inline int check_sanity(const char *text, size_t len) { size_t sl = strlen("84be9c3e-8a32-42c0-891c-4cd3b072becc"); errno = EINVAL; if (len < sl) return -1; else if (len > sl && !real_isspace(text[sl])) return -1; if (text[8] != '-' || text[13] != '-' || text[18] != '-' || text[23] != '-') return -1; errno = 0; return 0; } static inline int check_segment_sanity(const char *text, size_t len) { for(unsigned int i = 0; i < len; i++) { if (text[i] >= '0' && text[i] <= '9') continue; /* "| 0x20" is tolower() without having to worry about * locale concerns, since we know everything here must * be within traditional ascii space. */ if ((text[i] | 0x20) >= 'a' && (text[i] | 0x20) <= 'f') continue; errno = EINVAL; return -1; } return 0; } static inline int __attribute__((unused)) text_to_guid(const char *text, efi_guid_t *guid) { /* these variables represent the length of the /string/ they hold, * not the interpreted length of the value from them. Mostly the * names make it more obvious to verify that my bounds checking is * correct. */ char eightbytes[9] = ""; char fourbytes[5] = ""; char twobytes[3] = ""; size_t textlen = strlen(text); size_t guidlen = strlen("84be9c3e-8a32-42c0-891c-4cd3b072becc"); if (textlen == guidlen + 2) { if (text[0] != '{' || text[textlen - 1] != '}') { errno = EINVAL; return -1; } text++; textlen -= 2; } if (check_sanity(text, textlen) < 0) return -1; /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(eightbytes, text, 8); if (check_segment_sanity(eightbytes, 8) < 0) return -1; guid->a = (uint32_t)strtoul(eightbytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(fourbytes, text+9, 4); if (check_segment_sanity(fourbytes, 4) < 0) return -1; guid->b = (uint16_t)strtoul(fourbytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(fourbytes, text+14, 4); if (check_segment_sanity(fourbytes, 4) < 0) return -1; guid->c = (uint16_t)strtoul(fourbytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(fourbytes, text+19, 4); if (check_segment_sanity(fourbytes, 4) < 0) return -1; guid->d = bswap_16((uint16_t)strtoul(fourbytes, NULL, 16)); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+24, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[0] = (uint8_t)strtoul(twobytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+26, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[1] = (uint8_t)strtoul(twobytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+28, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[2] = (uint8_t)strtoul(twobytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+30, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[3] = (uint8_t)strtoul(twobytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+32, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[4] = (uint8_t)strtoul(twobytes, NULL, 16); /* 84be9c3e-8a32-42c0-891c-4cd3b072becc * ^ */ strncpy(twobytes, text+34, 2); if (check_segment_sanity(twobytes, 2) < 0) return -1; guid->e[5] = (uint8_t)strtoul(twobytes, NULL, 16); return 0; } struct guidname { efi_guid_t guid; char symbol[256]; char name[256]; }; #endif /* LIBEFIVAR_GUID */ efivar-0.21/src/guids.S000066400000000000000000000014671255101430600147430ustar00rootroot00000000000000 .globl efi_well_known_guids .data .balign 16 .type efi_well_known_guids, %object .size efi_well_known_guids, efi_well_known_guids_end - efi_well_known_guids efi_well_known_guids: .incbin "guids.bin" .globl efi_well_known_guids_end .data .balign 16 .type efi_well_known_guids_end, %object .size efi_well_known_guids_end, 1 efi_well_known_guids_end: .byte 0 .globl efi_well_known_names .data .balign 16 .type efi_well_known_names, %object .size efi_well_known_names, efi_well_known_names_end - efi_well_known_names efi_well_known_names: .incbin "names.bin" .globl efi_well_known_names_end .data .balign 16 .type efi_well_known_names_end, %object .size efi_well_known_names_end, 1 efi_well_known_names_end: .byte 0 #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif efivar-0.21/src/guids.txt000066400000000000000000000041071255101430600153520ustar00rootroot0000000000000000000000-0000-0000-0000-000000000000 zero zeroed sentinal guid 093e0fae-a6c4-4f50-9f1b-d41e2b89c19a sha512 SHA-512 0abba7dc-e516-4167-bbf5-4d9d1c739416 redhat Red Hat 0b6e5233-a65c-44c9-9407-d9ab83bfc8bd sha224 SHA-224 126a762d-5758-4fca-8531-201a7f57f850 lenovo_boot_menu Lenovo Boot Menu 3bd2a492-96c0-4079-b420-fcf98ef103ed x509_sha256 SHA256 hash of X.509 Certificate 3c5766e8-269c-4e34-aa14-ed776e85b3b6 rsa2048 RSA 2048 3CC24E96-22C7-41D8-8863-8E39DCDCC2CF lenovo Lenovo 3f7e615b-0d45-4f80-88dc-26b234958560 lenovo_diag Lenovo Diagnostics 446dbf63-2502-4cda-bcfa-2465d2b0fe9d x509_sha512 SHA512 hash of X.509 Certificate 4aafd29d-68df-49ee-8aa9-347d375665a7 pkcs7_cert PKCS7 Certificate 605dab50-e046-4300-abb6-3dd810dd8b23 shim shim 665d3f60-ad3e-4cad-8e26-db46eee9f1b5 lenovo_rescue Lenovo Rescue and Recovery 67f8444f-8743-48f1-a328-1eaab8736080 rsa2048_sha1 RSA 2048 with SHA-1 7076876e-80c2-4ee6-aad2-28b349a6865b x509_sha384 SHA384 hash of X.509 Certificate 721c8b66-426c-4e86-8e99-3457c46ab0b9 lenovo_setup Lenovo Firmware Setup 77fa9abd-0359-4d32-bd60-28f4e78f784b microsoft Microsoft 7FACC7B6-127F-4E9C-9C5D-080F98994345 lenovo_2 Lenovo 826ca512-cf10-4ac9-b187-be01496631bd sha1 SHA-1 82988420-7467-4490-9059-feb448dd1963 lenovo_me_config Lenovo ME Configuration Menu 8be4df61-93ca-11d2-aa0d-00e098032b8c global EFI Global Variable a5c059a1-94e4-4aa7-87b5-ab155c2bf072 x509_cert X.509 Certificate a7717414-c616-4977-9420-844712a735bf rsa2048_sha256_cert RSA 2048 with SHA-256 Certificate a7d8d9a6-6ab0-4aeb-ad9d-163e59a7a380 lenovo_diag_splash Lenovo Diagnostic Splash Screen ade9e48f-9cb8-98e6-31af-b4e6009e2fe3 redhat_2 Red Hat Maybe bc7838d2-0f82-4d60-8316-c068ee79d25b lenovo_msg Lenovo Vendor Message Device c1c41626-504c-4092-aca9-41f936934328 sha256 SHA-256 c57ad6b7-0515-40a8-9d21-551652854e37 shell EFI Shell d719b2cb-3d3a-4596-a3bc-dad00e67656f security EFI Security Database e2b36190-879b-4a3d-ad8d-f2e7bba32784 rsa2048_sha256 RSA 2048 with SHA-256 ff3e5307-9fd0-48c9-85f1-8ad56c701e01 sha384 SHA-384 f46ee6f4-4785-43a3-923d-7f786c3c8479 lenovo_startup_interrupt Lenovo Startup Interrupt Menu efivar-0.21/src/include/000077500000000000000000000000001255101430600151175ustar00rootroot00000000000000efivar-0.21/src/include/efivar/000077500000000000000000000000001255101430600163735ustar00rootroot00000000000000efivar-0.21/src/include/efivar/efiboot-creator.h000066400000000000000000000042351255101430600216340ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #ifndef _EFIBOOT_CREATOR_H #define _EFIBOOT_CREATOR_H #define EFIBOOT_ABBREV_NONE 0x00000001 #define EFIBOOT_ABBREV_HD 0x00000002 #define EFIBOOT_ABBREV_FILE 0x00000004 #define EFIBOOT_ABBREV_EDD10 0x00000008 #define EFIBOOT_OPTIONS_IGNORE_FS_ERROR 0x00000010 #define EFIBOOT_OPTIONS_WRITE_SIGNATURE 0x00000020 #define EFIBOOT_OPTIONS_IGNORE_PMBR_ERR 0x00000040 extern ssize_t efi_generate_file_device_path(uint8_t *buf, ssize_t size, const char * const filepath, uint32_t options, ...) __attribute__((__nonnull__ (3))); extern ssize_t efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, ...) __attribute__((__nonnull__ (3, 5))) __attribute__((__visibility__ ("default"))); extern ssize_t efi_generate_ipv4_device_path(uint8_t *buf, ssize_t size, const char * const ifname, const char * const local_addr, const char * const remote_addr, const char * const gateway_addr, const char * const netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, uint8_t addr_origin) __attribute__((__nonnull__ (3,4,5,6,7))) __attribute__((__visibility__ ("default"))); #endif /* _EFIBOOT_CREATOR_H */ efivar-0.21/src/include/efivar/efiboot-loadopt.h000066400000000000000000000057571255101430600216510ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #ifndef _EFIBOOT_LOADOPT_H #define _EFIBOOT_LOADOPT_H 1 typedef struct efi_load_option_s efi_load_option; extern ssize_t efi_loadopt_create(uint8_t *buf, ssize_t size, uint32_t attributes, efidp dp, ssize_t dp_size, unsigned char *description, uint8_t *optional_data, size_t optional_data_size) __attribute__((__nonnull__ (6))); extern efidp efi_loadopt_path(efi_load_option *opt) __attribute__((__nonnull__ (1))); extern const unsigned char * const efi_loadopt_desc(efi_load_option *opt) __attribute__((__visibility__ ("default"))) __attribute__((__nonnull__ (1))); extern uint32_t efi_loadopt_attrs(efi_load_option *opt) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); extern void efi_loadopt_attr_set(efi_load_option *opt, uint16_t attr) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); extern void efi_loadopt_attr_clear(efi_load_option *opt, uint16_t attr) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); extern uint16_t efi_loadopt_pathlen(efi_load_option *opt) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); extern int efi_loadopt_optional_data(efi_load_option *opt, size_t opt_size, unsigned char **datap, size_t *len) __attribute__((__nonnull__ (1,3))) __attribute__((__visibility__ ("default"))); extern ssize_t efi_loadopt_args_from_file(uint8_t *buf, ssize_t size, char *filename) __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))); extern ssize_t efi_loadopt_args_as_utf8(uint8_t *buf, ssize_t size, char *utf8) __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))); extern ssize_t efi_loadopt_args_as_ucs2(uint16_t *buf, ssize_t size, char *utf8) __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))); extern ssize_t efi_loadopt_optional_data_size(efi_load_option *opt, size_t size) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); extern int efi_loadopt_is_valid(efi_load_option *opt, size_t size) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))); #endif /* _EFIBOOT_LOADOPT_H */ efivar-0.21/src/include/efivar/efiboot.h000066400000000000000000000021641255101430600201760ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #ifndef EFIBOOT_H #define EFIBOOT_H 1 #include #include #include #include #include #include #include #include #include #include #include #endif /* EFIBOOT_H */ efivar-0.21/src/include/efivar/efivar-dp.h000066400000000000000000000561341255101430600204320ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #ifndef _EFIVAR_DP_H #define _EFIVAR_DP_H 1 #include /* Generic device path header */ typedef struct { uint8_t type; uint8_t subtype; uint16_t length; } efidp_header; /* A little bit of housekeeping... */ typedef uint8_t efidp_boolean; /* Each of the top-level types */ #define EFIDP_HARDWARE_TYPE 0x01 #define EFIDP_ACPI_TYPE 0x02 #define EFIDP_MESSAGE_TYPE 0x03 #define EFIDP_MEDIA_TYPE 0x04 #define EFIDP_BIOS_BOOT_TYPE 0x05 #define EFIDP_END_TYPE 0x7f /* Each hardware subtype */ #define EFIDP_HW_PCI 0x01 typedef struct { efidp_header header; uint8_t function; uint8_t device; } efidp_pci; extern ssize_t efidp_make_pci(uint8_t *buf, ssize_t size, uint8_t device, uint8_t function); #define EFIDP_HW_PCCARD 0x02 typedef struct { efidp_header header; uint8_t function; } efidp_pccard; #define EFIDP_HW_MMIO 0x03 typedef struct { efidp_header header; uint32_t memory_type; uint64_t starting_address; uint64_t ending_address; } efidp_mmio; #define EFIDP_HW_VENDOR 0x04 typedef struct { efidp_header header; efi_guid_t vendor_guid; uint8_t vendor_data[0]; } efidp_hw_vendor; typedef efidp_hw_vendor efidp_vendor_hw; #define efidp_make_hw_vendor(buf, size, guid, data, data_size) \ efidp_make_vendor(buf, size, EFIDP_HARDWARE_TYPE, \ EFIDP_HW_VENDOR, guid, data, data_size) #define EDD10_HARDWARE_VENDOR_PATH_GUID \ EFI_GUID(0xCF31FAC5,0xC24E,0x11d2,0x85F3,0x00,0xA0,0xC9,0x3E,0xC9,0x3B) typedef struct { efidp_header header; efi_guid_t vendor_guid; uint32_t hardware_device; } efidp_edd10; extern ssize_t efidp_make_edd10(uint8_t *buf, ssize_t size, uint32_t hardware_device); #define EFIDP_HW_CONTROLLER 0x05 typedef struct { efidp_header header; uint32_t controller; } efidp_controller; #define EFIDP_HW_BMC 0x06 typedef struct { efidp_header header; uint8_t interface_type; uint64_t base_addr; } efidp_bmc; #define EFIDP_BMC_UNKNOWN 0x00 #define EFIDP_BMC_KEYBOARD 0x01 #define EFIDP_BMC_SMIC 0x02 #define EFIDP_BMC_BLOCK 0x03 /* Each ACPI subtype */ #define EFIDP_ACPI_HID 0x01 typedef struct { efidp_header header; uint32_t hid; uint32_t uid; } efidp_acpi_hid; extern ssize_t efidp_make_acpi_hid(uint8_t *buf, ssize_t size, uint32_t hid, uint32_t uid); #define EFIDP_ACPI_HID_EX 0x02 typedef struct { efidp_header header; uint32_t hid; uint32_t uid; uint32_t cid; /* three ascii string fields follow */ char hidstr[]; } efidp_acpi_hid_ex; extern ssize_t efidp_make_acpi_hid_ex(uint8_t *buf, ssize_t size, uint32_t hid, uint32_t uid, uint32_t cid, char *hidstr, char *uidstr, char *cidstr) __attribute__((__nonnull__ (6,7,8))); #define EFIDP_PNP_EISA_ID_CONST 0x41d0 #define EFIDP_EISA_ID(_Name, _Num) ((uint32_t)((_Name) | (_Num) << 16)) #define EFIDP_EISA_PNP_ID(_PNPId) EFIDP_EISA_ID(EFIDP_PNP_EISA_ID_CONST,\ (_PNPId)) #define EFIDP_EFI_PNP_ID(_PNPId) EFIDP_EISA_ID(EFIDP_PNP_EISA_ID_CONST,\ (_PNPId)) #define EFIDP_PNP_EISA_ID_MASK 0xffff #define EFIDP_EISA_ID_TO_NUM(_Id) ((_Id) >> 16) #define EFIDP_ACPI_PCI_ROOT_HID EFIDP_EFI_PNP_ID(0x0a03) #define EFIDP_ACPI_PCIE_ROOT_HID EFIDP_EFI_PNP_ID(0x0a08) #define EFIDP_ACPI_FLOPPY_HID EFIDP_EFI_PNP_ID(0x0604) #define EFIDP_ACPI_KEYBOARD_HID EFIDP_EFI_PNP_ID(0x0301) #define EFIDP_ACPI_SERIAL_HID EFIDP_EFI_PNP_ID(0x0501) #define EFIDP_ACPI_PARALLEL_HID EFIDP_EFI_PNP_ID(0x0401) #define EFIDP_ACPI_ADR 0x03 typedef struct { efidp_header header; uint32_t adr[]; } efidp_acpi_adr; #define EFIDP_ACPI_ADR_DISPLAY_TYPE_OTHER 0 #define EFIDP_ACPI_ADR_DISPLAY_TYPE_VGA 1 #define EFIDP_ACPI_ADR_DISPLAY_TYPE_TV 2 #define EFIDP_ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3 #define EFIDP_ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4 #define EFIDP_ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput,\ _BiosCanDetect, _VendorInfo, _Type, _Port,\ _Index) \ ((UINT32)((((_DeviceIdScheme) & 0x1) << 31) | \ (((_HeadId) & 0x7) << 18) | \ (((_NonVgaOutput) & 0x1) << 17) | \ (((_BiosCanDetect) & 0x1) << 16) | \ (((_VendorInfo) & 0xf) << 12) | \ (((_Type) & 0xf) << 8) | \ (((_Port) & 0xf) << 4) | \ (((_Index) & 0xf) << 0))) /* Each messaging subtype */ #define EFIDP_MSG_ATAPI 0x01 typedef struct { efidp_header header; uint8_t primary; uint8_t slave; uint16_t lun; } efidp_atapi; extern ssize_t efidp_make_atapi(uint8_t *buf, ssize_t size, uint16_t primary, uint16_t slave, uint16_t lun); #define EFIDP_MSG_SCSI 0x02 typedef struct { efidp_header header; uint16_t target; uint16_t lun; } efidp_scsi; extern ssize_t efidp_make_scsi(uint8_t *buf, ssize_t size, uint16_t target, uint16_t lun); #define EFIDP_MSG_FIBRECHANNEL 0x03 typedef struct { efidp_header header; uint32_t reserved; uint64_t wwn; uint64_t lun; } efidp_fc; #define EFIDP_MSG_FIBRECHANNELEX 0x15 typedef struct { efidp_header header; uint32_t reserved; uint8_t wwn[8]; uint8_t lun[8]; } efidp_fcex; #define EFIDP_MSG_1394 0x04 typedef struct { efidp_header header; uint32_t reserved; uint64_t guid; } efidp_1394; #define EFIDP_MSG_USB 0x05 typedef struct { efidp_header header; uint8_t parent_port; uint8_t interface; } efidp_usb; #define EFIDP_MSG_USB_CLASS 0x0f typedef struct { efidp_header header; uint16_t vendor_id; uint16_t product_id; uint8_t device_class; uint8_t device_subclass; uint8_t device_protocol; } efidp_usb_class; #define EFIDP_USB_CLASS_AUDIO 0x01 #define EFIDP_USB_CLASS_CDC_CONTROL 0x02 #define EFIDP_USB_CLASS_HID 0x03 #define EFIDP_USB_CLASS_IMAGE 0x06 #define EFIDP_USB_CLASS_PRINTER 0x07 #define EFIDP_USB_CLASS_MASS_STORAGE 0x08 #define EFIDP_USB_CLASS_HUB 0x09 #define EFIDP_USB_CLASS_CDC_DATA 0x0a #define EFIDP_USB_CLASS_SMARTCARD 0x0b #define EFIDP_USB_CLASS_VIDEO 0x0e #define EFIDP_USB_CLASS_DIAGNOSTIC 0xdc #define EFIDP_USB_CLASS_WIRELESS 0xde #define EFIDP_USB_CLASS_254 0xfe #define EFIDP_USB_SUBCLASS_FW_UPDATE 0x01 #define EFIDP_USB_SUBCLASS_IRDA_BRIDGE 0x02 #define EFIDP_USB_SUBCLASS_TEST_AND_MEASURE 0x03 #define EFIDP_MSG_USB_WWID 0x10 typedef struct { efidp_header header; uint16_t interface; uint16_t vendor_id; uint16_t product_id; uint16_t serial_number[]; } efidp_usb_wwid; #define EFIDP_MSG_LUN 0x11 typedef struct { efidp_header header; uint8_t lun; } efidp_lun; #define EFIDP_MSG_SATA 0x12 typedef struct { efidp_header header; uint16_t hba_port; uint16_t port_multiplier_port; uint16_t lun; } efidp_sata; #define SATA_HBA_DIRECT_CONNECT_FLAG 0x8000 extern ssize_t efidp_make_sata(uint8_t *buf, ssize_t size, uint16_t hba_port, uint16_t port_multiplier_port, uint16_t lun); #define EFIDP_MSG_I2O 0x06 typedef struct { efidp_header header; uint32_t target; } efidp_i2o; #define EFIDP_MSG_MAC_ADDR 0x0b typedef struct { efidp_header header; uint8_t mac_addr[32]; uint8_t if_type; } efidp_mac_addr; extern ssize_t efidp_make_mac_addr(uint8_t *buf, ssize_t size, uint8_t if_type, const uint8_t * const mac_addr, ssize_t mac_addr_size); #define EFIDP_MSG_IPv4 0x0c typedef struct { efidp_header header; uint8_t local_ipv4_addr[4]; uint8_t remote_ipv4_addr[4]; uint16_t local_port; uint16_t remote_port; uint16_t protocol; efidp_boolean static_ip_addr; uint8_t gateway[4]; uint8_t netmask[4]; } efidp_ipv4_addr; /* everything here is in host byte order */ extern ssize_t efidp_make_ipv4(uint8_t *buf, ssize_t size, uint32_t local, uint32_t remote, uint32_t gateway, uint32_t netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, int is_static); #define EFIDP_IPv4_ORIGIN_DHCP 0x00 #define EFIDP_IPv4_ORIGIN_STATIC 0x01 #define EFIDP_MSG_IPv6 0x0d typedef struct { efidp_header header; uint8_t local_ipv6_addr[16]; uint8_t remote_ipv6_addr[16]; uint16_t local_port; uint16_t remote_port; uint16_t protocol; uint8_t ip_addr_origin; uint8_t prefix_length; uint8_t gateway_ipv6_addr; } efidp_ipv6_addr; #define EFIDP_IPv6_ORIGIN_MANUAL 0x00 #define EFIDP_IPv6_ORIGIN_AUTOCONF 0x01 #define EFIDP_IPv6_ORIGIN_STATEFUL 0x02 #define EFIDP_MSG_VLAN 0x14 typedef struct { efidp_header header; uint16_t vlan_id; } efidp_vlan; #define EFIDP_MSG_INFINIBAND 0x09 typedef struct { efidp_header header; uint32_t resource_flags; uint64_t port_gid[2]; union { uint64_t ioc_guid; uint64_t service_id; }; uint64_t target_port_id; uint64_t device_id; } efidp_infiniband; #define EFIDP_INFINIBAND_RESOURCE_IOC_SERVICE 0x01 #define EFIDP_INFINIBAND_RESOURCE_EXTENDED_BOOT 0x02 #define EFIDP_INFINIBAND_RESOURCE_CONSOLE 0x04 #define EFIDP_INFINIBAND_RESOURCE_STORAGE 0x08 #define EFIDP_INFINIBAND_RESOURCE_NETWORK 0x10 #define EFIDP_MSG_UART 0x0e typedef struct { efidp_header header; uint32_t reserved; uint64_t baud_rate; uint8_t data_bits; uint8_t parity; uint8_t stop_bits; } efidp_uart; #define EFIDP_UART_PARITY_DEFAULT 0x00 #define EFIDP_UART_PARITY_NONE 0x01 #define EFIDP_UART_PARITY_EVEN 0x02 #define EFIDP_UART_PARITY_ODD 0x03 #define EFIDP_UART_PARITY_MARK 0x04 #define EFIDP_UART_PARITY_SPACE 0x05 #define EFIDP_UART_STOP_BITS_DEFAULT 0x00 #define EFIDP_UART_STOP_BITS_ONE 0x01 #define EFIDP_UART_STOP_BITS_ONEFIVE 0x02 #define EFIDP_UART_STOP_BITS_TWO 0x03 #define EFIDP_PC_ANSI_GUID \ EFI_GUID(0xe0c14753,0xf9be,0x11d2,0x9a0c,0x00,0x90,0x27,0x3f,0xc1,0x4d) #define EFIDP_VT_100_GUID \ EFI_GUID(0xdfa66065,0xb419,0x11d3,0x9a2d,0x00,0x90,0x27,0x3f,0xc1,0x4d) #define EFIDP_VT_100_PLUS_GUID\ EFI_GUID(0x7baec70b,0x57e0,0x4c76,0x8e87,0x2f,0x9e,0x28,0x08,0x83,0x43) #define EFIDP_VT_UTF8_GUID\ EFI_GUID(0xad15a0d6,0x8bec,0x4acf,0xa073,0xd0,0x1d,0xe7,0x7e,0x2d,0x88) #define EFIDP_MSG_VENDOR 0x0a typedef struct { efidp_header header; efi_guid_t vendor_guid; uint8_t vendor_data[0]; } efidp_msg_vendor; typedef efidp_msg_vendor efidp_vendor_msg; #define efidp_make_msg_vendor(buf, size, guid, data, data_size) \ efidp_make_vendor(buf, size, EFIDP_MESSAGE_TYPE, \ EFIDP_MSG_VENDOR, guid, data, data_size) /* The next ones are phrased as vendor specific, but they're in the spec. */ #define EFIDP_MSG_UART_GUID \ EFI_GUID(0x37499a9d,0x542f,0x4c89,0xa026,0x35,0xda,0x14,0x20,0x94,0xe4) typedef struct { efidp_header header; efi_guid_t vendor_guid; uint32_t flow_control_map; } efidp_uart_flow_control; #define EFIDP_UART_FLOW_CONTROL_HARDWARE 0x1 #define EFIDP_UART_FLOW_CONTROL_XONXOFF 0x2 #define EFIDP_MSG_SAS_GUID \ EFI_GUID(0xd487ddb4,0x008b,0x11d9,0xafdc,0x00,0x10,0x83,0xff,0xca,0x4d) typedef struct { efidp_header header; efi_guid_t vendor_guid; uint32_t reserved; uint64_t sas_address; uint64_t lun; uint8_t device_topology_info; uint8_t drive_bay_id; /* If EFIDP_SAS_TOPOLOGY_NEXTBYTE set */ uint16_t rtp; } efidp_sas; extern ssize_t efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address); /* device_topology_info Bits 0:3 (enum) */ #define EFIDP_SAS_TOPOLOGY_MASK 0x02 #define EFIDP_SAS_TOPOLOGY_NONE 0x0 #define EFIDP_SAS_TOPOLOGY_THISBYTE 0x1 #define EFIDP_SAS_TOPOLOGY_NEXTBYTE 0x2 /* device_topology_info Bits 4:5 (enum) */ #define EFIDP_SAS_DEVICE_MASK 0x30 #define EFIDP_SAS_DEVICE_SHIFT 4 #define EFIDP_SAS_DEVICE_SAS_INTERNAL 0x0 #define EFIDP_SAS_DEVICE_SATA_INTERNAL 0x1 #define EFIDP_SAS_DEVICE_SAS_EXTERNAL 0x2 #define EFIDP_SAS_DEVICE_SATA_EXTERNAL 0x3 /* device_topology_info Bits 6:7 (enum) */ #define EFIDP_SAS_CONNECT_MASK 0x40 #define EFIDP_SAS_CONNECT_SHIFT 6 #define EFIDP_SAS_CONNECT_DIRECT 0x0 #define EFIDP_SAS_CONNECT_EXPANDER 0x1 #define EFIDP_MSG_SAS_EX 0x16 typedef struct { efidp_header header; uint8_t sas_address[8]; uint8_t lun[8]; uint8_t device_topology_info; uint8_t drive_bay_id; /* If EFIDP_SAS_TOPOLOGY_NEXTBYTE set */ uint16_t rtp; } efidp_sas_ex; #define EFIDP_MSG_DEBUGPORT_GUID \ EFI_GUID(0xEBA4E8D2,0x3858,0x41EC,0xA281,0x26,0x47,0xBA,0x96,0x60,0xD0) #define EFIDP_MSG_ISCSI 0x13 typedef struct { efidp_header header; uint16_t protocol; uint16_t options; uint8_t lun[8]; uint16_t tpgt; uint8_t target_name[0]; } efidp_iscsi; /* options bits 0:1 */ #define EFIDP_ISCSI_HEADER_DIGEST_SHIFT 0 #define EFIDP_ISCSI_NO_HEADER_DIGEST 0x0 #define EFIDP_ISCSI_HEADER_CRC32 0x2 /* option bits 2:3 */ #define EFIDP_ISCSI_DATA_DIGEST_SHIFT 2 #define EFIDP_ISCSI_NO_DATA_DIGEST 0x0 #define EFIDP_ISCSI_DATA_CRC32 0x2 /* option bits 4:9 */ #define EFIDP_ISCSI_RESERVED 0x0 /* option bits 10:11 */ #define EFIDP_ISCSI_AUTH_SHIFT 10 #define EFIDP_ISCSI_AUTH_CHAP 0x0 #define EFIDP_ISCSI_AUTH_NONE 0x2 /* option bit 12 */ #define EFIDP_ISCSI_CHAP_SHIFT 12 #define EFIDP_ISCSI_CHAP_BI 0x0 #define EFIDP_ISCSI_CHAP_UNI 0x1 #define EFIDP_ISCSI_MAX_TARGET_NAME_LEN 223 #define EFIDP_MSG_NVME 0x17 typedef struct { efidp_header header; uint32_t namespace_id; uint8_t ieee_eui_64[8]; } efidp_nvme; extern ssize_t efidp_make_nvme(uint8_t *buf, ssize_t size, uint32_t namespace_id, uint8_t *ieee_eui_64); #define EFIDP_MSG_URI 0x18 typedef struct { efidp_header header; uint8_t uri[0]; } efidp_uri; #define EFIDP_MSG_UFS 0x19 typedef struct { efidp_header header; uint8_t target_id; uint8_t lun; } efidp_ufs; #define EFIDP_MSG_SD 0x1a typedef struct { efidp_header header; uint8_t slot_number; } efidp_sd; /* Each media subtype */ #define EFIDP_MEDIA_HD 0x1 typedef struct { efidp_header header; uint32_t partition_number; uint64_t start; uint64_t size; uint8_t signature[16]; uint8_t format; uint8_t signature_type; #ifdef __ia64 uint8_t padding[6]; /* Emperically needed */ #endif } __attribute__((__packed__)) efidp_hd; extern ssize_t efidp_make_hd(uint8_t *buf, ssize_t size, uint32_t num, uint64_t part_start, uint64_t part_size, uint8_t *signature, uint8_t format, uint8_t signature_type); #define EFIDP_HD_FORMAT_PCAT 0x01 #define EFIDP_HD_FORMAT_GPT 0x02 #define EFIDP_HD_SIGNATURE_NONE 0x00 #define EFIDP_HD_SIGNATURE_MBR 0x01 #define EFIDP_HD_SIGNATURE_GUID 0x02 #define EFIDP_MEDIA_CDROM 0x2 typedef struct { efidp_header header; uint32_t boot_catalog_entry; uint64_t partition_rba; uint64_t sectors; } efidp_cdrom; #define EFIDP_MEDIA_VENDOR 0x3 typedef struct { efidp_header header; efi_guid_t vendor_guid; uint8_t vendor_data[0]; } efidp_media_vendor; typedef efidp_media_vendor efidp_vendor_media; #define efidp_make_media_vendor(buf, size, guid, data, data_size) \ efidp_make_vendor(buf, size, EFIDP_MEDIA_TYPE, \ EFIDP_MEDIA_VENDOR, guid, data, data_size) #define EFIDP_MEDIA_FILE 0x4 typedef struct { efidp_header header; uint16_t name[]; } efidp_file; extern ssize_t efidp_make_file(uint8_t *buf, ssize_t size, char *filename); #define EFIDP_MEDIA_PROTOCOL 0x5 typedef struct { efidp_header header; efi_guid_t protocol_guid; } efidp_protocol; #define EFIDP_MEDIA_FIRMWARE_FILE 0x6 typedef struct { efidp_header header; uint8_t pi_info[0]; } efidp_firmware_file; #define EFIDP_MEDIA_FIRMWARE_VOLUME 0x7 typedef struct { efidp_header header; uint8_t pi_info[0]; } efidp_firmware_volume; #define EFIDP_MEDIA_RELATIVE_OFFSET 0x8 typedef struct { efidp_header header; uint32_t reserved; uint64_t first_byte; uint64_t last_byte; } efidp_relative_offset; #define EFIDP_MEDIA_RAMDISK 0x9 typedef struct { efidp_header header; uint64_t start_addr; uint64_t end_addr; efi_guid_t disk_type_guid; uint16_t instance_number; } efidp_ramdisk; #define EFIDP_VIRTUAL_DISK_GUID \ EFI_GUID(0x77AB535A,0x45FC,0x624B,0x5560,0xF7,0xB2,0x81,0xD1,0xF9,0x6E) #define EFIDP_VIRTUAL_CD_GUID \ EFI_GUID(0x3D5ABD30,0x4175,0x87CE,0x6D64,0xD2,0xAD,0xE5,0x23,0xC4,0xBB) #define EFIDP_PERSISTENT_VIRTUAL_DISK_GUID \ EFI_GUID(0x5CEA02C9,0x4D07,0x69D3,0x269F,0x44,0x96,0xFB,0xE0,0x96,0xF9) #define EFIDP_PERSISTENT_VIRTUAL_CD_GUID \ EFI_GUID(0x08018188,0x42CD,0xBB48,0x100F,0x53,0x87,0xD5,0x3D,0xED,0x3D) /* Each BIOS Boot subtype */ #define EFIDP_BIOS_BOOT 0x1 typedef struct { efidp_header header; uint16_t device_type; uint16_t status; uint8_t description[0]; } efidp_bios_boot; #define EFIDP_BIOS_BOOT_DEVICE_TYPE_FLOPPY 1 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_HD 2 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_CDROM 3 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_PCMCIA 4 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_USB 5 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_EMBEDDED_NET 6 #define EFIDP_BIOS_BOOT_DEVICE_TYPE_UNKNOWN 0xff #define EFIDP_END_ENTIRE 0xff #define EFIDP_END_INSTANCE 0x01 /* utility functions */ typedef union { struct { uint8_t type; uint8_t subtype; uint16_t length; }; efidp_header header; efidp_pci pci; efidp_pccard pccard; efidp_mmio mmio; efidp_hw_vendor hw_vendor; efidp_controller controller; efidp_bmc bmc; efidp_acpi_hid acpi_hid; efidp_acpi_hid_ex acpi_hid_ex; efidp_acpi_adr acpi_adr; efidp_atapi atapi; efidp_scsi scsi; efidp_fc fc; efidp_fcex fcex; efidp_1394 firewire; efidp_usb usb; efidp_usb_class usb_class; efidp_usb_wwid usb_wwid; efidp_lun lun; efidp_sata sata; efidp_i2o i2o; efidp_mac_addr mac_addr; efidp_ipv4_addr ipv4_addr; efidp_ipv6_addr ipv6_addr; efidp_vlan vlan; efidp_infiniband infiniband; efidp_uart uart; efidp_msg_vendor msg_vendor; efidp_uart_flow_control uart_flow_control; efidp_sas sas; efidp_sas_ex sas_ex; efidp_iscsi iscsi; efidp_nvme nvme; efidp_uri uri; efidp_ufs ufs; efidp_sd sd; efidp_hd hd; efidp_cdrom cdrom; efidp_media_vendor media_vendor; efidp_file file; efidp_protocol protocol; efidp_firmware_file firmware_file; efidp_firmware_volume firmware_volume; efidp_relative_offset relative_offset; efidp_ramdisk ramdisk; efidp_bios_boot bios_boot; } efidp_data; typedef efidp_data *efidp; typedef const efidp_data *const_efidp; extern int efidp_set_node_data(const_efidp dn, void *buf, size_t bufsize); extern int efidp_duplicate_path(const_efidp dp, efidp *out); extern int efidp_append_path(const_efidp dp0, const_efidp dp1, efidp *out); extern int efidp_append_node(const_efidp dp, const_efidp dn, efidp *out); extern int efidp_append_instance(const_efidp dp, const_efidp dpi, efidp *out); static inline int16_t __attribute__((__unused__)) efidp_type(const_efidp dp) { if (!dp) { errno = EINVAL; return -1; } return (uint8_t)dp->type; } static inline int16_t __attribute__((__unused__)) efidp_subtype(const_efidp dp) { if (!dp) { errno = EINVAL; return -1; } return (uint8_t)dp->subtype; } static inline ssize_t __attribute__((__unused__)) efidp_node_size(const_efidp dn) { if (!dn || dn->length < 4) { errno = EINVAL; return -1; } return dn->length; } static inline int __attribute__((__unused__)) efidp_next_node(const_efidp in, const_efidp *out) { if (efidp_type(in) == EFIDP_END_TYPE) return -1; ssize_t sz = efidp_node_size(in); if (sz < 0) return -1; /* I love you gcc. */ *out = (const_efidp)(const efidp_header *)((uint8_t *)in + sz); return 0; } static inline int __attribute__((__unused__)) efidp_next_instance(const_efidp in, const_efidp *out) { if (efidp_type(in) != EFIDP_END_TYPE || efidp_subtype(in) != EFIDP_END_INSTANCE) return -1; ssize_t sz = efidp_node_size(in); if (sz < 0) return -1; /* I love you gcc. */ *out = (const_efidp)(const efidp_header *)((uint8_t *)in + sz); return 0; } static inline int __attribute__((__unused__)) efidp_is_multiinstance(const_efidp dn) { while (1) { const_efidp next; int rc = efidp_next_node(dn, &next); if (rc < 0) break; } if (efidp_type(dn) == EFIDP_END_TYPE && efidp_subtype(dn) == EFIDP_END_INSTANCE) return 1; return 0; } static inline int __attribute__((__unused__)) efidp_get_next_end(const_efidp in, const_efidp *out) { while (1) { if (efidp_type(in) == EFIDP_END_TYPE) { *out = in; return 0; } ssize_t sz; sz = efidp_node_size(in); if (sz < 0) break; in = (const_efidp)(const efidp_header *)((uint8_t *)in + sz); } return -1; } static inline ssize_t __attribute__((__unused__)) efidp_size(const_efidp dp) { ssize_t ret = 0; if (!dp) { errno = EINVAL; return -1; } while (1) { ssize_t sz; int rc; const_efidp next; sz = efidp_node_size(dp); if (sz < 0) return sz; ret += sz; if (efidp_type(dp) == EFIDP_END_TYPE && efidp_subtype(dp) == EFIDP_END_ENTIRE) break; rc = efidp_next_instance(dp, &next); if (rc < 0) rc = efidp_next_node(dp, &next); if (rc < 0) return -1; dp = next; } return ret; } static inline ssize_t __attribute__((__unused__)) efidp_instance_size(const_efidp dpi) { ssize_t ret = 0; while (1) { ssize_t sz; const_efidp next; sz = efidp_node_size(dpi); if (sz < 0) return sz; ret += sz; if (efidp_type(dpi) == EFIDP_END_TYPE) break; int rc = efidp_next_node(dpi, &next); if (rc < 1) return -1; dpi = next; } return ret; } static inline int __attribute__((__unused__)) __attribute__((__nonnull__ (1))) efidp_is_valid(const_efidp dp, ssize_t limit) { efidp_header *hdr = (efidp_header *)dp; /* just to make it so I'm not checking for negatives everywhere, * limit this at a truly absurdly large size. */ if (limit < 0) limit = INT_MAX; while (limit > 0 && hdr) { if (limit < (int64_t)(sizeof (efidp_header))) return 0; switch (hdr->type) { case EFIDP_HARDWARE_TYPE: if (hdr->subtype != EFIDP_HW_VENDOR && hdr->length > 1024) return 0; break; case EFIDP_ACPI_TYPE: if (hdr->length > 1024) return 0; break; case EFIDP_MESSAGE_TYPE: if (hdr->subtype != EFIDP_MSG_VENDOR && hdr->length > 1024) return 0; break; case EFIDP_MEDIA_TYPE: if (hdr->subtype != EFIDP_MEDIA_VENDOR && hdr->length > 1024) return 0; break; case EFIDP_BIOS_BOOT_TYPE: break; case EFIDP_END_TYPE: if (hdr->length > 4) return 0; break; default: return 0; } if (limit < hdr->length) return 0; limit -= hdr->length; if (hdr->type != EFIDP_END_TYPE && hdr->type != EFIDP_END_ENTIRE) break; hdr = (efidp_header *)((uint8_t *)hdr + hdr->length); } return (limit >= 0); } /* and now, printing and parsing */ extern ssize_t efidp_parse_device_node(char *path, efidp out, size_t size); extern ssize_t efidp_parse_device_path(char *path, efidp out, size_t size); extern ssize_t efidp_format_device_path(char *buf, size_t size, const_efidp dp, ssize_t limit); extern ssize_t efidp_make_vendor(uint8_t *buf, ssize_t size, uint8_t type, uint8_t subtype, efi_guid_t vendor_guid, void *data, size_t data_size); extern ssize_t efidp_make_generic(uint8_t *buf, ssize_t size, uint8_t type, uint8_t subtype, ssize_t total_size); #define efidp_make_end_entire(buf, size) \ efidp_make_generic(buf, size, EFIDP_END_TYPE, EFIDP_END_ENTIRE, \ sizeof (efidp_header)); #define efidp_make_end_instance(buf, size) \ efidp_make_generic(buf, size, EFIDP_END_TYPE, \ EFIDP_END_INSTANCE, sizeof (efidp_header)); #endif /* _EFIVAR_DP_H */ efivar-0.21/src/include/efivar/efivar.h000066400000000000000000000154261255101430600200300ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2014 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #ifndef EFIVAR_H #define EFIVAR_H 1 #include #include #include #include #include #include #include #include typedef struct { uint32_t a; uint16_t b; uint16_t c; uint16_t d; uint8_t e[6]; } efi_guid_t; #ifndef EFIVAR_BUILD_ENVIRONMENT #include #endif #define EFI_GUID(a,b,c,d,e0,e1,e2,e3,e4,e5) \ ((efi_guid_t) {(a), (b), (c), bswap_16(d), { (e0), (e1), (e2), (e3), (e4), (e5) }}) #define EFI_GLOBAL_GUID EFI_GUID(0x8be4df61,0x93ca,0x11d2,0xaa0d,0x00,0xe0,0x98,0x03,0x2b,0x8c) #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 #define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 #define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 #define EFI_VARIABLE_HAS_AUTH_HEADER 0x0000000100000000 #define EFI_VARIABLE_HAS_SIGNATURE 0x0000000200000000 extern int efi_variables_supported(void); extern int efi_get_variable_size(efi_guid_t guid, const char *name, size_t *size) __attribute__((__nonnull__ (2, 3))); extern int efi_get_variable_attributes(efi_guid_t, const char *name, uint32_t *attributes) __attribute__((__nonnull__ (2, 3))); extern int efi_get_variable(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes) __attribute__((__nonnull__ (2, 3, 4, 5))); extern int efi_del_variable(efi_guid_t guid, const char *name) __attribute__((__nonnull__ (2))); extern int _efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) __attribute__((__nonnull__ (2, 3))); extern int _efi_set_variable_variadic(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, ...); __attribute__((__nonnull__ (2, 3))) extern inline int __attribute__((__gnu_inline__)) __attribute__((__artificial__)) __attribute__((__visibility__ ("default"))) efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, ...) { if (__builtin_va_arg_pack_len() != 0 && __builtin_va_arg_pack_len() != 1) { errno = EINVAL; return -1; } if (__builtin_va_arg_pack_len() == 0) return _efi_set_variable(guid, name, data, data_size, attributes, 0644); return _efi_set_variable_variadic(guid, name, data, data_size, attributes, __builtin_va_arg_pack()); } extern int efi_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) __attribute__((__nonnull__ (2, 3))); extern int efi_get_next_variable_name(efi_guid_t **guid, char **name) __attribute__((__nonnull__ (1, 2))); extern int efi_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) __attribute__((__nonnull__ (2))); extern int efi_str_to_guid(const char *s, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))); extern int efi_guid_to_str(const efi_guid_t *guid, char **sp) __attribute__((__nonnull__ (1))); extern int efi_guid_to_id_guid(const efi_guid_t *guid, char **sp) __attribute__((__nonnull__ (1))); extern int efi_guid_to_symbol(efi_guid_t *guid, char **symbol) __attribute__((__nonnull__ (1, 2))); extern int efi_guid_to_name(efi_guid_t *guid, char **name) __attribute__((__nonnull__ (1, 2))); extern int efi_name_to_guid(const char *name, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))); extern int efi_id_guid_to_guid(const char *name, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))); extern int efi_symbol_to_guid(const char *symbol, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))); static inline int __attribute__ ((unused)) __attribute__((__nonnull__ (1, 2))) efi_guid_cmp(const efi_guid_t *a, const efi_guid_t *b) { return memcmp(a, b, sizeof (efi_guid_t)); } extern const efi_guid_t efi_guid_zero; static inline int __attribute__ ((unused)) __attribute__((__nonnull__ (1))) efi_guid_is_zero(const efi_guid_t *guid) { return !efi_guid_cmp(guid,&efi_guid_zero); } extern int efi_guid_is_empty(const efi_guid_t *guid) __attribute__ ((unused)) __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) __attribute__ ((weak, alias ("efi_guid_is_zero"))); /* import / export functions */ typedef struct efi_variable efi_variable_t; extern ssize_t efi_variable_import(uint8_t *data, size_t size, efi_variable_t **var) __attribute__((__nonnull__ (1, 3))); extern ssize_t efi_variable_export(efi_variable_t *var, uint8_t *data, size_t size) __attribute__((__nonnull__ (1))); extern efi_variable_t *efi_variable_alloc(void) __attribute__((__visibility__ ("default"))); extern void efi_variable_free(efi_variable_t *var, int free_data); extern int efi_variable_set_name(efi_variable_t *var, char *name) __attribute__((__nonnull__ (1, 2))); extern char *efi_variable_get_name(efi_variable_t *var) __attribute__((__visibility__ ("default"))) __attribute__((__nonnull__ (1))); extern int efi_variable_set_guid(efi_variable_t *var, efi_guid_t *guid) __attribute__((__nonnull__ (1, 2))); extern int efi_variable_get_guid(efi_variable_t *var, efi_guid_t **guid) __attribute__((__nonnull__ (1, 2))); extern int efi_variable_set_data(efi_variable_t *var, uint8_t *data, size_t size) __attribute__((__nonnull__ (1, 2))); extern ssize_t efi_variable_get_data(efi_variable_t *var, uint8_t **data, size_t *size) __attribute__((__nonnull__ (1, 2, 3))); extern int efi_variable_set_attributes(efi_variable_t *var, uint64_t attrs) __attribute__((__nonnull__ (1))); extern int efi_variable_get_attributes(efi_variable_t *var, uint64_t *attrs) __attribute__((__nonnull__ (1, 2))); extern int efi_variable_realize(efi_variable_t *var) __attribute__((__nonnull__ (1))); #include #endif /* EFIVAR_H */ efivar-0.21/src/lib.c000066400000000000000000000110521255101430600144050ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include "efivar.h" #include "lib.h" #include "generics.h" static int default_probe(void) { return 1; } struct efi_var_operations default_ops = { .name = "default", .probe = default_probe, }; struct efi_var_operations *ops = NULL; int __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) _efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) { return ops->set_variable(guid, name, data, data_size, attributes, mode); } int __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) _efi_set_variable_variadic(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, ...) { va_list ap; va_start(ap, attributes); mode_t mode = va_arg(ap, mode_t); va_end(ap); return ops->set_variable(guid, name, data, data_size, attributes, mode); } extern typeof(_efi_set_variable_variadic) efi_set_variable __attribute__ ((alias ("_efi_set_variable_variadic"))); int __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) efi_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { if (!ops->append_variable) return generic_append_variable(guid, name, data, data_size, attributes); return ops->append_variable(guid, name, data, data_size, attributes); } int __attribute__((__nonnull__ (2))) __attribute__((__visibility__ ("default"))) efi_del_variable(efi_guid_t guid, const char *name) { if (!ops->del_variable) { errno = ENOSYS; return -1; } return ops->del_variable(guid, name); } int __attribute__((__nonnull__ (2, 3, 4, 5))) __attribute__((__visibility__ ("default"))) efi_get_variable(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes) { if (!ops->get_variable) { errno = ENOSYS; return -1; } return ops->get_variable(guid, name, data, data_size, attributes); } int __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) efi_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t *attributes) { if (!ops->get_variable_attributes) { errno = ENOSYS; return -1; } return ops->get_variable_attributes(guid, name, attributes); } int __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) efi_get_variable_size(efi_guid_t guid, const char *name, size_t *size) { if (!ops->get_variable_size) { errno = ENOSYS; return -1; } return ops->get_variable_size(guid, name, size); } int __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_get_next_variable_name(efi_guid_t **guid, char **name) { if (!ops->get_next_variable_name) { errno = ENOSYS; return -1; } return ops->get_next_variable_name(guid, name); } int __attribute__((__nonnull__ (2))) __attribute__((__visibility__ ("default"))) efi_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { if (!ops->chmod_variable) { errno = ENOSYS; return -1; } return ops->chmod_variable(guid, name, mode); } int __attribute__((__visibility__ ("default"))) efi_variables_supported(void) { if (ops == &default_ops) return 0; return 1; } static void libefivar_init(void) __attribute__((constructor)); static void libefivar_init(void) { struct efi_var_operations *ops_list[] = { &efivarfs_ops, &vars_ops, &default_ops, NULL }; char *ops_name = getenv("LIBEFIVAR_OPS"); for (int i = 0; ops_list[i] != NULL; i++) { if (ops_name != NULL) { if (!strcmp(ops_list[i]->name, ops_name) || !strcmp(ops_list[i]->name, "default")) { ops = ops_list[i]; break; } } else if (ops_list[i]->probe()) { ops = ops_list[i]; break; } } } efivar-0.21/src/lib.h000066400000000000000000000035731255101430600144230ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #ifndef LIBEFIVAR_LIB_H #define LIBEFIVAR_LIB_H 1 #include "efivar.h" #include #include #define GUID_FORMAT "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x" struct efi_var_operations { char name[NAME_MAX]; int (*probe)(void); int (*set_variable)(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode); int (*del_variable)(efi_guid_t guid, const char *name); int (*get_variable)(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes); int (*get_variable_attributes)(efi_guid_t guid, const char *name, uint32_t *attributes); int (*get_variable_size)(efi_guid_t guid, const char *name, size_t *size); int (*get_next_variable_name)(efi_guid_t **guid, char **name); int (*append_variable)(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes); int (*chmod_variable)(efi_guid_t guid, const char *name, mode_t mode); }; typedef unsigned long efi_status_t; extern struct efi_var_operations vars_ops; extern struct efi_var_operations efivarfs_ops; #endif /* LIBEFIVAR_LIB_H */ efivar-0.21/src/linux.c000066400000000000000000000467551255101430600150200ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dp.h" #include "linux.h" #include "util.h" int __attribute__((__visibility__ ("hidden"))) eb_nvme_ns_id(int fd, uint32_t *ns_id) { uint64_t ret = ioctl(fd, NVME_IOCTL_ID, NULL); if ((int)ret < 0) return ret; *ns_id = (uint32_t)ret; return 0; } int __attribute__((__visibility__ ("hidden"))) set_disk_and_part_name(struct disk_info *info) { char *linkbuf; ssize_t rc; rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%hhd", info->major, info->minor); if (rc < 0) return -1; char *ultimate; ultimate = strrchr(linkbuf, '/'); if (!ultimate) { errno = EINVAL; return -1; } *ultimate = '\0'; ultimate++; char *penultimate; penultimate = strrchr(linkbuf, '/'); if (!penultimate) { errno = EINVAL; return -1; } penultimate++; if (!strcmp(penultimate, "block")) { if (!info->disk_name) { info->disk_name = strdup(ultimate); if (!info->disk_name) return -1; } if (!info->part_name) { rc = asprintf(&info->part_name, "%s%d", info->disk_name, info->part); if (rc < 0) return -1; } } else { if (!info->disk_name) { info->disk_name = strdup(penultimate); if (!info->disk_name) return -1; } if (!info->part_name) { info->part_name = strdup(ultimate); if (!info->part_name) return -1; } } return 0; } int __attribute__((__visibility__ ("hidden"))) get_partition_number(const char *devpath) { struct stat statbuf = { 0, }; int rc; unsigned int maj, min; char *linkbuf; char *partbuf; int ret = -1; rc = stat(devpath, &statbuf); if (rc < 0) return -1; if (!S_ISBLK(statbuf.st_mode)) { errno = EINVAL; return -1; } maj = gnu_dev_major(statbuf.st_rdev); min = gnu_dev_minor(statbuf.st_rdev); rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%u:%u", maj, min); if (rc < 0) return -1; rc = read_sysfs_file(&partbuf, "/sys/dev/block/%s/partition", linkbuf); if (rc < 0) return -1; rc = sscanf(partbuf, "%d\n", &ret); if (rc != 1) return -1; return ret; } static int sysfs_test_sata(const char *buf, ssize_t size) { if (!strncmp(buf, "ata", MIN(size,3))) return 1; return 0; } static int sysfs_test_sas(const char *buf, ssize_t size, struct disk_info *info) { int rc; char *path; struct stat statbuf = { 0, }; int host; int sz; errno = 0; rc = sscanf(buf, "host%d/%n", &host, &sz); if (rc < 1) return (errno == 0) ? 0 : -1; rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address", host); if (rc < 0) return -1; rc = stat(path, &statbuf); if (rc >= 0) return 1; return 0; } static ssize_t sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info) { DIR *d; struct dirent *de; int saved_errno; uint8_t *buf = NULL; int rc; d = opendir("/sys/class/ata_device/"); if (!d) return -1; while ((de = readdir(d)) != NULL) { uint32_t found_print_id; uint32_t found_pmp; uint32_t found_devno = 0; if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; int rc; rc = sscanf(de->d_name, "dev%d.%d.%d", &found_print_id, &found_pmp, &found_devno); if (rc == 2) { found_devno = found_pmp; found_pmp=0; } else if (rc != 3) { saved_errno = errno; closedir(d); errno = saved_errno; return -1; } if (found_print_id == print_id) { info->sata_info.ata_devno = found_devno; info->sata_info.ata_pmp = found_pmp; break; } } closedir(d); rc = read_sysfs_file(&buf, "/sys/class/ata_port/ata%d/port_no", print_id); if (rc <= 0) return -1; rc = sscanf((char *)buf, "%d", &info->sata_info.ata_port); if (rc != 1) return -1; info->sata_info.ata_port -= 1; return 0; } static ssize_t sysfs_parse_sata(uint8_t *buf, ssize_t size, ssize_t *off, const char *pbuf, ssize_t psize, ssize_t *poff, struct disk_info *info) { int psz = 0; int rc; *poff = 0; *off = 0; uint32_t print_id; uint32_t scsi_bus; uint32_t scsi_device; uint32_t scsi_target; uint32_t scsi_lun; /* find the ata info: * ata1/host0/target0:0:0/ * ^dev ^host x y z */ rc = sscanf(pbuf, "ata%d/host%d/target%d:%d:%d/%n", &print_id, &scsi_bus, &scsi_device, &scsi_target, &scsi_lun, &psz); if (rc != 5) return -1; *poff += psz; /* find the emulated scsi bits (and ignore them) * 0:0:0:0/ */ uint32_t dummy0, dummy1, dummy2; uint64_t dummy3; rc = sscanf(pbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", &dummy0, &dummy1, &dummy2, &dummy3, &psz); if (rc != 4) return -1; *poff += psz; /* what's left is: * block/sda/sda4 */ char *disk_name = NULL; char *part_name = NULL; int psz1 = 0; rc = sscanf(pbuf+*poff, "block/%m[^/]%n/%m[^/]%n", &disk_name, &psz, &part_name, &psz1); if (rc == 1) { rc = asprintf(&part_name, "%s%d", disk_name, info->part); if (rc < 0) { free(disk_name); errno = EINVAL; return -1; } *poff += psz; } else if (rc != 2) { errno = EINVAL; return -1; } else { *poff += psz1; } info->sata_info.scsi_bus = scsi_bus; info->sata_info.scsi_device = scsi_device; info->sata_info.scsi_target = scsi_target; info->sata_info.scsi_lun = scsi_lun; rc = sysfs_sata_get_port_info(print_id, info); if (rc < 0) { free(disk_name); free(part_name); return -1; } if (pbuf[*poff] != '\0') { free(disk_name); free(part_name); errno = EINVAL; return -1; } info->disk_name = disk_name; info->part_name = part_name; if (info->interface_type == interface_type_unknown) info->interface_type = sata; if (info->interface_type == ata) { *off = efidp_make_atapi(buf, size, info->sata_info.ata_port, info->sata_info.ata_pmp, info->sata_info.ata_devno); } else { *off = efidp_make_sata(buf, size, info->sata_info.ata_port, info->sata_info.ata_pmp, info->sata_info.ata_devno); } return *off; } static ssize_t sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off, const char *pbuf, ssize_t psize, ssize_t *poff, struct disk_info *info) { int rc; int psz = 0; char *filebuf = NULL; uint64_t sas_address; *poff = 0; *off = 0; /* buf is: * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1 */ uint32_t tosser0, tosser1, tosser2; /* ignore a bunch of stuff * host4/port-4:0 * or host4/port-4:0:0 */ rc = sscanf(pbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1, &tosser2, &psz); if (rc != 3) return -1; *poff += psz; psz = 0; rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz); if (rc != 0 && rc != 1) return -1; *poff += psz; /* next: * /end_device-4:0 * or /end_device-4:0:0 * awesomely these are the exact same fields that go into port-blah, * but we don't care for now about any of them anyway. */ rc = sscanf(pbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1, &psz); if (rc != 2) return -1; *poff += psz; psz = 0; rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz); if (rc != 0 && rc != 1) return -1; *poff += psz; /* now: * /target4:0:0/ */ uint64_t tosser3; rc = sscanf(pbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0, &tosser1, &tosser3, &psz); if (rc != 3) return -1; *poff += psz; /* now: * %d:%d:%d:%llu/ */ rc = sscanf(pbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", &info->sas_info.scsi_bus, &info->sas_info.scsi_device, &info->sas_info.scsi_target, &info->sas_info.scsi_lun, &psz); if (rc != 4) return -1; *poff += psz; /* what's left is: * block/sdc/sdc1 */ char *disk_name = NULL; char *part_name = NULL; rc = sscanf(pbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name, &part_name, &psz); if (rc != 2) return -1; *poff += psz; if (pbuf[*poff] != '\0') { free(disk_name); free(part_name); errno = EINVAL; return -1; } /* * we also need to get the actual sas_address from someplace... */ rc = read_sysfs_file(&filebuf, "/sys/class/block/%s/device/sas_address", disk_name); if (rc < 0) return -1; rc = sscanf(filebuf, "%"PRIx64, &sas_address); if (rc != 1) return -1; info->sas_info.sas_address = sas_address; info->disk_name = disk_name; info->part_name = part_name; info->interface_type = sas; *off = efidp_make_sas(buf, size, sas_address); return *off; } static ssize_t make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff) { ssize_t off=0, sz=0; ssize_t poff = 0; int psz; int rc; if (pathstr == NULL || pathoff == NULL || pathstr[0] == '\0') { errno = EINVAL; return -1; } *pathoff = 0; uint16_t root_domain; uint8_t root_bus; uint32_t acpi_hid = 0; uint64_t acpi_uid_int = 0; /* * find the pci root domain and port; they basically look like: * pci0000:00/ * ^d ^p */ rc = sscanf(pathstr+poff, "pci%hx:%hhx/%n", &root_domain, &root_bus, &psz); if (rc != 2) return -1; poff += psz; char *fbuf = NULL; rc = read_sysfs_file(&fbuf, "/sys/devices/pci%04x:%02x/firmware_node/hid", root_domain, root_bus); if (rc < 0) return -1; uint16_t tmp16 = 0; rc = sscanf((char *)fbuf, "PNP%hx", &tmp16); if (rc != 1) return -1; acpi_hid = EFIDP_EFI_PNP_ID(tmp16); /* Apparently basically nothing can look up a PcieRoot() node, * because they just check _CID. So since _CID for the root pretty * much always has to be PNP0A03 anyway, just use that no matter * what. */ if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID) acpi_hid = EFIDP_ACPI_PCI_ROOT_HID; errno = 0; fbuf = NULL; int use_uid_str = 0; rc = read_sysfs_file(&fbuf, "/sys/devices/pci%4x:%02x/firmware_node/uid", root_domain, root_bus); if (rc <= 0 && errno != ENOENT) return -1; if (rc > 0) { rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int); if (rc != 1) { /* kernel uses "%s\n" to print it, so there * should always be some value and a newline... */ int l = strlen((char *)buf); if (l >= 1) { use_uid_str=1; fbuf[l-1] = '\0'; } } } errno = 0; if (use_uid_str) { sz = efidp_make_acpi_hid_ex(buf+off, size?size-off:0, acpi_hid, 0, 0, "", (char *)fbuf, ""); } else { sz = efidp_make_acpi_hid(buf+off, size?size-off:0, acpi_hid, acpi_uid_int); } if (sz < 0) return -1; off += sz; /* find the pci domain/bus/device/function: * 0000:00:01.0/0000:01:00.0/ * ^d ^b ^d ^f (of the last one in the series) */ int found=0; while (1) { uint16_t domain; uint8_t bus, device, function; rc = sscanf(pathstr+poff, "%hx:%hhx:%hhx.%hhx/%n", &domain, &bus, &device, &function, &psz); if (rc != 4) break; found=1; poff += psz; sz = efidp_make_pci(buf+off, size?size-off:0, device, function); if (sz < 0) return -1; off += sz; } if (!found) return -1; *pathoff = poff; return off; } int __attribute__((__visibility__ ("hidden"))) make_blockdev_path(uint8_t *buf, ssize_t size, int fd, struct disk_info *info) { char *linkbuf = NULL; char *driverbuf = NULL; ssize_t off=0, sz=0, loff=0; int lsz = 0; int rc; int found = 0; rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%u", info->major, info->minor); if (rc < 0) return -1; /* * the sysfs path basically looks like: * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART */ rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz); if (rc != 0) return -1; loff += lsz; ssize_t tmplsz=0; sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz); if (sz < 0) return -1; loff += tmplsz; off += sz; char *tmppath = strdupa(linkbuf); if (!tmppath) return -1; tmppath[loff] = '\0'; rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver", tmppath); if (rc < 0) return -1; char *driver = strrchr(driverbuf, '/'); if (!driver || !*driver) return -1; driver+=1; if (!strncmp(driver, "pata_", 5) || !(strcmp(driver, "ata_piix"))) info->interface_type = ata; if (info->interface_type == interface_type_unknown || info->interface_type == atapi || info->interface_type == usb || info->interface_type == i1394 || info->interface_type == fibre || info->interface_type == i2o || info->interface_type == md) { uint32_t tosser; int tmpoff; rc = sscanf(linkbuf+loff, "virtio%x/%n", &tosser, &tmpoff); if (rc < 0) { return -1; } else if (rc == 1) { info->interface_type = virtblk; loff += tmpoff; found = 1; } if (!found) { uint32_t ns_id=0; int rc = eb_nvme_ns_id(fd, &ns_id); if (rc >= 0) { sz = efidp_make_nvme(buf+off, size?size-off:0, ns_id, NULL); if (sz < 0) return -1; info->interface_type = nvme; off += sz; found = 1; } } } /* /dev/sda as SATA looks like: * /sys/dev/block/8:0 -> ../../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda */ if (!found) { rc = sysfs_test_sata(linkbuf+loff, PATH_MAX-off); if (rc < 0) return -1; if (!found && rc > 0) { ssize_t linksz=0; rc = sysfs_parse_sata(buf+off, size?size-off:0, &sz, linkbuf+loff, PATH_MAX-off, &linksz, info); if (rc < 0) return -1; loff += linksz; off += sz; found = 1; } } /* /dev/sdc as SAS looks like: * /sys/dev/block/8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc */ if (!found) { rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off, info); if (rc < 0) return -1; else if (rc > 0) { ssize_t linksz=0; rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz, linkbuf+loff, PATH_MAX-off, &linksz, info); if (rc < 0) return -1; loff += linksz; off += sz; found = 1; } } if (!found && info->interface_type == scsi) { char *linkbuf; rc = sysfs_readlink(&linkbuf, "/sys/class/block/%s/device", info->disk_name); if (rc < 0) return 0; rc = sscanf(linkbuf, "../../../%d:%d:%d:%"PRIu64, &info->scsi_info.scsi_bus, &info->scsi_info.scsi_device, &info->scsi_info.scsi_target, &info->scsi_info.scsi_lun); if (rc != 4) return -1; sz = efidp_make_scsi(buf+off, size?size-off:0, info->scsi_info.scsi_target, info->scsi_info.scsi_lun); if (sz < 0) return -1; off += sz; found = 1; } if (!found) { errno = ENOENT; return -1; } return off; } int __attribute__((__visibility__ ("hidden"))) eb_disk_info_from_fd(int fd, struct disk_info *info) { struct stat buf; int rc; memset(info, 0, sizeof *info); info->pci_root.root_pci_domain = 0xffff; info->pci_root.root_pci_bus = 0xff; memset(&buf, 0, sizeof(struct stat)); rc = fstat(fd, &buf); if (rc == -1) { perror("stat"); return 1; } if (S_ISBLK(buf.st_mode)) { info->major = buf.st_rdev >> 8; info->minor = buf.st_rdev & 0xFF; } else if (S_ISREG(buf.st_mode)) { info->major = buf.st_dev >> 8; info->minor = buf.st_dev & 0xFF; } else { printf("Cannot stat non-block or non-regular file\n"); return 1; } /* IDE disks can have up to 64 partitions, or 6 bits worth, * and have one bit for the disk number. * This leaves an extra bit at the top. */ if (info->major == 3) { info->disknum = (info->minor >> 6) & 1; info->controllernum = (info->major - 3 + 0) + info->disknum; info->interface_type = ata; info->part = info->minor & 0x3F; return 0; } else if (info->major == 22) { info->disknum = (info->minor >> 6) & 1; info->controllernum = (info->major - 22 + 2) + info->disknum; info->interface_type = ata; info->part = info->minor & 0x3F; return 0; } else if (info->major >= 33 && info->major <= 34) { info->disknum = (info->minor >> 6) & 1; info->controllernum = (info->major - 33 + 4) + info->disknum; info->interface_type = ata; info->part = info->minor & 0x3F; return 0; } else if (info->major >= 56 && info->major <= 57) { info->disknum = (info->minor >> 6) & 1; info->controllernum = (info->major - 56 + 8) + info->disknum; info->interface_type = ata; info->part = info->minor & 0x3F; return 0; } else if (info->major >= 88 && info->major <= 91) { info->disknum = (info->minor >> 6) & 1; info->controllernum = (info->major - 88 + 12) + info->disknum; info->interface_type = ata; info->part = info->minor & 0x3F; return 0; } /* I2O disks can have up to 16 partitions, or 4 bits worth. */ if (info->major >= 80 && info->major <= 87) { info->interface_type = i2o; info->disknum = 16*(info->major-80) + (info->minor >> 4); info->part = (info->minor & 0xF); return 0; } /* SCSI disks can have up to 16 partitions, or 4 bits worth * and have one bit for the disk number. */ if (info->major == 8) { info->interface_type = scsi; info->disknum = (info->minor >> 4); info->part = (info->minor & 0xF); return 0; } else if (info->major >= 65 && info->major <= 71) { info->interface_type = scsi; info->disknum = 16*(info->major-64) + (info->minor >> 4); info->part = (info->minor & 0xF); return 0; } else if (info->major >= 128 && info->major <= 135) { info->interface_type = scsi; info->disknum = 16*(info->major-128) + (info->minor >> 4); info->part = (info->minor & 0xF); return 0; } errno = ENOSYS; return -1; } static ssize_t make_net_pci_path(uint8_t *buf, ssize_t size, const char * const ifname) { char *linkbuf = NULL; ssize_t off=0, sz=0, loff=0; int lsz = 0; int rc; rc = sysfs_readlink(&linkbuf, "/sys/class/net/%s", ifname); if (rc < 0) return -1; /* * the sysfs path basically looks like: * ../../devices/$PCI_STUFF/net/$IFACE */ rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz); if (rc != 0) return -1; loff += lsz; ssize_t tmplsz = 0; sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz); if (sz < 0) return -1; off += sz; loff += tmplsz; return off; } ssize_t __attribute__((__visibility__ ("hidden"))) make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname) { struct ifreq ifr = { 0, }; struct ethtool_drvinfo drvinfo = { 0, }; int fd, rc; ssize_t ret = -1, sz, off=0; char busname[PATH_MAX+1] = ""; strncpy(ifr.ifr_name, ifname, IF_NAMESIZE); drvinfo.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t)&drvinfo; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return -1; rc = ioctl(fd, SIOCETHTOOL, &ifr); if (rc < 0) goto err; strncpy(busname, drvinfo.bus_info, PATH_MAX); rc = ioctl(fd, SIOCGIFHWADDR, &ifr); if (rc < 0) goto err; sz = make_net_pci_path(buf, size, ifname); if (sz < 0) goto err; off += sz; sz = efidp_make_mac_addr(buf+off, size?size-off:0, ifr.ifr_ifru.ifru_hwaddr.sa_family, (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data, sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data)); if (sz < 0) return -1; off += sz; ret = off; err: if (fd >= 0) close(fd); return ret; } efivar-0.21/src/linux.h000066400000000000000000000051331255101430600150060ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #ifndef _EFIBOOT_LINUX_H #define _EFIBOOT_LINUX_H struct pci_root_info { uint16_t root_pci_domain; uint8_t root_pci_bus; uint32_t root_pci_acpi_hid; uint32_t root_pci_acpi_uid; }; struct pci_dev_info { uint16_t pci_domain; uint8_t pci_bus; uint8_t pci_device; uint8_t pci_function; }; struct scsi_info { uint32_t scsi_bus; uint32_t scsi_device; uint32_t scsi_target; uint64_t scsi_lun; }; struct sas_info { uint32_t scsi_bus; uint32_t scsi_device; uint32_t scsi_target; uint64_t scsi_lun; uint64_t sas_address; }; struct sata_info { uint32_t scsi_bus; uint32_t scsi_device; uint32_t scsi_target; uint64_t scsi_lun; uint32_t ata_devno; uint32_t ata_port; uint32_t ata_pmp; }; struct disk_info { int interface_type; unsigned int controllernum; unsigned int disknum; unsigned char part; uint64_t major; unsigned char minor; uint32_t edd10_devicenum; struct pci_root_info pci_root; struct pci_dev_info pci_dev; union { struct scsi_info scsi_info; struct sas_info sas_info; struct sata_info sata_info; }; char *disk_name; char *part_name; }; enum _bus_type {bus_type_unknown, isa, pci}; enum _interface_type {interface_type_unknown, ata, atapi, scsi, sata, sas, usb, i1394, fibre, i2o, md, virtblk, nvme}; extern int eb_disk_info_from_fd(int fd, struct disk_info *info); extern int set_disk_and_part_name(struct disk_info *info); extern int make_blockdev_path(uint8_t *buf, ssize_t size, int fd, struct disk_info *info); extern int eb_nvme_ns_id(int fd, uint32_t *ns_id); extern int get_partition_number(const char *devpath) __attribute__((__visibility__ ("hidden"))); extern ssize_t make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname) __attribute__((__visibility__ ("hidden"))); #endif /* _EFIBOOT_LINUX_H */ efivar-0.21/src/list.h000066400000000000000000000101061255101430600146160ustar00rootroot00000000000000/* Copied from the Linux 2.4.4 kernel, in linux/include/linux/list.h */ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; typedef struct list_head list_t; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head * new, struct list_head * prev, struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static __inline__ void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static __inline__ void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #endif efivar-0.21/src/loadopt.c000066400000000000000000000150011255101430600152770ustar00rootroot00000000000000/* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. * Copyright (C) 2001 Dell Computer Corporation * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include #include "dp.h" typedef struct efi_load_option_s { uint32_t attributes; uint16_t file_path_list_length; uint16_t description[]; // uint8_t file_path_list[]; // uint8_t optional_data[]; } __attribute__((packed)) efi_load_option; ssize_t __attribute__((__nonnull__ (6))) __attribute__((__visibility__ ("default"))) efi_loadopt_create(uint8_t *buf, ssize_t size, uint32_t attributes, efidp dp, ssize_t dp_size, unsigned char *description, uint8_t *optional_data, size_t optional_data_size) { if (!description) { errno = EINVAL; return -1; } ssize_t desc_len = utf8len((uint8_t *)description, 1024) * 2 + 2; ssize_t sz = sizeof (attributes) + sizeof (uint16_t) + desc_len + dp_size + optional_data_size; if (size == 0) return sz; if (size < sz) { errno = ENOSPC; return -1; } if (!optional_data && optional_data_size != 0) { errno = EINVAL; return -1; } if (!dp && dp_size == 0) { errno = EINVAL; return -1; } uint8_t *pos = buf; *(uint32_t *)pos = attributes; pos += sizeof (attributes); *(uint16_t *)pos = dp_size; pos += sizeof (uint16_t); utf8_to_ucs2((uint16_t *)pos, desc_len, 1, (uint8_t *)description); pos += desc_len; memcpy(pos, dp, dp_size); pos += dp_size; if (optional_data && optional_data_size > 0) memcpy(pos, optional_data, optional_data_size); return sz; } ssize_t __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_optional_data_size(efi_load_option *opt, size_t size) { size_t sz; uint8_t *p; if (!opt) return -1; if (size < sizeof(*opt)) return -1; size -= sizeof(*opt); if (size < opt->file_path_list_length) return -1; sz = ucs2size(opt->description, size); if (sz >= size) // since there's no room for a file path... return -1; p = (uint8_t *)(opt->description) + sz; size -= sz; if (!efidp_is_valid((const_efidp)p, size)) return -1; sz = efidp_size((const_efidp)p); p += sz; size -= sz; return size; } int __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_is_valid(efi_load_option *opt, size_t size) { ssize_t rc; rc = efi_loadopt_optional_data_size(opt, size); return (rc >= 0); } uint32_t __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_attrs(efi_load_option *opt) { return opt->attributes; } void __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_attr_set(efi_load_option *opt, uint16_t attr) { opt->attributes |= attr; } void __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_attr_clear(efi_load_option *opt, uint16_t attr) { opt->attributes &= ~attr; } uint16_t __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_pathlen(efi_load_option *opt) { return opt->file_path_list_length; } efidp __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) efi_loadopt_path(efi_load_option *opt) { char *p = (char *)opt; if (!opt) { errno = EINVAL; return NULL; } efidp dp = (efidp)(p + sizeof (opt->attributes) + sizeof (opt->file_path_list_length) + ucs2size(opt->description, -1)); return dp; } int __attribute__((__nonnull__ (1,3))) __attribute__((__visibility__ ("default"))) efi_loadopt_optional_data(efi_load_option *opt, size_t opt_size, unsigned char **datap, size_t *len) { unsigned char *p = (unsigned char *)opt; if (!opt || !datap) { errno = EINVAL; return -1; } *datap = (unsigned char *)(p + sizeof (opt->attributes) + sizeof (opt->file_path_list_length) + ucs2size(opt->description, -1) + opt->file_path_list_length); if (len && opt_size > 0) *len = (p+opt_size) - *datap; return 0; } ssize_t __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))) efi_loadopt_args_from_file(uint8_t *buf, ssize_t size, char *filename) { int rc; ssize_t ret = -1; struct stat statbuf = { 0, }; int saved_errno; FILE *f; if (!filename || (!buf && size > 0)) { errno = -EINVAL; return -1; } f = fopen(filename, "r"); if (!f) return -1; rc = fstat(fileno(f), &statbuf); if (rc < 0) goto err; if (size == 0) return statbuf.st_size; if (size < statbuf.st_size) { errno = ENOSPC; goto err; } ret = fread(buf, 1, statbuf.st_size, f); if (ret < statbuf.st_size) ret = -1; err: saved_errno = errno; if (f) fclose(f); errno = saved_errno; return ret; } ssize_t __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))) efi_loadopt_args_as_utf8(uint8_t *buf, ssize_t size, char *utf8) { ssize_t req; if (!utf8 || (!buf && size > 0)) { errno = EINVAL; return -1; } /* we specifically want the storage size without NUL here, * not the size with NUL or the number of utf8 characters */ req = strlen(utf8); if (size == 0) return req; if (size < req) { errno = ENOSPC; return -1; } memcpy(buf, utf8, req); return req; } ssize_t __attribute__((__nonnull__ (3))) __attribute__((__visibility__ ("default"))) efi_loadopt_args_as_ucs2(uint16_t *buf, ssize_t size, uint8_t *utf8) { ssize_t req; if (!utf8 || (!buf && size > 0)) { errno = EINVAL; return -1; } req = utf8len(utf8, -1) * sizeof(uint16_t); if (size == 0) return req; if (size < req) { errno = ENOSPC; return -1; } return utf8_to_ucs2(buf, size, 0, utf8); } static unsigned char *last_desc; static void __attribute__((destructor)) teardown(void) { if (last_desc) free(last_desc); last_desc = NULL; } __attribute__((__nonnull__ (1))) __attribute__((__visibility__ ("default"))) const unsigned char * const efi_loadopt_desc(efi_load_option *opt) { if (last_desc) { free(last_desc); last_desc = NULL; } last_desc = ucs2_to_utf8(opt->description, -1); return last_desc; } efivar-0.21/src/makeguids.c000066400000000000000000000130651255101430600156160ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include "efivar.h" #include "util.h" #include "guid.h" efi_guid_t const efi_guid_zero = {0}; efi_guid_t const efi_guid_empty = {0}; struct guidname efi_well_known_guids[] = { }; char efi_well_known_guids_end; struct guidname efi_well_known_names[] = { }; char efi_well_known_names_end; static int cmpguidp(const void *p1, const void *p2) { struct guidname *gn1 = (struct guidname *)p1; struct guidname *gn2 = (struct guidname *)p2; return memcmp(&gn1->guid, &gn2->guid, sizeof (gn1->guid)); } static int cmpnamep(const void *p1, const void *p2) { struct guidname *gn1 = (struct guidname *)p1; struct guidname *gn2 = (struct guidname *)p2; return memcmp(gn1->name, gn2->name, sizeof (gn1->name)); } int main(int argc, char *argv[]) { if (argc != 6) exit(1); int in, guidout, nameout; int rc; FILE *symout, *header; in = open(argv[1], O_RDONLY); if (in < 0) err(1, "makeguids: could not open \"%s\"", argv[1]); guidout = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0644); if (guidout < 0) err(1, "makeguids: could not open \"%s\"", argv[2]); nameout = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, 0644); if (nameout < 0) err(1, "makeguids: could not open \"%s\"", argv[3]); symout = fopen(argv[4], "w"); if (symout == NULL) err(1, "makeguids: could not open \"%s\"", argv[4]); rc = chmod(argv[4], 0644); if (rc < 0) warn("makeguids: chmod(%s, 0644)", argv[4]); header = fopen(argv[5], "w"); if (header == NULL) err(1, "makeguids: could not open \"%s\"", argv[5]); rc = chmod(argv[5], 0644); if (rc < 0) warn("makeguids: chmod(%s, 0644)", argv[5]); char *inbuf = NULL; size_t inlen = 0; rc = read_file(in, (uint8_t **)&inbuf, &inlen); if (rc < 0) err(1, "makeguids: could not read \"%s\"", argv[1]); struct guidname *outbuf = malloc(1); if (!outbuf) err(1, "makeguids"); char *guidstr = inbuf; unsigned int line; for (line = 1; (uintptr_t)guidstr - (uintptr_t)inbuf < inlen; line++) { if (guidstr && guidstr[0] == '\0') break; outbuf = realloc(outbuf, line * sizeof (struct guidname)); if (!outbuf) err(1, "makeguids"); char *symbol = strchr(guidstr, '\t'); if (symbol == NULL) err(1, "makeguids: \"%s\": 1 invalid data on line %d", argv[1], line); *symbol = '\0'; symbol += 1; char *name = strchr(symbol, '\t'); if (name == NULL) err(1, "makeguids: \"%s\": 2 invalid data on line %d", argv[1], line); *name = '\0'; name += 1; char *end = strchr(name, '\n'); if (end == NULL) err(1, "makeguids: \"%s\": 3 invalid data on line %d", argv[1], line); *end = '\0'; efi_guid_t guid; rc = efi_str_to_guid(guidstr, &guid); if (rc < 0) err(1, "makeguids: \"%s\": 4 invalid data on line %d", argv[1], line); memcpy(&outbuf[line-1].guid, &guid, sizeof(guid)); strcpy(outbuf[line-1].symbol, "efi_guid_"); strncat(outbuf[line-1].symbol, symbol, 255 - strlen("efi_guid_")); strncpy(outbuf[line-1].name, name, 255); guidstr = end+1; } printf("%d lines\n", line-1); fprintf(header, "#ifndef EFIVAR_GUIDS_H\n#define EFIVAR_GUIDS_H 1\n\n"); for (unsigned int i = 0; i < line-1; i++) { if (!strcmp(outbuf[i].symbol, "efi_guid_zero")) fprintf(symout, "\t.globl %s\n" "\t.data\n" "\t.balign 1\n" "\t.type %s, %%object\n" "\t.size %s, %s_end - %s\n", "efi_guid_empty", "efi_guid_empty", "efi_guid_empty", "efi_guid_empty", "efi_guid_empty"); fprintf(symout, "\t.globl %s\n" "\t.data\n" "\t.balign 1\n" "\t.type %s, %%object\n" "\t.size %s, %s_end - %s\n" "%s:\n", outbuf[i].symbol, outbuf[i].symbol, outbuf[i].symbol, outbuf[i].symbol, outbuf[i].symbol, outbuf[i].symbol); if (!strcmp(outbuf[i].symbol, "efi_guid_zero")) fprintf(symout, "efi_guid_empty:\n"); uint8_t *guid_data = (uint8_t *) &outbuf[i].guid; for (unsigned int j = 0; j < sizeof (efi_guid_t); j++) fprintf(symout,"\t.byte 0x%02x\n", guid_data[j]); fprintf(symout, "%s_end:\n", outbuf[i].symbol); if (!strcmp(outbuf[i].symbol, "efi_guid_zero")) { fprintf(symout, "efi_guid_empty_end:\n"); fprintf(header, "extern const efi_guid_t efi_guid_empty;\n"); } fprintf(header, "extern const efi_guid_t %s;\n", outbuf[i].symbol); } fprintf(header, "\n#endif /* EFIVAR_GUIDS_H */\n"); fprintf(symout, "#if defined(__linux__) && defined(__ELF__)\n.section .note.GNU-stack,\"\",%%progbits\n#endif"); fclose(header); fclose(symout); qsort(outbuf, line-1, sizeof (struct guidname), cmpguidp); rc = write(guidout, outbuf, sizeof (struct guidname) * (line - 1)); if (rc < 0) err(1, "makeguids"); qsort(outbuf, line-1, sizeof (struct guidname), cmpnamep); rc = write(nameout, outbuf, sizeof (struct guidname) * (line - 1)); if (rc < 0) err(1, "makeguids"); close(in); close(guidout); close(nameout); return 0; } efivar-0.21/src/test/000077500000000000000000000000001255101430600144535ustar00rootroot00000000000000efivar-0.21/src/test/.gitignore000066400000000000000000000000071255101430600164400ustar00rootroot00000000000000tester efivar-0.21/src/test/Makefile000066400000000000000000000007071255101430600161170ustar00rootroot00000000000000SRCDIR = $(realpath .) TOPDIR = $(realpath $(SRCDIR)/../..) include $(TOPDIR)/Make.defaults include $(TOPDIR)/Make.version ccldflags += -L$(TOPDIR)/src/ -Wl,-rpath=$(TOPDIR)/src/ LIBS=efivar all : tester install : clean : @rm -rfv tester *.o *.E *.S test : tester ./tester tester :: tester.o $(CC) $(cflags) $(LDFLAGS) -Wl,-rpath,$(TOPDIR)/src -L$(TOPDIR)/src -o $@ $^ -lefivar -ldl .PHONY: all clean install test include $(TOPDIR)/Make.rules efivar-0.21/src/test/tester.c000066400000000000000000000155641255101430600161400ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #define TEST_GUID EFI_GUID(0x84be9c3e,0x8a32,0x42c0,0x891c,0x4c,0xd3,0xb0,0x72,0xbe,0xcc) uint8_t * __attribute__((malloc)) __attribute__((alloc_size(1))) get_random_bytes(size_t size) { uint8_t *ret = NULL; int errno_saved = 0; int fd = -1; if (!size) return ret; uint8_t *retdata = malloc(size); if (!retdata) goto fail; fd = open("/dev/urandom", O_RDONLY); if (fd < 0) goto fail; int rc = read(fd, retdata, size); if (rc < 0) goto fail; ret = retdata; retdata = NULL; fail: errno_saved = errno; if (fd >= 0) close(fd); if (retdata) free(retdata); errno = errno_saved; return ret; } struct test { const char *name; size_t size; int result; }; static void print_error(int line, struct test *test, int rc, char *fmt, ...) __attribute__ ((format (printf, 4, 5))); static void print_error(int line, struct test *test, int rc, char *fmt, ...) { fprintf(stderr, "FAIL: \"%s\"(line %d) (%d) ", test->name, line, rc); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #define report_error(test, ret, rc, ...) ({ \ __typeof(errno) __errno_saved = errno; \ free(testdata); \ if (data) { \ free(data); \ data = NULL; \ } \ if (test->result != rc) { \ print_error(__LINE__, test, rc, __VA_ARGS__); \ ret = -1; \ errno = __errno_saved; \ goto fail; \ } \ errno = __errno_saved; \ }) int do_test(struct test *test) { int rc = -1; errno = 0; uint8_t *testdata = NULL; uint8_t *data = NULL; testdata = get_random_bytes(test->size); if (testdata == NULL && errno != 0) { perror(test->name); return -1; } int ret = 0; printf("testing efi_set_variable()\n"); rc = efi_set_variable(TEST_GUID, test->name, testdata, test->size, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE); if (rc < 0) { report_error(test, ret, rc, "set test failed: %m\n"); } size_t datasize = 0; uint32_t attributes = 0; printf("testing efi_get_variable_size()\n"); rc = efi_get_variable_size(TEST_GUID, test->name, &datasize); if (rc < 0) report_error(test, ret, rc, "get size test failed: %m\n"); if (datasize != test->size) report_error(test, ret, -1, "get size test failed: wrong size: %zd should be %zd\n", datasize, test->size); printf("testing efi_get_variable()\n"); rc = efi_get_variable(TEST_GUID, test->name, &data, &datasize, &attributes); if (rc < 0) report_error(test, ret, rc, "get test failed: %m\n"); if (datasize != test->size) report_error(test, ret, -1, "get size test failed: wrong size: %zd should be %zd\n", datasize, test->size); if (testdata != NULL && test->size > 0) if (memcmp(data, testdata, test->size)) report_error(test, ret, rc, "get test failed: bad data\n"); free(data); data = NULL; if (attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)) report_error(test, ret, rc, "get test failed: wrong attributes\n"); printf("testing efi_get_variable_attributes()\n"); rc = efi_get_variable_attributes(TEST_GUID, test->name, &attributes); if (rc < 0) report_error(test, ret, rc, "get attributes test failed: %m\n"); if (attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)) report_error(test, ret, rc, "get attributes test failed: wrong attributes\n"); printf("testing efi_del_variable()\n"); rc = efi_del_variable(TEST_GUID, test->name); if (rc < 0) report_error(test, ret, rc, "del test failed: %m\n"); printf("testing efi_set_variable() with too many arguments\n"); rc = efi_set_variable(TEST_GUID, test->name, testdata, test->size, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 0644, 1); if (rc < 0) { report_error(test, ret, -1, "set test failed: %m\n"); } rc = efi_set_variable(TEST_GUID, test->name, testdata, test->size, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE); if (rc < 0) { report_error(test, ret, rc, "set test failed: %m\n"); } printf("testing efi_append_variable()\n"); rc = efi_append_variable(TEST_GUID, test->name, testdata, test->size, EFI_VARIABLE_APPEND_WRITE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE); if (rc < 0) { report_error(test, ret, rc, "append test failed: %m\n"); } printf("testing efi_get_variable()\n"); rc = efi_get_variable(TEST_GUID, test->name, &data, &datasize, &attributes); if (rc < 0) report_error(test, ret, rc, "get test failed: %m\n"); if (datasize != test->size * 2) report_error(test, ret, -1, "get size test failed: wrong size: %zd should be %zd (append may be at fault)\n", datasize, test->size * 2); if (memcmp(data, testdata, test->size)) report_error(test, ret, rc, "get test failed: bad data\n"); if (memcmp(data + test->size, testdata, test->size)) report_error(test, ret, rc, "get test failed: bad data\n"); printf("testing efi_del_variable()\n"); rc = efi_del_variable(TEST_GUID, test->name); if (rc < 0 && test->size != 0) report_error(test, ret, rc, "del test failed: %m\n"); else ret = test->result; free(data); free(testdata); fail: if (ret != test->result) return -1; return 0; } int main(void) { if (!efi_variables_supported()) { printf("UEFI variables not supported on this machine.\n"); return 0; } struct test tests[] = { {.name= "empty", .size = 0, .result= -1}, {.name= "one", .size = 1, .result= 0 }, {.name= "two", .size = 2, .result= 0 }, {.name= "three", .size = 3, .result= 0 }, {.name= "four", .size = 4, .result= 0 }, {.name= "five", .size = 5, .result= 0 }, {.name= "seven", .size = 7, .result= 0 }, {.name= "eight", .size = 8, .result= 0 }, {.name= "nine", .size = 9, .result= 0 }, {.name= "fifteen", .size = 15, .result= 0 }, {.name= "sixteen", .size = 16, .result= 0 }, {.name= "seventeen", .size = 17, .result= 0 }, {.name= "thirtyone", .size = 31, .result= 0 }, {.name= "thirtytwo", .size = 32, .result= 0 }, {.name= "thirtythree", .size = 33, .result= 0 }, {.name= "tentwentyfour", .size = 1024, .result= 0}, {.name= "tentwentyfive", .size = 1025, .result= 0}, {.name= "", .size = 0, .result= 0} }; for (int x = 0; tests[x].name[0] != '\0'; x++) { efi_del_variable(TEST_GUID, tests[x].name); } int ret = 0; for (int x = 0; tests[x].name[0] != '\0'; x++) { printf("About to test %s\n", tests[x].name); int rc = do_test(&tests[x]); if (rc < 0) { efi_del_variable(TEST_GUID, tests[x].name); ret = 1; break; } } return ret; } efivar-0.21/src/ucs2.h000066400000000000000000000100551255101430600145220ustar00rootroot00000000000000#ifndef _EFIVAR_UCS2_H #define _EFIVAR_UCS2_H #define ev_bits(val, mask, shift) \ (((val) & ((mask) << (shift))) >> (shift)) static inline size_t __attribute__((__unused__)) ucs2len(const uint16_t * const s, ssize_t limit) { ssize_t i; for (i = 0; i < (limit >= 0 ? limit : i+1) && s[i] != L'\0'; i++) ; return i; } static inline size_t __attribute__((__unused__)) ucs2size(const uint16_t * const s, ssize_t limit) { size_t rc = ucs2len(s, limit); rc *= sizeof (uint16_t); rc += sizeof (uint16_t); if (limit > 0 && rc > (size_t)limit) return limit; return rc; } static inline size_t __attribute__((__unused__)) __attribute__((__nonnull__ (1))) utf8len(uint8_t *s, ssize_t limit) { ssize_t i, j; for (i = 0, j = 0; i < (limit >= 0 ? limit : i+1) && s[i] != '\0'; j++, i++) { if (!(s[i] & 0x80)) { ; } else if ((s[i] & 0xc0) == 0xc0 && !(s[i] & 0x20)) { i += 1; } else if ((s[i] & 0xe0) == 0xe0 && !(s[i] & 0x10)) { i += 2; } } return j; } static inline size_t __attribute__((__unused__)) __attribute__((__nonnull__ (1))) utf8size(uint8_t *s, ssize_t limit) { size_t ret = utf8len(s,limit); if (ret < (limit >= 0 ? (size_t)limit : ret+1)) ret++; return ret; } static inline unsigned char * __attribute__((__unused__)) ucs2_to_utf8(const uint16_t * const chars, ssize_t limit) { ssize_t i, j; unsigned char *ret; if (limit < 0) limit = ucs2len(chars, -1); ret = alloca(limit * 6 + 1); if (!ret) return NULL; memset(ret, 0, limit * 6 +1); for (i=0, j=0; chars[i] && i < (limit >= 0 ? limit : i+1); i++,j++) { if (chars[i] <= 0x7f) { ret[j] = chars[i]; } else if (chars[i] > 0x7f && chars[i] <= 0x7ff) { ret[j++] = 0xc0 | ev_bits(chars[i], 0x1f, 6); ret[j] = 0x80 | ev_bits(chars[i], 0x3f, 0); #if 1 } else if (chars[i] > 0x7ff) { ret[j++] = 0xe0 | ev_bits(chars[i], 0xf, 12); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 6); ret[j] = 0x80| ev_bits(chars[i], 0x3f, 0); } #else } else if (chars[i] > 0x7ff && chars[i] < 0x10000) { ret[j++] = 0xe0 | ev_bits(chars[i], 0xf, 12); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 6); ret[j] = 0x80| ev_bits(chars[i], 0x3f, 0); } else if (chars[i] > 0xffff && chars[i] < 0x200000) { ret[j++] = 0xf0 | ev_bits(chars[i], 0x7, 18); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 12); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 6); ret[j] = 0x80| ev_bits(chars[i], 0x3f, 0); } else if (chars[i] > 0x1fffff && chars[i] < 0x4000000) { ret[j++] = 0xf8 | ev_bits(chars[i], 0x3, 24); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 18); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 12); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 6); ret[j] = 0x80 | ev_bits(chars[i], 0x3f, 0); } else if (chars[i] > 0x3ffffff) { ret[j++] = 0xfc | ev_bits(chars[i], 0x1, 30); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 24); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 18); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 12); ret[j++] = 0x80 | ev_bits(chars[i], 0x3f, 6); ret[j] = 0x80 | ev_bits(chars[i], 0x3f, 0); } #endif } ret[j] = '\0'; return (unsigned char *)strdup((char *)ret); } static inline ssize_t __attribute__((__unused__)) __attribute__((__nonnull__ (4))) utf8_to_ucs2(uint16_t *ucs2, ssize_t size, int terminate, uint8_t *utf8) { ssize_t req; ssize_t i, j; if (!utf8 || (!ucs2 && size > 0)) { errno = EINVAL; return -1; } req = utf8len(utf8, -1) * sizeof (uint16_t); if (terminate && req > 0) req += 1; if (size == 0 || req <= 0) return req; if (size < req) { errno = ENOSPC; return -1; } for (i=0, j=0; i < (size >= 0 ? size : i+1) && utf8[i] != '\0'; j++) { uint32_t val = 0; if ((utf8[i] & 0xe0) == 0xe0 && !(utf8[i] & 0x10)) { val = ((utf8[i+0] & 0x0f) << 10) |((utf8[i+1] & 0x3f) << 6) |((utf8[i+2] & 0x3f) << 0); i += 3; } else if ((utf8[i] & 0xc0) == 0xc0 && !(utf8[i] & 0x20)) { val = ((utf8[i+0] & 0x1f) << 6) |((utf8[i+1] & 0x3f) << 0); i += 2; } else { val = utf8[i] & 0x7f; i += 1; } ucs2[j] = val; } if (terminate) ucs2[j++] = L'\0'; return j; }; #endif /* _EFIVAR_UCS2_H */ efivar-0.21/src/util.h000066400000000000000000000113271255101430600146260ustar00rootroot00000000000000/* * Copyright 2011-2014 Red Hat, Inc. * All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * * Author(s): Peter Jones */ #ifndef EFIVAR_UTIL_H #define EFIVAR_UTIL_H 1 #include #include #include #include #include #include #include #include static inline int __attribute__((unused)) read_file(int fd, uint8_t **buf, size_t *bufsize) { uint8_t *p; size_t size = 4096; size_t filesize = 0; ssize_t s = 0; uint8_t *newbuf; if (!(newbuf = calloc(size, sizeof (uint8_t)))) return -1; *buf = newbuf; do { p = *buf + filesize; /* size - filesize shouldn't exceed SSIZE_MAX because we're * only allocating 4096 bytes at a time and we're checking that * before doing so. */ s = read(fd, p, size - filesize); if (s < 0 && errno == EAGAIN) { continue; } else if (s < 0) { int saved_errno = errno; free(*buf); *buf = NULL; *bufsize = 0; errno = saved_errno; return -1; } filesize += s; /* only exit for empty reads */ if (s == 0) break; if (filesize >= size) { /* See if we're going to overrun and return an error * instead. */ if (size > (size_t)-1 - 4096) { free(*buf); *buf = NULL; *bufsize = 0; errno = ENOMEM; return -1; } newbuf = realloc(*buf, size + 4096); if (newbuf == NULL) { int saved_errno = errno; free(*buf); *buf = NULL; *bufsize = 0; errno = saved_errno; return -1; } *buf = newbuf; memset(*buf + size, '\0', 4096); size += 4096; } } while (1); newbuf = realloc(*buf, filesize+1); if (!newbuf) { free(*buf); *buf = NULL; return -1; } newbuf[filesize] = '\0'; *buf = newbuf; *bufsize = filesize+1; return 0; } static inline uint64_t __attribute__((unused)) lcm(uint64_t x, uint64_t y) { uint64_t m = x, n = y, o; while ((o = m % n)) { m = n; n = o; } return (x / n) * y; } /************************************************************ * get_sector_size * Requires: * - filedes is an open file descriptor, suitable for reading * Modifies: nothing * Returns: * sector size, or 512. ************************************************************/ static inline int __attribute__((unused)) get_sector_size(int filedes) { int rc, sector_size = 512; rc = ioctl(filedes, BLKSSZGET, §or_size); if (rc) sector_size = 512; return sector_size; } #define asprintfa(str, fmt, args...) \ ({ \ char *_tmp = NULL; \ int _rc; \ *(str) = NULL; \ _rc = asprintf((str), (fmt), ## args); \ if (_rc > 0) { \ _tmp = strdupa(*(str)); \ if (!_tmp) { \ _rc = -1; \ } else { \ free(*(str)); \ *(str) = _tmp; \ } \ } else { \ _rc = -1; \ } \ _rc; \ }) #define read_sysfs_file(buf, fmt, args...) \ ({ \ int _rc=-1; \ char *_pathname; \ uint8_t *_buf=NULL; \ size_t _bufsize=-1; \ int _saved_errno; \ \ *(buf) = NULL; \ _rc = asprintfa(&_pathname, (fmt), ## args); \ if (_rc >= 0) { \ int _fd; \ _fd = open(_pathname, O_RDONLY); \ _saved_errno = errno; \ _rc = -1; \ if (_fd >= 0) { \ _rc = read_file(_fd, &_buf, &_bufsize); \ _saved_errno = errno; \ close(_fd); \ errno = _saved_errno; \ } \ } \ if (_rc >= 0) { \ uint8_t *_buf2 = alloca(_bufsize); \ _saved_errno = errno; \ if (_buf2) { \ memcpy(_buf2, _buf, _bufsize); \ _rc = _bufsize; \ } \ free(_buf); \ *((uint8_t **)buf) = _buf2; \ errno = _saved_errno; \ } \ _rc; \ }) #define sysfs_readlink(linkbuf, fmt, args...) \ ({ \ char *_lb = alloca(PATH_MAX+1); \ char *_pn; \ int _rc; \ \ *(linkbuf) = NULL; \ _rc = asprintfa(&_pn, fmt, ## args); \ if (_rc >= 0) { \ ssize_t _linksz; \ _linksz = readlink(_pn, _lb, PATH_MAX); \ _rc = _linksz; \ if (_linksz >= 0) \ _lb[_linksz] = '\0'; \ *(linkbuf) = _lb; \ } \ _rc; \ }) #endif /* EFIVAR_UTIL_H */ efivar-0.21/src/vars.c000066400000000000000000000261741255101430600146250ustar00rootroot00000000000000/* * libefivar - library for the manipulation of EFI variables * Copyright 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "lib.h" #include "generics.h" #include "util.h" #define VARS_PATH "/sys/firmware/efi/vars/" typedef struct efi_kernel_variable_32_t { uint16_t VariableName[1024/sizeof(uint16_t)]; efi_guid_t VendorGuid; uint32_t DataSize; uint8_t Data[1024]; uint32_t Status; uint32_t Attributes; } __attribute__((packed)) efi_kernel_variable_32_t; typedef struct efi_kernel_variable_64_t { uint16_t VariableName[1024/sizeof(uint16_t)]; efi_guid_t VendorGuid; uint64_t DataSize; uint8_t Data[1024]; uint64_t Status; uint32_t Attributes; } __attribute__((packed)) efi_kernel_variable_64_t; static ssize_t get_file_data_size(int dfd, char *name) { char raw_var[NAME_MAX + 9]; memset(raw_var, '\0', sizeof (raw_var)); strncpy(raw_var, name, NAME_MAX); strcat(raw_var, "/raw_var"); int fd = openat(dfd, raw_var, O_RDONLY); if (fd < 0) return -1; char buf[4096]; ssize_t sz, total = 0; int tries = 5; while (1) { sz = read(fd, buf, 4096); if (sz < 0 && (errno == EAGAIN || errno == EINTR)) { if (tries--) continue; total = -1; break; } if (sz < 0) { int saved_errno = errno; close(fd); errno = saved_errno; return -1; } if (sz == 0) break; total += sz; } close(fd); return total; } /* * Determine which ABI the kernel has given us. * * We have two situations - before and after kernel's commit e33655a38. * Before hand, the situation is like: * 64-on-64 - 64-bit DataSize and status * 32-on-32 - 32-bit DataSize and status * 32-on-64 - 64-bit DataSize and status * * After it's like this if CONFIG_COMPAT is enabled: * 64-on-64 - 64-bit DataSize and status * 32-on-64 - 32-bit DataSize and status * 32-on-32 - 32-bit DataSize and status * * Is there a better way to figure this out? * Submit your patch here today! */ static int is_64bit(void) { static int sixtyfour_bit = -1; DIR *dir = NULL; int dfd = -1; int saved_errno; if (sixtyfour_bit != -1) return sixtyfour_bit; dir = opendir(VARS_PATH); if (!dir) goto err; dfd = dirfd(dir); if (dfd < 0) goto err; struct dirent entry; struct dirent *result = NULL; while (1) { int rc = readdir_r(dir, &entry, &result); if (rc != 0) break; if (result == NULL) break; if (!strcmp(entry.d_name, "..") || !strcmp(entry.d_name, ".")) continue; ssize_t size = get_file_data_size(dfd, entry.d_name); if (size < 0) { continue; } else if (size == 2084) { sixtyfour_bit = 1; } else { sixtyfour_bit = 0; } errno = 0; break; } if (sixtyfour_bit == -1) sixtyfour_bit = __SIZEOF_POINTER__ == 4 ? 0 : 1; err: saved_errno = errno; if (dir) closedir(dir); errno = saved_errno; return sixtyfour_bit; } static int get_size_from_file(const char *filename, size_t *retsize) { uint8_t *buf = NULL; size_t bufsize = -1; int errno_value; int ret = -1; int fd = open(filename, O_RDONLY); if (fd < 0) goto err; int rc = read_file(fd, &buf, &bufsize); if (rc < 0) goto err; long long size = strtoll((char *)buf, NULL, 0); if ((size == LLONG_MIN || size == LLONG_MAX) && errno == ERANGE) { *retsize = -1; } else if (size < 0) { *retsize = -1; } else { *retsize = (size_t)size; ret = 0; } err: errno_value = errno; if (fd >= 0) close(fd); if (buf != NULL) free(buf); errno = errno_value; return ret; } static int vars_probe(void) { /* If we can't tell if it's 64bit or not, this interface is no good. */ if (is_64bit() < 0) return 0; if (!access(VARS_PATH "new_var", F_OK)) return 1; return 0; } static int vars_get_variable_size(efi_guid_t guid, const char *name, size_t *size) { int errno_value; int ret = -1; char *path = NULL; int rc = asprintf(&path, VARS_PATH "%s-"GUID_FORMAT"/size", name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); if (rc < 0) goto err; size_t retsize = 0; rc = get_size_from_file(path, &retsize); if (rc >= 0) { ret = 0; *size = retsize; } err: errno_value = errno; if (path) free(path); errno = errno_value; return ret; } static int vars_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t *attributes) { int ret = -1; uint8_t *data; size_t data_size; uint32_t attribs; ret = efi_get_variable(guid, name, &data, &data_size, &attribs); if (ret < 0) return ret; *attributes = attribs; if (data) free(data); return ret; } static int vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes) { int errno_value; int ret = -1; uint8_t *buf = NULL; size_t bufsize = -1; char *path; int rc = asprintf(&path, VARS_PATH "%s-" GUID_FORMAT "/raw_var", name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); if (rc < 0) return -1; int fd = open(path, O_RDONLY); if (fd < 0) goto err; rc = read_file(fd, &buf, &bufsize); if (rc < 0) goto err; bufsize -= 1; /* read_file pads out 1 extra byte to NUL it */ if (is_64bit()) { efi_kernel_variable_64_t *var64; if (bufsize != sizeof(efi_kernel_variable_64_t)) { errno = EFBIG; goto err; } var64 = (void *)buf; *data = malloc(var64->DataSize); if (!*data) goto err; memcpy(*data, var64->Data, var64->DataSize); *data_size = var64->DataSize; *attributes = var64->Attributes; } else { efi_kernel_variable_32_t *var32; if (bufsize != sizeof(efi_kernel_variable_32_t)) { errno = EFBIG; goto err; } var32 = (void *)buf; *data = malloc(var32->DataSize); if (!*data) goto err; memcpy(*data, var32->Data, var32->DataSize); *data_size = var32->DataSize; *attributes = var32->Attributes; } ret = 0; err: errno_value = errno; if (buf) free(buf); if (fd >= 0) close(fd); if (path) free(path); errno = errno_value; return ret; } static int vars_del_variable(efi_guid_t guid, const char *name) { int errno_value; int ret = -1; char *path; int rc = asprintf(&path, VARS_PATH "%s-" GUID_FORMAT "/raw_var", name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); if (rc < 0) return -1; uint8_t *buf = NULL; size_t buf_size = 0; int fd = open(path, O_RDONLY); if (fd < 0) goto err; rc = read_file(fd, &buf, &buf_size); buf_size -= 1; /* read_file pads out 1 extra byte to NUL it */ if (rc < 0) goto err; if (buf_size != sizeof(efi_kernel_variable_64_t) && buf_size != sizeof(efi_kernel_variable_32_t)) { errno = EFBIG; goto err; } close(fd); fd = open(VARS_PATH "del_var", O_WRONLY); if (fd < 0) goto err; rc = write(fd, buf, buf_size); if (rc >= 0) ret = 0; err: errno_value = errno; if (buf) free(buf); if (fd >= 0) close(fd); if (path) free(path); errno = errno_value; return ret; } static int _vars_chmod_variable(char *path, mode_t mode) { mode_t mask = umask(umask(0)); size_t len = strlen(path); char c = path[len - 5]; path[len - 5] = '\0'; char *files[] = { "", "attributes", "data", "guid", "raw_var", "size", NULL }; int saved_errno = 0; int ret = 0; for (int i = 0; files[i] != NULL; i++) { char *new_path = NULL; int rc = asprintf(&new_path, "%s/%s", path, files[i]); if (rc > 0) { rc = chmod(new_path, mode & ~mask); if (rc < 0) { if (saved_errno == 0) saved_errno = errno; ret = -1; } free(new_path); } else if (ret < 0) { if (saved_errno == 0) saved_errno = errno; ret = -1; } } path[len - 5] = c; errno = saved_errno; return ret; } static int vars_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { if (strlen(name) > 1024) { errno = EINVAL; return -1; } char *path; int rc = asprintf(&path, VARS_PATH "%s-" GUID_FORMAT, name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); if (rc < 0) return -1; rc = _vars_chmod_variable(path, mode); int saved_errno = errno; free(path); errno = saved_errno; return rc; } static int vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) { int errno_value; size_t len; int ret = -1; if (strlen(name) > 1024) { errno = EINVAL; return -1; } if (data_size > 1024) { errno = ENOSPC; return -1; } char *path; int rc = asprintf(&path, VARS_PATH "%s-" GUID_FORMAT "/data", name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); if (rc < 0) return -1; len = rc; int fd = -1; if (!access(path, F_OK)) { rc = efi_del_variable(guid, name); if (rc < 0) goto err; } if (is_64bit()) { efi_kernel_variable_64_t var64 = { .VendorGuid = guid, .DataSize = data_size, .Status = 0, .Attributes = attributes }; for (int i = 0; name[i] != '\0'; i++) var64.VariableName[i] = name[i]; memcpy(var64.Data, data, data_size); fd = open(VARS_PATH "new_var", O_WRONLY); if (fd < 0) goto err; rc = write(fd, &var64, sizeof(var64)); } else { efi_kernel_variable_32_t var32 = { .VendorGuid = guid, .DataSize = data_size, .Status = 0, .Attributes = attributes }; for (int i = 0; name[i] != '\0'; i++) var32.VariableName[i] = name[i]; memcpy(var32.Data, data, data_size); fd = open(VARS_PATH "new_var", O_WRONLY); if (fd < 0) goto err; rc = write(fd, &var32, sizeof(var32)); } if (rc >= 0) ret = 0; /* this is inherently racy, but there's no way to do it correctly with * this kernel API. Fortunately, all directory contents get created * with root.root ownership and an effective umask of 177 */ path[len-5] = '\0'; _vars_chmod_variable(path, mode); err: errno_value = errno; if (path) free(path); if (fd >= 0) close(fd); errno = errno_value; return ret; } static int vars_get_next_variable_name(efi_guid_t **guid, char **name) { return generic_get_next_variable_name(VARS_PATH, guid, name); } struct efi_var_operations vars_ops = { .name = "vars", .probe = vars_probe, .set_variable = vars_set_variable, .del_variable = vars_del_variable, .get_variable = vars_get_variable, .get_variable_attributes = vars_get_variable_attributes, .get_variable_size = vars_get_variable_size, .get_next_variable_name = vars_get_next_variable_name, .chmod_variable = vars_chmod_variable, };