--- /dev/null
+Matt Domsch <Matt_Domsch@dell.com>
+- All .c and .h files
+
+
+Andreas Schwab <schwab@suse.de>
+- Patches to several .c and .h files
+
+Richard Hirst <rhirst@linuxcare.com>
+- Patch to efichar.c
+
+dann frazier <dannf@debian.org>
+- docbook of manpage
+- Patches to efibootmgr.c
+- network boot entry creation in efi.c
+
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Running 'make' builds the file src/efibootmgr/efibootmgr.
+efibootmgr should be placed into /usr/sbin/.
+
+
+
--- /dev/null
+ default: all
+
+ RELEASE_DATE := "04-Sep-2003"
+ RELEASE_MAJOR := 0
+ RELEASE_MINOR := 4
+ RELEASE_SUBLEVEL := 2
+ RELEASE_EXTRALEVEL :=
+ RELEASE_NAME := efibootmgr
+ RELEASE_STRING := $(RELEASE_NAME)-$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_SUBLEVEL)$(RELEASE_EXTRALEVEL)
+
+ CFLAGS += -DEFIBOOTMGR_VERSION=\"$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_SUBLEVEL)$(RELEASE_EXTRALEVEL)\" -Wall
+
+ MODULES := src
+
+ BINDIR := /usr/sbin
+
+#--------------------------------------------
+# Generic Makefile stuff is below. You
+# should not have to modify any of the stuff
+# below.
+#--------------------------------------------
+
+#Included makefiles will add their deps for each stage in these vars:
+ INSTALLDEPS :=
+ CLEANDEPS :=
+ ALLDEPS :=
+ CLEANLIST :=
+
+#Define the top-level build directory
+ BUILDDIR := $(shell pwd)
+
+#Include make rules from each submodule (subdirectory)
+ include $(patsubst %,%/module.mk,$(MODULES))
+
+ .PHONY: all clean install_list install install_link post_install tarball echotree default
+
+ all: $(ALLDEPS)
+ clean: clean_list $(CLEANDEPS)
+
+ clean_list:
+ rm -f $(CLEANLIST)
+
+ install_list: echotree $(INSTALLDEPS)
+
+ install: all
+ @make install_list | tools/install.pl copy
+
+ install_link: all
+ @make install_list | tools/install.pl link
+
+ post_install:
+
+ tarball: clean
+ -rm $(RELEASE_NAME)*.tar.gz
+ cp -a ../$(RELEASE_NAME) ../$(RELEASE_STRING)
+ find ../$(RELEASE_STRING) -name CVS -type d -depth -exec rm -rf \{\} \;
+ sync; sync; sync;
+ cd ..; tar cvzf $(RELEASE_STRING).tar.gz $(RELEASE_STRING)
+ mv ../$(RELEASE_STRING).tar.gz .
+ rm -rf ../$(RELEASE_STRING)
+
+
+#The rest of the docs...
+ doc_TARGETS += COPYING README INSTALL
+
+echotree:
+ @# making directory tree
+ @#RPM FORMAT:
+ @# %defattr(-, user, group)
+ @# %attr(4755,user,group) filename
+ @# filename
+
+# Here is a list of variables that are assumed Local to each Makefile. You can
+# safely stomp on these values without affecting the build.
+# MODULES
+# FILES
+# TARGETS
+# SOURCES
--- /dev/null
+This is efibootmgr, a Linux user-space application to modify the Intel
+Extensible Firmware Interface (EFI) Boot Manager. This application
+can create and destroy boot entries, change the boot order, change
+the next running boot option, and more.
+
+Details on the EFI Boot Manager are available from the EFI
+Specification, v1.02 or above, available from http://developer.intel.com.
+
+Note: efibootmgr requires that the kernel module efivars be loaded
+prior to use. 'modprobe efivars' should do the trick.
+
+usage: efibootmgr [options]
+ -a | --active sets bootnum active
+ -A | --inactive sets bootnum inactive
+ -b | --bootnum XXXX modify BootXXXX (hex)
+ -B | --delete-bootnum delete bootnum (hex)
+ -c | --create create new variable bootnum and add to bootorder
+ -d | --disk disk (defaults to /dev/sda) containing loader
+ -e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess
+ -E | --device num EDD 1.0 device number (defaults to 0x80)
+ -g | --gpt force disk w/ invalid PMBR to be treated as GPT
+ -H | --acpi_hid XXXX set the ACPI HID (used with -i)
+ -i | --iface name create a netboot entry for the named interface
+ -l | --loader name (defaults to \elilo.efi)
+ -L | --label label Boot manager display label (defaults to "Linux")
+ -n | --bootnext XXXX set BootNext to XXXX (hex)
+ -N | --delete-bootnext delete BootNext
+ -o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)
+ -O | --delete-bootorder delete BootOrder
+ -p | --part part (defaults to 1) containing loader
+ -q | --quiet be quiet
+ -t | --test filename don't write to NVRAM, write to filename
+ -u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)
+ -U | --acpi_uid XXXX set the ACPI UID (used with -i)
+ -v | --verbose print additional information
+ -V | --version return version and exit
+ -w | --write-signature write unique sig to MBR if needed
+
+
+Typical usage:
+1) Root can use it to display the current Boot Manager settings.
+ [root@localhost ~]# efibootmgr
+ BootCurrent: 0004
+ BootNext: 0003
+ BootOrder: 0004,0000,0001,0002,0003
+ Boot0000* Diskette Drive(device:0)
+ Boot0001* CD-ROM Drive(device:FF)
+ Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)
+ Boot0003* PXE Boot: MAC(00D0B7C15D91)
+ Boot0004* Linux
+
+ This shows:
+ BootCurrent - the boot entry used to start the currently running
+ system.
+
+ BootOrder - the boot order as would appear in the boot manager. The
+ boot manager tries to boot the first active entry on this list. If
+ unsuccessful, it tries the next entry, and so on.
+
+ BootNext - the boot entry which is scheduled to be run on next boot.
+ This superceeds BootOrder for one boot only, and is deleted by the
+ boot manager after first use. This allows you to change the next boot
+ behavior without changing BootOrder.
+
+ Five boot entries (0000 - 0004), the active/inactive flag (* means
+ active), and the name displayed on the screen.
+
+
+2) An OS installer would call 'efibootmgr -c'. This assumes that
+ /boot/efi is your EFI System Partition, and is mounted at /dev/sda1.
+ This creates a new boot option, called "Linux", and puts it at the top
+ of the boot order list. Options may be passed to modify the
+ default behavior. The default OS Loader is elilo.efi.
+
+3) A system administrator wants to change the boot order. She would
+ call 'efibootmgr -o 3,4' to specify PXE boot first, then Linux
+ boot.
+
+4) A system administrator wants to change the boot order for the next
+ boot only. She would call 'efibootmgr -n 4' to specify that the
+ Linux entry be taken on next boot.
+
+5) A system administrator wants to delete the Linux boot option from
+ the menu. 'efibootmgr -b 4 -B' deletes entry 4 and removes it
+ from BootOrder.
+
+6) A system administrator wants to create a boot option to network
+ boot (PXE). Unfortunately, this requires knowing a little more
+ information about your system than can be easily found by
+ efibootmgr, so you've got to pass additional information - the ACPI
+ HID and UID values. These can generally be found by using the EFI
+ Boot Manager (in the EFI environment) to create a network boot
+ entry, then using efibootmgr to print it verbosely. Here's one example:
+
+ Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \
+ ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0)
+
+ In this case, the ACPI HID is "0A0341d0" and the UID is "0".
+ For the zx2000 gigE, the HID is "222F" and the UID is "500".
+ For the rx2000 gigE, the HID is "0002" and the UID is "100".
+ You create the boot entry with:
+ 'efibootmgr -c -i eth0 -H 222F -U 500 -L netboot'
+
+Many other uses may be found.
+
+Please direct any bugs, features, patches, etc. to Matt Domsch
+<Matt_Domsch@dell.com>.
+
+
+
+
+
--- /dev/null
+* Thu Sep 04 2003 Matt Domsch <Matt_Domsch@dell.com>
+- released v0.4.2-test2 as v0.4.2 without additional changes.
+
+* Mon Aug 11 2003 Matt Domsch <Matt_Domsch@dell.com>
+- fixed unaligned access errors
+- removed extraneous printing of mac addr when creating netboot entries
+- sync docbook to README
+- whitespace cleanups
+
+* Thu Jul 31 2003 Matt Domsch <Matt_Domsch@dell.com>
+- Applied patch from Dann Frazier to enable creating netboot entries.
+- update AUTHORS with Dann's netboot contribution.
+- Until we can get the ACPI HID and UID programatically, make the user
+ pass them in when creating a netboot entry.
+- Add O_DIRECT support for reading the disk.
+- Fix unparse_hardware_path() for the PCI case - the device and function
+ values were printed in reverse order.
+- Fix the README file to reflect all the options that can be passed, and
+ add a new item for netboot entries.
+- whitespace cleanups
+
+* Fri Oct 25 2002 Matt Domsch <Matt_Domsch@dell.com>
+- trivial patch from Fabien Lebaillif - Delamare <fabien@quadric.com>
+ increases the length of the boot option description from 40 to 64 bytes.
+
+* Tue Oct 22 2002 Matt Domsch <Matt_Domsch@dell.com>
+- ran docbook2man on the man page Dann Frazier created
+- Added man page to spec file
+- Added patches from Dann Frazier
+ - Removes the requirement to be root to run efibootmgr. This lets
+ mortal users run efibootmgr to check the version, and see the
+ --help output. It should also allow efibootmgr to work under
+ security systems without the strict root/non-root dichotomy.
+ - Checks to see if a boot option was specified when a boot option
+ deletion was requested.
+- Released version 0.4.1
+
+* Sun Jul 21 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Added kernel_has_blkgetsize64() test, now uses BLKGETSIZE64 if on a
+ known-good kernel. This is important when the Large Block Device (64-bit
+ block address) patch gets merged into the 2.5 kernel.
+
+* Wed May 1 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Released version 0.4.0
+
+* Tue Apr 30 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Added some printfs to compare_gpts().
+
+* Mon Apr 08 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Make sure partition number arg is in the GPT disk.
+- Added a few more _FILE_OFFSET_BITS defines where needed
+
+* Fri Apr 05 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Added syncs to make tarball target so NFS is current and CVS dirs get
+ deleted before the tarball is made.
+- Added a few __leXX_to_cpu() calls in code currently commented out in gpt.c
+
+* Tue Apr 02 2002 Matt Domsch <Matt_Domsch@dell.com>
+- finished conversion to GPT code
+
+* Sat Mar 30 2002 Matt Domsch <Matt_Domsch@dell.com>
+- began conversion to GPT code in post-2.4.18 and post-2.5.7 kernels.
+- added manpage contributed by dannf@fc.hp.com
+
+* Mon Feb 11 2002 Matt Domsch <Matt_Domsch@dell.com>
+- BLKGETSIZE64 is fixed in 2.4.18-pre8 and 2.5.4-pre3. Wait a bit longer
+before using though.
+- added list_for_each_safe() routine. It's needed in the boot
+var deletion routine, though it was already breaking out once found.
+- changed struct list_head to list_t
+- released v0.4.0-test4
+
+* Fri Jan 18 2002 Matt Domsch <Matt_Domsch@dell.com>
+- commented out BLKGETSIZE64 ioctl use for now. Kernels 2.4.15-2.4.18 and
+ 2.5.0-2.5.3 don't return the right value.
+
+* Thu Jan 3 2002 Matt Domsch <Matt_Domsch@dell.com>
+- added back in read last sector IOCTL hack, but only after read() fails.
+- released v0.4.0-test4
+
+* Thu Jan 3 2002 Matt Domsch <Matt_Domsch@dell.com>
+- more cleanups
+- released v0.4.0-test3
+
+* Wed Jan 2 2002 Matt Domsch <Matt_Domsch@dell.com>
+- Changed PROC_DIR_EFI to PROC_DIR_EFI_VARS
+- write_variable() now searches /proc/efi/vars for a variable that's not
+ the one being written. The EFI 1.1 sample implementation changed the
+ name of the "victim" being written to (was Efi-xxxxx, now EFI-xxxxx), so
+ previous versions of efibootmgr don't work with the new firmware. This
+ should fix that up.
+- released v0.4.0-test2
+
+* Fri Dec 7 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Removed read last sector ioctl hack, it's not needed anymore. The
+ kernel takes care of it for us with a new patch.
+- Added test for valid PMBR, similar to parted and the kernel.
+- Added test for returning size of block device as a u64.
+- Added test for returning sector size as int, and use that.
+- Changed GPT struct and member names to be more Linux-like.
+- added -g option to force disk with invalid PMBR to be treated as GPT anyhow.
+- released v0.4.0-test1
+
+* Thu Aug 9 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Added some uniqueness to the MBR signature.
+- removed ExclusiveArch from spec file
+- released v0.3.4
+
+* Mon Aug 6 2001 Matt Domsch <Matt_Domsch@dell.com>
+- applied patch from Richard Hirst <rhirst@linuxcare.com> to fix
+ efichar_char_strcmp().
+
+
+* Fri Aug 3 2001 Matt Domsch <Matt_Domsch@dell.com>
+- By request, warn when creating a new boot entry with the same name
+ as another boot entry.
+- released v0.3.3
+
+* Mon Jul 30 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Added test for non-zero signature on MBR-style disks,
+ and new -w flag to write a unique signature to the disk if so.
+- released v0.3.3-test4
+- Fixed counting of optional data length (extra args)
+- released v0.3.3-test5
+
+* Fri Jul 27 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Added test for running as root
+- released v0.3.3-test3
+
+* Thu Jul 26 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Unparse extra args being passed to bootloader too.
+- released v0.3.3-test2
+
+* Wed Jul 25 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Added -u option to pass extra args to the bootloader in unicode
+ (default is to pass in ASCII)
+- Added -t option to allow writing to a file (for testing)
+- released v0.3.3-test1
+
+* Tue May 22 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Applied patch from Andreas Schwab. remove_from_boot_order() called
+ read_boot_order() without checking the return status.
+- Changed README to remove os loader args comment
+- Changed efi_status_t to be unsigned long (not uint64_t) as per EFI
+ spec. This allows efibootmgr to be recompiled as a 32-bit or 64-bit app
+ depending on its running on 32-bit or 64-bit Linux. Note: this changes
+ the size of the structure returned in /proc/efi/vars to match the kernel
+ implementation. 32-bit efibootmgr won't work on 64-bit Linux and vice versa.
+- release v0.3.2
+
+* Fri May 18 2001 Matt Domsch <Matt_Domsch@dell.com>
+- changed usage() to *not* let you think you can pass args to the OS
+ loader
+- release v0.3.1
+
+* Fri May 18 2001 Matt Domsch <Matt_Domsch@dell.com>
+- Padded HARDDRIVE_DEVICE_PATH out to please EFI Boot Manager.
+- Incorporated patches from Andreas Schwab
+ - replace __u{8,16,32,64} with uint{8,16,32,64}_t
+ - use _FILE_OFFSET_BITS
+ - fix a segfault
+- release v0.3.0
+
+* Tue May 15 2001 Matt Domsch <Matt_Domsch@dell.com>
+- initial external release v0.2.0
--- /dev/null
+* MS-DOS style extended partitions
--- /dev/null
+Summary: EFI Boot Manager
+Name: efibootmgr
+Version: 0.4.1
+Release: 0
+Group: System Environment/Base
+Copyright: GPL
+Vendor: Dell Computer Corporation www.dell.com
+Packager: Matt Domsch <Matt_Domsch@dell.com>
+
+
+Source0: http://domsch.com/linux/ia64/efibootmgr/efibootmgr-%{version}.tar.gz
+
+%description
+efibootmgr displays and allows the user to edit the Intel Extensible
+Firmware Interface (EFI) Boot Manager variables. Additional
+information about EFI can be found at
+http://developer.intel.com/technology/efi/efi.htm.
+
+%prep
+%setup
+%build
+make
+%install
+install --group=root --owner=root --mode 555 src/efibootmgr/efibootmgr $RPM_BUILD_ROOT/usr/sbin
+install --group=root --owner=root --mode 444 src/man/man8/efibootmgr.8 $RPM_BUILD_ROOT/usr/share/man/man8
+
+%files
+/usr/sbin/efibootmgr
+/usr/share/man/man8/efibootmgr.8
+%doc README
+%doc INSTALL
+
+
+%changelog
+* Fri May 18 2001 Matt Domsch <Matt_Domsch@dell.com>
+- See doc/ChangeLog
--- /dev/null
+ %attr(0755,root,root) /usr/sbin
+ %attr(0755,root,root) /usr/sbin/efibootmgr
+ %attr(0444,root,root) /usr/share/man/man8/efibootmgr.8
--- /dev/null
+%:
+ +make -C ../ $*
--- /dev/null
+%:
+ +make -C ../ $*
--- /dev/null
+/*
+ efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+
+
+ This must tie the EFI_DEVICE_PATH to /boot/efi/elilo.efi
+ The EFI_DEVICE_PATH will look something like:
+ ACPI device path, length 12 bytes
+ Hardware Device Path, PCI, length 6 bytes
+ Messaging Device Path, SCSI, length 8 bytes, or ATAPI, length ??
+ Media Device Path, Hard Drive, partition XX, length 30 bytes
+ Media Device Path, File Path, length ??
+ End of Hardware Device Path, length 4
+ Arguments passed to elilo, as UCS-2 characters, length ??
+
+*/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "list.h"
+#include "efi.h"
+#include "efichar.h"
+#include "unparse_path.h"
+#include "disk.h"
+#include "efibootmgr.h"
+
+#ifndef EFIBOOTMGR_VERSION
+#define EFIBOOTMGR_VERSION "unknown (fix Makefile!)"
+#endif
+
+
+typedef struct _var_entry {
+ struct dirent *name;
+ uint16_t num;
+ efi_variable_t var_data;
+ list_t list;
+} var_entry_t;
+
+
+/* global variables */
+static LIST_HEAD(boot_entry_list);
+static LIST_HEAD(blk_list);
+efibootmgr_opt_t opts;
+
+static inline void
+var_num_from_name(const char *pattern, char *name, uint16_t *num)
+{
+ sscanf(name, pattern, num);
+}
+
+static int
+select_boot_var_names(const struct dirent *d)
+{
+ int num, rc;
+ rc = sscanf(d->d_name, "Boot0%03x-%*s", &num);
+ return rc;
+}
+
+#if 0
+static int
+select_blk_var_names(const struct dirent *d)
+{
+ int num;
+ return sscanf(d->d_name, "blk%x-%*s", &num);
+}
+#endif
+
+static int
+read_boot_var_names(struct dirent ***namelist)
+{
+ int n;
+ n = scandir(PROC_DIR_EFI_VARS, namelist, select_boot_var_names, alphasort);
+ if (n < 0) {
+ perror("scandir " PROC_DIR_EFI_VARS);
+ fprintf(stderr, "You must 'modprobe efivars' before running efibootmgr.\n");
+ }
+ return n;
+}
+
+#if 0
+static int
+read_blk_var_names(struct dirent ***namelist)
+{
+ int n;
+ n = scandir(PROC_DIR_EFI_VARS, namelist, select_blk_var_names, alphasort);
+ if (n < 0)
+ perror("scandir");
+ return n;
+}
+
+static int
+dirent_list_length(struct dirent **namelist)
+{
+ int i;
+ if (!namelist) return 0;
+ for (i=0; namelist[i]; i++);
+ return i;
+}
+#endif
+
+static void
+read_vars(struct dirent **namelist,
+ int num_boot_names,
+ list_t *head)
+{
+ efi_status_t status;
+ var_entry_t *entry;
+ int i;
+
+ if (!namelist) return;
+
+ for (i=0; i < num_boot_names; i++)
+ {
+ if (namelist[i]) {
+ entry = malloc(sizeof(var_entry_t));
+ if (!entry) return;
+ memset(entry, 0, sizeof(var_entry_t));
+
+ status = read_variable(namelist[i]->d_name,
+ &entry->var_data);
+ if (status != EFI_SUCCESS) break;
+ entry->name = namelist[i];
+ list_add_tail(&entry->list, head);
+ }
+ }
+ return;
+}
+
+
+
+
+
+static void
+free_dirents(struct dirent **ptr, int num_dirents)
+{
+ int i;
+ if (!ptr) return;
+ for (i=0; i < num_dirents; i++) {
+ if (ptr[i]) {
+ free(ptr[i]);
+ ptr[i] = NULL;
+ }
+ }
+ free(ptr);
+}
+
+
+
+static int
+compare(const void *a, const void *b)
+{
+ int rc = -1;
+ uint32_t n1, n2;
+ memcpy(&n1, a, sizeof(n1));
+ memcpy(&n2, b, sizeof(n2));
+ if (n1 < n2) rc = -1;
+ if (n1 == n2) rc = 0;
+ if (n2 > n2) rc = 1;
+ return rc;
+}
+
+
+/*
+ Return an available boot variable number,
+ or -1 on failure.
+*/
+static int
+find_free_boot_var(list_t *boot_list)
+{
+ int num_vars=0, i=0, found;
+ uint16_t *vars, free_number;
+ list_t *pos;
+ var_entry_t *boot;
+ list_for_each(pos, boot_list) {
+ num_vars++;
+ }
+ vars = malloc(sizeof(uint16_t) * num_vars);
+ if (!vars) return -1;
+ memset(vars, 0, sizeof(uint16_t) * num_vars);
+
+ list_for_each(pos, boot_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ vars[i] = boot->num;
+ i++;
+ }
+ qsort(vars, i, sizeof(uint16_t), compare);
+ found = 1;
+
+ num_vars = i;
+ for (free_number = 0; free_number < num_vars && found; free_number++) {
+ found = 0;
+ list_for_each(pos, boot_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ if (boot->num == free_number) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) break;
+ }
+ if (found && num_vars) free_number = vars[num_vars-1] + 1;
+ free(vars);
+ return free_number;
+}
+
+
+static void
+warn_duplicate_name(list_t *boot_list)
+{
+ list_t *pos;
+ var_entry_t *boot;
+ EFI_LOAD_OPTION *load_option;
+
+ list_for_each(pos, boot_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ load_option = (EFI_LOAD_OPTION *)
+ boot->var_data.Data;
+ if (!efichar_char_strcmp(opts.label,
+ load_option->description)) {
+ fprintf(stderr, "** Warning ** : Boot%04x has same label %s\n",
+ boot->num,
+ opts.label);
+ }
+ }
+}
+
+
+static var_entry_t *
+make_boot_var(list_t *boot_list)
+{
+ var_entry_t *boot;
+ int free_number;
+
+ if (opts.bootnum == -1) free_number = find_free_boot_var(boot_list);
+ else free_number = opts.bootnum;
+
+ if (free_number == -1) return NULL;
+
+ /* Create a new var_entry_t object
+ and populate it.
+ */
+
+ boot = malloc(sizeof(*boot));
+ if (!boot) return NULL;
+ memset(boot, 0, sizeof(*boot));
+ boot->num = free_number;
+ if (!make_linux_efi_variable(&boot->var_data, free_number)) {
+ free(boot);
+ return NULL;
+ }
+ write_variable(&boot->var_data);
+ list_add_tail(&boot->list, boot_list);
+ return boot;
+}
+
+static efi_status_t
+read_boot_order(efi_variable_t *boot_order)
+{
+ efi_status_t status;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char boot_order_name[80], text_uuid[40];
+ efi_guid_unparse(&guid, text_uuid);
+
+ memset(boot_order, 0, sizeof(*boot_order));
+ sprintf(boot_order_name, "BootOrder-%s", text_uuid);
+
+ status = read_variable(boot_order_name, boot_order);
+ if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
+ return status;
+
+ if (status == EFI_NOT_FOUND) {
+ /* Create it */
+ efichar_from_char(boot_order->VariableName, "BootOrder",
+ 1024);
+ memcpy(&boot_order->VendorGuid, &guid, sizeof(guid));
+ boot_order->Attributes = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS;
+ return status;
+ }
+ return EFI_SUCCESS;
+}
+
+
+
+
+static efi_status_t
+add_to_boot_order(uint16_t num)
+{
+ efi_status_t status;
+ efi_variable_t boot_order;
+ uint64_t new_data_size;
+ uint16_t *new_data, *old_data;
+
+ status = read_boot_order(&boot_order);
+ if (status != EFI_SUCCESS) return status;
+
+ /* We've now got an array (in boot_order.Data) of the
+ boot order. First add our entry, then copy the old array.
+ */
+ old_data = (uint16_t *)&(boot_order.Data);
+ new_data_size = boot_order.DataSize + sizeof(uint16_t);
+ new_data = malloc(new_data_size);
+
+ new_data[0] = num;
+ memcpy(new_data+1, old_data, boot_order.DataSize);
+
+ /* Now new_data has what we need */
+ memcpy(&(boot_order.Data), new_data, new_data_size);
+ boot_order.DataSize = new_data_size;
+ return write_variable(&boot_order);
+}
+
+
+static efi_status_t
+remove_from_boot_order(uint16_t num)
+{
+ efi_status_t status;
+ efi_variable_t boot_order;
+ uint64_t new_data_size;
+ uint16_t *new_data, *old_data;
+ int old_i,new_i;
+
+ status = read_boot_order(&boot_order);
+ if (status != EFI_SUCCESS) return status;
+
+ /* If it's empty, yea! */
+ if (!boot_order.DataSize) return EFI_SUCCESS;
+
+ /* We've now got an array (in boot_order.Data) of the
+ boot order. Simply copy the array, skipping the
+ entry we're deleting.
+ */
+ old_data = (uint16_t *)&(boot_order.Data);
+ /* Start with the same size */
+ new_data_size = boot_order.DataSize;
+ new_data = malloc(new_data_size);
+ for (old_i=0,new_i=0;
+ old_i < boot_order.DataSize / sizeof(uint16_t);
+ old_i++) {
+ if (old_data[old_i] != num) {
+ /* Copy this value */
+ new_data[new_i] = old_data[old_i];
+ new_i++;
+ }
+ }
+
+ /* Now new_data has what we need */
+ new_data_size = new_i * sizeof(uint16_t);
+ memset(&(boot_order.Data), 0, boot_order.DataSize);
+ memcpy(&(boot_order.Data), new_data, new_data_size);
+ boot_order.DataSize = new_data_size;
+
+ return write_variable(&boot_order);
+}
+
+static int
+read_boot_current()
+{
+ efi_status_t status;
+ efi_variable_t boot_next;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char boot_next_name[80], text_uuid[40];
+ uint16_t *n = (uint16_t *)(boot_next.Data);
+
+ efi_guid_unparse(&guid, text_uuid);
+
+ memset(&boot_next, 0, sizeof(boot_next));
+ sprintf(boot_next_name, "BootCurrent-%s", text_uuid);
+
+ status = read_variable(boot_next_name, &boot_next);
+ if (status) return -1;
+
+ return *n;
+}
+
+static int
+read_boot_next()
+{
+ efi_status_t status;
+ efi_variable_t boot_next;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char boot_next_name[80], text_uuid[40];
+ uint16_t *n = (uint16_t *)(boot_next.Data);
+
+ efi_guid_unparse(&guid, text_uuid);
+
+ memset(&boot_next, 0, sizeof(boot_next));
+ sprintf(boot_next_name, "BootNext-%s", text_uuid);
+
+ status = read_variable(boot_next_name, &boot_next);
+ if (status) return -1;
+
+ return *n;
+}
+
+
+static efi_status_t
+set_boot_next(uint16_t num)
+{
+ efi_variable_t var;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ uint16_t *n = (uint16_t *)var.Data;
+
+ memset(&var, 0, sizeof(var));
+
+ efichar_from_char(var.VariableName, "BootNext",
+ 1024);
+ memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ *n = num;
+ var.DataSize = sizeof(uint16_t);
+ var.Attributes = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS;
+ return write_variable(&var);
+}
+
+static efi_status_t
+delete_boot_next()
+{
+ efi_variable_t var;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+
+ memset(&var, 0, sizeof(var));
+
+ efichar_from_char(var.VariableName, "BootNext",
+ 1024);
+ memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ return write_variable(&var);
+}
+
+
+static efi_status_t
+delete_boot_var(uint16_t num)
+{
+ efi_status_t status;
+ efi_variable_t var;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char name[80];
+ list_t *pos, *n;
+ var_entry_t *boot;
+ sprintf(name, "Boot%04x", num);
+
+ memset(&var, 0, sizeof(var));
+
+ efichar_from_char(var.VariableName, name, 1024);
+ memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ status = write_variable(&var);
+
+ if (status) return status;
+
+ list_for_each_safe(pos, n, &boot_entry_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ if (boot->num == num) {
+ status = remove_from_boot_order(num);
+ if (status) return status;
+ list_del(&(boot->list));
+ break; /* short-circuit since it was found */
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+static void
+set_var_nums(const char *pattern, list_t *list)
+{
+ list_t *pos;
+ var_entry_t *var;
+ int num=0, rc;
+
+ list_for_each(pos, list) {
+ var = list_entry(pos, var_entry_t, list);
+ rc = sscanf(var->name->d_name, pattern, &num);
+ if (rc == 1) var->num = num;
+ }
+}
+
+#if 0
+static efi_variable_t *
+find_pci_scsi_disk_blk(int fd, int bus, int device, int func,
+ list_t *blk_list)
+{
+ list_t *pos;
+ int rc;
+ Scsi_Idlun idlun;
+ unsigned char host, channel, id, lun;
+ var_entry_t *blk;
+ efi_variable_t *blk_var;
+ long size = 0;
+
+ memset(&idlun, 0, sizeof(idlun));
+ rc = get_scsi_idlun(fd, &idlun);
+ if (rc) return NULL;
+
+ rc = disk_get_size(fd, &size);
+
+ idlun_to_components(&idlun, &host, &channel, &id, &lun);
+
+ list_for_each(pos, blk_list) {
+ blk = list_entry(pos, var_entry_t, list);
+ blk_var = blk->var_data;
+
+ if (!compare_pci_scsi_disk_blk(blk_var,
+ bus, device, func,
+ host, channel, id, lun,
+ 0, size)) {
+ return blk_var;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+/* The right blkX variable contains:
+ 1) the PCI and SCSI information for the disk passed in disk_name
+ 2) Does not contain a partition field
+*/
+
+
+static efi_variable_t *
+find_disk_blk(char *disk_name, list_t *blk_list)
+{
+ efi_variable_t *disk_blk = NULL;
+ int fd, rc;
+ unsigned char bus=0,device=0,func=0;
+ int interface_type=interface_type_unknown;
+ unsigned int controllernum=0, disknum=0;
+ unsigned char part=0;
+
+ fd = open(disk_name, O_RDONLY|O_DIRECT);
+ rc = disk_get_pci(fd, &bus, &device, &func);
+ if (rc) {
+ fprintf(stderr, "disk_get_pci() failed.\n");
+ return NULL;
+ }
+ rc = disk_info_from_fd(fd,
+ &interface_type,
+ &controllernum,
+ &disknum,
+ &part);
+ if (rc) {
+ fprintf(stderr, "disk_info_from_fd() failed.\n");
+ return NULL;
+ }
+ switch (interface_type)
+ {
+ case scsi:
+ return find_pci_scsi_disk_blk(fd,bus,device,func,blk_list);
+ break;
+ case ata:
+ return find_pci_ata_disk_blk(fd,bus,device,func,blk_list);
+ break;
+ case i2o:
+ return find_pci_i2o_disk_blk(fd,bus,device,func,blk_list);
+ break;
+ case md:
+ return find_pci_md_disk_blk(fd,bus,device,func,blk_list);
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+#endif
+
+static void
+unparse_boot_order(uint16_t *order, int length)
+{
+ int i;
+ printf("BootOrder: ");
+ for (i=0; i<length; i++) {
+ printf("%04x", order[i]);
+ if (i < (length-1))
+ printf(",");
+ }
+ printf("\n");
+}
+
+static int
+parse_boot_order(char *buffer, uint16_t *order, int length)
+{
+ int i;
+ int num, rc;
+
+ for (i=0; i<length && *buffer; i++) {
+ rc = sscanf(buffer, "%x", &num);
+ if (rc == 1) order[i] = num & 0xFFFF;
+ /* Advance to the comma */
+ while (*buffer && *buffer != ',') buffer++;
+ /* Advance through the comma(s) */
+ while (*buffer && *buffer == ',') buffer++;
+ }
+ return i;
+}
+
+static efi_status_t
+set_boot_order()
+{
+ efi_variable_t var;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ uint16_t *n = (uint16_t *)var.Data;
+
+ if (!opts.bootorder) return EFI_SUCCESS;
+
+ memset(&var, 0, sizeof(var));
+
+ efichar_from_char(var.VariableName, "BootOrder",
+ 1024);
+ memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ var.Attributes = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ var.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
+ return write_variable(&var);
+}
+
+static void
+show_boot_vars()
+{
+ list_t *pos;
+ var_entry_t *boot;
+ char description[80];
+ EFI_LOAD_OPTION *load_option;
+ EFI_DEVICE_PATH *path;
+ char text_path[1024], *p;
+ unsigned long optional_data_len=0;
+
+ list_for_each(pos, &boot_entry_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ load_option = (EFI_LOAD_OPTION *)
+ boot->var_data.Data;
+ efichar_to_char(description,
+ load_option->description, sizeof(description));
+ memset(text_path, 0, sizeof(text_path));
+ path = load_option_path(load_option);
+ printf("Boot%04x", boot->num);
+ if (load_option->attributes & LOAD_OPTION_ACTIVE)
+ printf("* ");
+ else printf(" ");
+ printf("%s", description);
+
+ if (opts.verbose) {
+ unparse_path(text_path, path,
+ load_option->file_path_list_length);
+ /* Print optional data */
+ optional_data_len =
+ boot->var_data.DataSize -
+ load_option->file_path_list_length -
+ ((char *)path - (char *)load_option);
+ if (optional_data_len) {
+ p = text_path;
+ p += strlen(text_path);
+ unparse_raw_text(p, ((uint8_t *)path) +
+ load_option->file_path_list_length,
+ optional_data_len);
+ }
+
+ printf("\t%s", text_path);
+ }
+ printf("\n");
+ }
+}
+
+
+
+static void
+show_boot_order()
+{
+ efi_status_t status;
+ efi_variable_t boot_order;
+ uint16_t *data;
+
+ status = read_boot_order(&boot_order);
+
+ if (status != EFI_SUCCESS) {
+ perror("show_boot_order()");
+ return;
+ }
+
+ /* We've now got an array (in boot_order.Data) of the
+ boot order. First add our entry, then copy the old array.
+ */
+ data = (uint16_t *)&(boot_order.Data);
+ if (boot_order.DataSize)
+ unparse_boot_order(data, boot_order.DataSize / sizeof(uint16_t));
+
+}
+
+static efi_status_t
+set_active_state()
+{
+ list_t *pos;
+ var_entry_t *boot;
+ EFI_LOAD_OPTION *load_option;
+
+ list_for_each(pos, &boot_entry_list) {
+ boot = list_entry(pos, var_entry_t, list);
+ load_option = (EFI_LOAD_OPTION *)
+ boot->var_data.Data;
+ if (boot->num == opts.bootnum) {
+ if (opts.active == 1) {
+ if (load_option->attributes
+ & LOAD_OPTION_ACTIVE) return EFI_SUCCESS;
+ else {
+ load_option->attributes
+ |= LOAD_OPTION_ACTIVE;
+ return write_variable(&boot->var_data);
+ }
+ }
+ else if (opts.active == 0) {
+ if (!(load_option->attributes
+ & LOAD_OPTION_ACTIVE))
+ return EFI_SUCCESS;
+ else {
+ load_option->attributes
+ &= ~LOAD_OPTION_ACTIVE;
+ return write_variable(&boot->var_data);
+ }
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+
+static efi_status_t
+delete_boot_order()
+{
+ efi_variable_t var;
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+
+ memset(&var, 0, sizeof(var));
+
+ efichar_from_char(var.VariableName, "BootOrder",
+ 1024);
+ memcpy(&var.VendorGuid, &guid, sizeof(guid));
+ return write_variable(&var);
+}
+
+
+static void
+usage()
+{
+ printf("efibootmgr version %s\n", EFIBOOTMGR_VERSION);
+ printf("usage: efibootmgr [options]\n");
+ printf("\t-a | --active sets bootnum active\n");
+ printf("\t-A | --inactive sets bootnum inactive\n");
+ printf("\t-b | --bootnum XXXX modify BootXXXX (hex)\n");
+ printf("\t-B | --delete-bootnum delete bootnum (hex)\n");
+ printf("\t-c | --create create new variable bootnum and add to bootorder\n");
+ printf("\t-d | --disk disk (defaults to /dev/sda) containing loader\n");
+ printf("\t-e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess\n");
+ printf("\t-E | --device num EDD 1.0 device number (defaults to 0x80)\n");
+ printf("\t-g | --gpt force disk with invalid PMBR to be treated as GPT\n");
+ printf("\t-H | --acpi_hid XXXX set the ACPI HID (used with -i)\n");
+ printf("\t-i | --iface name create a netboot entry for the named interface\n");
+ printf("\t-l | --loader name (defaults to \\elilo.efi)\n");
+ printf("\t-L | --label label Boot manager display label (defaults to \"Linux\")\n");
+ printf("\t-n | --bootnext XXXX set BootNext to XXXX (hex)\n");
+ printf("\t-N | --delete-bootnext delete BootNext\n");
+ printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)\n");
+ printf("\t-O | --delete-bootorder delete BootOrder\n");
+ printf("\t-p | --part part (defaults to 1) containing loader\n");
+ printf("\t-q | --quiet be quiet\n");
+ printf("\t-t | --test filename don't write to NVRAM, write to filename.\n");
+ printf("\t-u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)\n");
+ printf("\t-U | --acpi_uid XXXX set the ACPI UID (used with -i)\n");
+ printf("\t-v | --verbose print additional information\n");
+ printf("\t-V | --version return version and exit\n");
+ printf("\t-w | --write-signature write unique sig to MBR if needed\n");
+}
+
+static void
+set_default_opts()
+{
+ memset(&opts, 0, sizeof(opts));
+ opts.bootnum = -1; /* auto-detect */
+ opts.bootnext = -1; /* Don't set it */
+ opts.active = -1; /* Don't set it */
+ opts.edd10_devicenum = 0x80;
+ opts.loader = "\\elilo.efi";
+ opts.label = "Linux";
+ opts.disk = "/dev/sda";
+ opts.iface = NULL;
+ opts.part = 1;
+ opts.acpi_hid = -1;
+ opts.acpi_uid = -1;
+}
+
+static void
+parse_opts(int argc, char **argv)
+{
+ int c, num, rc;
+ int option_index = 0;
+
+ while (1)
+ {
+ static struct option long_options[] =
+ /* name, has_arg, flag, val */
+ {
+ {"active", no_argument, 0, 'a'},
+ {"inactive", no_argument, 0, 'A'},
+ {"bootnum", required_argument, 0, 'b'},
+ {"delete-bootnum", no_argument, 0, 'B'},
+ {"create", no_argument, 0, 'c'},
+ {"disk", required_argument, 0, 'd'},
+ {"iface", required_argument, 0, 'i'},
+ {"acpi_hid", required_argument, 0, 'H' },
+ {"edd-device", required_argument, 0, 'E'},
+ {"edd30", required_argument, 0, 'e'},
+ {"gpt", no_argument, 0, 'g'},
+ {"loader", required_argument, 0, 'l'},
+ {"label", required_argument, 0, 'L'},
+ {"bootnext", required_argument, 0, 'n'},
+ {"delete-bootnext", no_argument, 0, 'N'},
+ {"bootorder", required_argument, 0, 'o'},
+ {"delete-bootorder", no_argument, 0, 'O'},
+ {"part", required_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"test", required_argument, 0, 't'},
+ {"unicode", no_argument, 0, 'u'},
+ {"UCS-2", no_argument, 0, 'u'},
+ {"acpi_uid", required_argument, 0, 'U' },
+ {"verbose", optional_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"write-signature", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv,
+ "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:uU:v::Vw",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 'a':
+ opts.active = 1;
+ break;
+ case 'A':
+ opts.active = 0;
+ break;
+ case 'B':
+ opts.delete_boot = 1;
+ break;
+ case 'b':
+ rc = sscanf(optarg, "%x", &num);
+ if (rc == 1) opts.bootnum = num;
+ break;
+ case 'c':
+ opts.create = 1;
+ break;
+ case 'd':
+ opts.disk = optarg;
+ break;
+ case 'e':
+ rc = sscanf(optarg, "%d", &num);
+ if (rc == 1) opts.edd_version = num;
+ break;
+ case 'E':
+ rc = sscanf(optarg, "%x", &num);
+ if (rc == 1) opts.edd10_devicenum = num;
+ break;
+ case 'g':
+ opts.forcegpt = 1;
+ break;
+ case 'H':
+ rc = sscanf(optarg, "%x", &num);
+ if (rc == 1) opts.acpi_hid = num;
+ break;
+ case 'i':
+ opts.iface = optarg;
+ break;
+ case 'l':
+ opts.loader = optarg;
+ break;
+ case 'L':
+ opts.label = optarg;
+ break;
+ case 'N':
+ opts.delete_bootnext = 1;
+ break;
+ case 'n':
+ rc = sscanf(optarg, "%x", &num);
+ if (rc == 1) opts.bootnext = num;
+ break;
+ case 'o':
+ opts.bootorder = optarg;
+ break;
+ case 'O':
+ opts.delete_bootorder = 1;
+ break;
+ case 'p':
+ rc = sscanf(optarg, "%u", &num);
+ if (rc == 1) opts.part = num;
+ break;
+ case 'q':
+ opts.quiet = 1;
+ break;
+ case 't':
+ opts.testfile = optarg;
+ break;
+ case 'u':
+ opts.unicode = 1;
+ break;
+
+ case 'U':
+ rc = sscanf(optarg, "%x", &num);
+ if (rc == 1) opts.acpi_uid = num;
+ break;
+ case 'v':
+ opts.verbose = 1;
+ if (optarg) {
+ if (!strcmp(optarg, "v")) opts.verbose = 2;
+ if (!strcmp(optarg, "vv")) opts.verbose = 3;
+ rc = sscanf(optarg, "%d", &num);
+ if (rc == 1) opts.verbose = num;
+ }
+ break;
+ case 'V':
+ opts.showversion = 1;
+ break;
+
+ case 'w':
+ opts.write_signature = 1;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (optind < argc) {
+ opts.argc = argc;
+ opts.argv = argv;
+ opts.optind = optind;
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ struct dirent **boot_names = NULL;
+ var_entry_t *new_boot = NULL;
+ int num, num_boot_names=0;
+
+ set_default_opts();
+ parse_opts(argc, argv);
+ if (opts.showversion) {
+ printf("version %s\n", EFIBOOTMGR_VERSION);
+ return 0;
+ }
+
+ if (opts.iface && opts.acpi_hid == -1 && opts.acpi_uid == -1) {
+ fprintf(stderr, "\nYou must specify the ACPI HID and UID when using -i.\n\n");
+ return 1;
+ }
+
+ if (!opts.testfile) {
+ num_boot_names = read_boot_var_names(&boot_names);
+ read_vars(boot_names, num_boot_names, &boot_entry_list);
+ set_var_nums("Boot%04x-%*s", &boot_entry_list);
+
+ if (opts.delete_boot) {
+ if (opts.bootnum == -1)
+ fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n");
+ else
+ delete_boot_var(opts.bootnum);
+ }
+
+ if (opts.active >= 0) {
+ set_active_state();
+ }
+ }
+
+ if (opts.create) {
+ warn_duplicate_name(&boot_entry_list);
+ new_boot = make_boot_var(&boot_entry_list);
+ /* Put this boot var in the right BootOrder */
+ if (!opts.testfile && new_boot)
+ add_to_boot_order(new_boot->num);
+ }
+
+ if (!opts.testfile) {
+
+ if (opts.delete_bootorder) {
+ delete_boot_order();
+ }
+
+ if (opts.bootorder) {
+ set_boot_order();
+ }
+
+
+ if (opts.delete_bootnext) {
+ delete_boot_next();
+ }
+
+ if (opts.bootnext >= 0) {
+ set_boot_next(opts.bootnext & 0xFFFF);
+ }
+
+ if (!opts.quiet) {
+ num = read_boot_next();
+ if (num != -1 ) {
+ printf("BootNext: %04x\n", num);
+ }
+ num = read_boot_current();
+ if (num != -1) {
+ printf("BootCurrent: %04x\n", num);
+ }
+ show_boot_order();
+ show_boot_vars();
+ }
+ }
+ free_dirents(boot_names, num_boot_names);
+ return 0;
+}
+
--- /dev/null
+efibootmgr_SRCDIR := src/efibootmgr
+efibootmgr_OBJECTS := efibootmgr.o
+efibootmgr_TARGETS := efibootmgr
+efibootmgr_FULLTARGET := \
+ $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_TARGETS))
+efibootmgr_FULLOBJECT := \
+ $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_OBJECT))
+
+efibootmgr_LIBS := crc32.o disk.o efi.o efichar.o gpt.o scsi_ioctls.o \
+ unparse_path.o
+efibootmgr_LIBDIR := src/lib
+efibootmgr_FULLLIB := \
+ $(patsubst %,$(efibootmgr_LIBDIR)/%,$(efibootmgr_LIBS))
+
+ALLDEPS += $(efibootmgr_FULLTARGET)
+CLEANLIST += $(efibootmgr_FULLTARGET)
+CLEANLIST += $(efibootmgr_FULLOBJECT)
+bindir_TARGETS += $(efibootmgr_FULLTARGET)
+
+$(efibootmgr_FULLTARGET): \
+ $(efibootmgr_FULLOBJECT) \
+ $(efibootmgr_FULLLIB)
--- /dev/null
+/*
+ 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 <stdint.h>
+
+/*
+ * 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 */
--- /dev/null
+/*
+ disk.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _DISK_H
+#define _DISK_H
+
+#include <sys/ioctl.h>
+
+/* Snagged from linux/include/asm-ia64/ioctl.h */
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#define _IOC_SIZEBITS 14
+#define _IOC_DIRBITS 2
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE 0U
+#define _IOC_WRITE 1U
+#define _IOC_READ 2U
+
+#define _IOC(dir,type,nr,size) \
+ (((dir) << _IOC_DIRSHIFT) | \
+ ((type) << _IOC_TYPESHIFT) | \
+ ((nr) << _IOC_NRSHIFT) | \
+ ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
+
+
+/* Snagged from linux/include/linux/fs.h */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+
+
+enum _bus_type {bus_type_unknown, isa, pci};
+enum _interface_type {interface_type_unknown,
+ ata, atapi, scsi, usb,
+ i1394, fibre, i2o, md};
+
+int disk_get_pci(int fd,
+ unsigned char *bus,
+ unsigned char *device,
+ unsigned char *function);
+
+int disk_info_from_fd(int fd,
+ int *interface_type,
+ unsigned int *controllernum,
+ unsigned int *disknum,
+ unsigned char *part);
+
+int disk_get_partition_info (int fd,
+ uint32_t num,
+ uint64_t *start, uint64_t *size,
+ char *signature,
+ uint8_t *mbr_type, uint8_t *signature_type);
+
+
+int disk_get_size(int fd, long *size);
+int get_sector_size(int fd);
+
+
+#endif
--- /dev/null
+/*
+ efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 EFI_H
+#define EFI_H
+
+/*
+ * Extensible Firmware Interface
+ * Based on 'Extensible Firmware Interface Specification'
+ * version 1.02, 12 December, 2000
+ */
+#include <stdint.h>
+
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+
+#define EFI_ERROR(x) ((x) | (1L << (BITS_PER_LONG - 1)))
+
+#define EFI_SUCCESS 0
+#define EFI_LOAD_ERROR EFI_ERROR(1)
+#define EFI_INVALID_PARAMETER EFI_ERROR(2)
+#define EFI_UNSUPPORTED EFI_ERROR(3)
+#define EFI_BAD_BUFFER_SIZE EFI_ERROR(4)
+#define EFI_BUFFER_TOO_SMALL EFI_ERROR(5)
+#define EFI_NOT_FOUND EFI_ERROR(14)
+#define EFI_OUT_OF_RESOURCES EFI_ERROR(15)
+
+
+/*******************************************************
+ * Boot Option Attributes
+ *******************************************************/
+#define LOAD_OPTION_ACTIVE 0x00000001
+
+/******************************************************
+ * EFI Variable Attributes
+ ******************************************************/
+#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+
+
+typedef struct {
+ uint8_t b[16];
+} efi_guid_t;
+
+#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
+((efi_guid_t) \
+{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+ (c) & 0xff, ((c) >> 8) & 0xff, \
+ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+
+/******************************************************
+ * GUIDs
+ ******************************************************/
+#define DEVICE_PATH_PROTOCOL \
+EFI_GUID( 0x09576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_GLOBAL_VARIABLE \
+EFI_GUID( 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C)
+#define EDD10_HARDWARE_VENDOR_PATH_GUID \
+EFI_GUID( 0xCF31FAC5, 0xC24E, 0x11d2, 0x85, 0xF3, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define BLKX_UNKNOWN_GUID \
+EFI_GUID( 0x47c7b225, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define DIR_UNKNOWN_GUID \
+EFI_GUID( 0x47c7b227, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define ESP_UNKNOWN_GUID \
+EFI_GUID( 0x47c7b226, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+static inline int
+efi_guidcmp(efi_guid_t left, efi_guid_t right)
+{
+ return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+
+typedef unsigned long efi_status_t;
+typedef uint8_t efi_bool_t;
+typedef uint16_t efi_char16_t; /* UNICODE character */
+
+typedef struct _efi_variable_t {
+ efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
+ efi_guid_t VendorGuid;
+ uint64_t DataSize;
+ uint8_t Data[1024];
+ efi_status_t Status;
+ uint32_t Attributes;
+} __attribute__((packed)) efi_variable_t;
+
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t data[1];
+} __attribute__((packed)) EFI_DEVICE_PATH;
+
+typedef struct {
+ uint32_t attributes;
+ uint16_t file_path_list_length;
+ efi_char16_t description[1];
+ EFI_DEVICE_PATH _unused_file_path_list[1];
+} __attribute__((packed)) EFI_LOAD_OPTION;
+
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t _HID;
+ uint32_t _UID;
+} __attribute__((packed)) ACPI_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ efi_guid_t vendor_guid;
+ uint8_t data[1];
+} __attribute__((packed)) VENDOR_DEVICE_PATH;
+
+#define EDD10_HARDWARE_VENDOR_PATH_LENGTH 24
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t function;
+ uint8_t device;
+} __attribute__((packed)) PCI_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t socket;
+} __attribute__((packed)) PCCARD_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t memory_type;
+ uint64_t start;
+ uint64_t end;
+} __attribute__((packed)) MEMORY_MAPPED_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t controller;
+} __attribute__((packed)) CONTROLLER_DEVICE_PATH;
+
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint16_t id;
+ uint16_t lun;
+} __attribute__((packed)) SCSI_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t primary_secondary;
+ uint8_t slave_master;
+ uint16_t lun;
+} __attribute__((packed)) ATAPI_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t reserved;
+ uint64_t wwn;
+ uint64_t lun;
+} __attribute__((packed)) FIBRE_CHANNEL_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t reserved;
+ uint64_t guid;
+} __attribute__((packed)) I1394_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t port;
+ uint8_t endpoint;
+} __attribute__((packed)) USB_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint16_t vendor;
+ uint16_t product;
+ uint8_t class;
+ uint8_t subclass;
+ uint8_t protocol;
+} __attribute__((packed)) USB_CLASS_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t tid;
+} __attribute__((packed)) I2O_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t macaddr[32];
+ uint8_t iftype;
+} __attribute__((packed)) MAC_ADDR_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t local_ip;
+ uint32_t remote_ip;
+ uint16_t local_port;
+ uint16_t remote_port;
+ uint16_t protocol;
+ uint8_t static_addr;
+} __attribute__((packed)) IPv4_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint8_t local_ip[16];
+ uint8_t remote_ip[16];
+ uint16_t local_port;
+ uint16_t remote_port;
+ uint16_t protocol;
+ uint8_t static_addr;
+} __attribute__((packed)) IPv6_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t reserved;
+ uint64_t node_guid;
+ uint64_t ioc_guid;
+ uint64_t id;
+} __attribute__((packed)) INFINIBAND_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t reserved;
+ uint64_t baud_rate;
+ uint8_t data_bits;
+ uint8_t parity;
+ uint8_t stop_bits;
+} __attribute__((packed)) UART_DEVICE_PATH;
+
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t part_num;
+ uint64_t start;
+ uint64_t size;
+ uint8_t signature[16];
+ uint8_t mbr_type;
+ uint8_t signature_type;
+ uint8_t padding[6]; /* Emperically needed */
+} __attribute__((packed)) HARDDRIVE_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint32_t boot_entry;
+ uint64_t start;
+ uint64_t size;
+} __attribute__((packed)) CDROM_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ efi_char16_t path_name[1];
+} __attribute__((packed)) FILE_PATH_DEVICE_PATH;
+
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ efi_guid_t guid;
+} __attribute__((packed)) MEDIA_PROTOCOL_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+ uint16_t device_type;
+ uint16_t status_flag;
+ uint8_t description[1];
+} __attribute__((packed)) BIOS_BOOT_SPEC_DEVICE_PATH;
+
+typedef struct {
+ uint8_t type;
+ uint8_t subtype;
+ uint16_t length;
+} __attribute__((packed)) END_DEVICE_PATH;
+
+
+/* Used for ACPI _HID */
+#define EISAID_PNP0A03 0xa0341d0
+
+#define PROC_DIR_EFI_VARS "/proc/efi/vars/"
+
+
+
+/* Exported functions */
+
+efi_status_t read_variable(char *name, efi_variable_t *var);
+efi_status_t write_variable(efi_variable_t *var);
+int make_linux_efi_variable(efi_variable_t *var,
+ unsigned int free_number);
+char * efi_guid_unparse(efi_guid_t *guid, char *out);
+EFI_DEVICE_PATH *load_option_path(EFI_LOAD_OPTION *option);
+
+
+
+
+
+#endif /* _ASM_IA64_EFI_H */
--- /dev/null
+/*
+ efibootmgr.h - Manipulates EFI variables as exported in /proc/efi/vars
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _EFIBOOTMGR_H
+#define _EFIBOOTMGR_H
+
+typedef struct {
+ int argc;
+ char **argv;
+ int optind;
+ char *disk;
+ char *iface;
+ char *loader;
+ char *label;
+ char *bootorder;
+ char *testfile;
+ uint32_t part;
+ int edd_version;
+ int edd10_devicenum;
+ int bootnum;
+ int bootnext;
+ int verbose;
+ int active;
+ uint32_t acpi_hid;
+ uint32_t acpi_uid;
+ unsigned int delete_boot:1;
+ unsigned int delete_bootorder:1;
+ unsigned int delete_bootnext:1;
+ unsigned int quiet:1;
+ unsigned int showversion:1;
+ unsigned int create:1;
+ unsigned int unicode:1;
+ unsigned int write_signature:1;
+ unsigned int forcegpt:1;
+} efibootmgr_opt_t;
+
+
+extern efibootmgr_opt_t opts;
+
+#endif
--- /dev/null
+/*
+ efichar.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _EFICHAR_H
+#define _EFICHAR_H
+
+int efichar_strlen(const efi_char16_t *p, int max);
+int efichar_strsize(const efi_char16_t *p);
+unsigned long efichar_from_char(efi_char16_t *dest, const char *src, size_t dest_len);
+unsigned long efichar_to_char(char *dest, const efi_char16_t *src, size_t dest_len);
+int efichar_strcmp(const efi_char16_t *s1, const efi_char16_t *s2);
+int efichar_char_strcmp(const char *s1, const efi_char16_t *s2);
+int efichar_strncpy(efi_char16_t *s1, const efi_char16_t *s2, int max);
+
+#endif
--- /dev/null
+/*
+ gpt.[ch]
+
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _GPT_H
+#define _GPT_H
+
+
+#include <inttypes.h>
+#include "efi.h"
+
+#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 0x5452415020494645
+#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, \
+ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
+#define LEGACY_MBR_PARTITION_GUID \
+ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
+ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
+#define PARTITION_MSFT_RESERVED_GUID \
+ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
+ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
+#define PARTITION_BASIC_DATA_GUID \
+ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
+ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
+#define PARTITION_LINUX_RAID_GUID \
+ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
+ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
+#define PARTITION_LINUX_SWAP_GUID \
+ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
+ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
+#define PARTITION_LINUX_LVM_GUID \
+ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
+ 0xa2, 0x3c, 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;
+ efi_char16_t partition_name[72 / sizeof(efi_char16_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 */
+int gpt_disk_get_partition_info (int fd,
+ uint32_t num,
+ uint64_t *start, uint64_t *size,
+ char *signature,
+ uint8_t *mbr_type, uint8_t *signature_type);
+
+
+#endif
+
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ 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
--- /dev/null
+CFLAGS += -Isrc/include
--- /dev/null
+/*
+ scsi_ioctls.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _SCSI_IOCTLS_H
+#define _SCSI_IOCTLS_H
+
+#include <stdint.h>
+
+
+/* Snagged from linux/include/scsi/scsi.h */
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+#define SCSI_IOCTL_GET_PCI 0x5387
+
+typedef struct scsi_idlun {
+ uint32_t dev_id;
+ uint32_t host_unique_id;
+} Scsi_Idlun;
+
+
+inline int get_scsi_idlun(int fd, Scsi_Idlun *idlun);
+inline int get_scsi_pci(int fd, char *slot_name);
+int idlun_to_components (Scsi_Idlun *idlun,
+ unsigned char *host,
+ unsigned char *channel,
+ unsigned char *id,
+ unsigned char *lun);
+
+#endif
--- /dev/null
+/*
+ unparse_path.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 _UNPARSE_PATH_H
+#define _UNPARSE_PATH_H
+
+#include <stdint.h>
+#include "efi.h"
+
+#define OFFSET_OF(struct_type, member) \
+ ((unsigned long) ((char *) &((struct_type*) 0)->member))
+
+uint64_t unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize);
+void dump_raw_data(void *data, uint64_t length);
+unsigned long unparse_raw(char *buffer, uint8_t *p, uint64_t length);
+unsigned long unparse_raw_text(char *buffer, uint8_t *p, uint64_t length);
+
+#endif
--- /dev/null
+%:
+ +make -C ../ $*
--- /dev/null
+/*
+ * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - 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 <stdint.h>
+
+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;
+}
--- /dev/null
+/*
+ disk.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+ */
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "disk.h"
+#include "scsi_ioctls.h"
+#include "gpt.h"
+#include "efibootmgr.h"
+
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+
+int
+disk_info_from_fd(int fd,
+ int *interface_type,
+ unsigned int *controllernum,
+ unsigned int *disknum,
+ unsigned char *part)
+{
+ struct stat buf;
+ int rc;
+ uint64_t major;
+ unsigned char minor;
+ memset(&buf, 0, sizeof(struct stat));
+ rc = fstat(fd, &buf);
+ if (rc == -1) {
+ perror("stat");
+ return 1;
+ }
+ if (!(S_ISBLK(buf.st_mode) || S_ISREG(buf.st_mode))) {
+ printf("Cannot stat non-block or non-regular file\n");
+ return 1;
+ }
+ major = buf.st_dev >> 8;
+ minor = buf.st_dev && 0xFF;
+
+ /* 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 (major == 3) {
+ *disknum = (minor >> 6) & 1;
+ *controllernum = (major - 3 + 0) + *disknum;
+ *interface_type = ata;
+ *part = minor & 0x3F;
+ return 0;
+ }
+ else if (major == 22) {
+ *disknum = (minor >> 6) & 1;
+ *controllernum = (major - 22 + 2) + *disknum;
+ *interface_type = ata;
+ *part = minor & 0x3F;
+ return 0;
+ }
+ else if (major >= 33 && major <= 34) {
+ *disknum = (minor >> 6) & 1;
+ *controllernum = (major - 33 + 4) + *disknum;
+ *interface_type = ata;
+ *part = minor & 0x3F;
+ return 0;
+ }
+ else if (major >= 56 && major <= 57) {
+ *disknum = (minor >> 6) & 1;
+ *controllernum = (major - 56 + 8) + *disknum;
+ *interface_type = ata;
+ *part = minor & 0x3F;
+ return 0;
+ }
+ else if (major >= 88 && major <= 91) {
+ *disknum = (minor >> 6) & 1;
+ *controllernum = (major - 88 + 12) + *disknum;
+ *interface_type = ata;
+ *part = minor & 0x3F;
+ return 0;
+ }
+
+ /* I2O disks can have up to 16 partitions, or 4 bits worth. */
+ if (major >= 80 && major <= 87) {
+ *interface_type = i2o;
+ *disknum = 16*(major-80) + (minor >> 4);
+ *part = (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 (major == 8) {
+ *interface_type = scsi;
+ *disknum = (minor >> 4);
+ *part = (minor & 0xF);
+ return 0;
+ }
+ else if ( major >= 65 && major <= 71) {
+ *interface_type = scsi;
+ *disknum = 16*(major-64) + (minor >> 4);
+ *part = (minor & 0xF);
+ return 0;
+ }
+
+ printf("Unknown interface type.\n");
+ return 1;
+}
+
+static int
+disk_get_scsi_pci(int fd,
+ unsigned char *bus,
+ unsigned char *device,
+ unsigned char *function)
+{
+ int rc, usefd=fd;
+ struct stat buf;
+ char slot_name[8];
+ unsigned int b=0,d=0,f=0;
+ memset(&buf, 0, sizeof(buf));
+ rc = fstat(fd, &buf);
+ if (rc == -1) {
+ perror("stat");
+ return 1;
+ }
+ if (S_ISREG(buf.st_mode)) {
+ /* can't call ioctl() on this file and have it succeed.
+ * instead, need to open the block device
+ * from /dev/.
+ */
+ fprintf(stderr, "You must call this program with "
+ "a file name such as /dev/sda.\n");
+ return 1;
+ }
+
+ rc = get_scsi_pci(usefd, slot_name);
+ if (rc) {
+ perror("get_scsi_pci");
+ return rc;
+ }
+ rc = sscanf(slot_name, "%x:%x.%x", &b,&d,&f);
+ if (rc != 3) {
+ printf("sscanf failed\n");
+ return 1;
+ }
+ *bus = b & 0xFF;
+ *device = d & 0xFF;
+ *function = f & 0xFF;
+ return 0;
+}
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 7:3 = slot
+ * 2:0 = function
+ *
+ * pci bus 00 device 39 vid 8086 did 7111 channel 1
+ * 00:07.1
+ */
+#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+
+static int
+disk_get_ide_pci(int fd,
+ unsigned char *bus,
+ unsigned char *device,
+ unsigned char *function)
+{
+ int num_scanned, procfd;
+ unsigned int b=0,d=0,disknum=0, controllernum=0;
+ unsigned char part=0;
+ char procname[80], infoline[80];
+ size_t read_count;
+ int interface_type;
+ int rc;
+
+ rc = disk_info_from_fd(fd, &interface_type, &controllernum,
+ &disknum, &part);
+ if (rc) return rc;
+
+
+ sprintf(procname, "/proc/ide/ide%d/config", controllernum);
+
+ procfd = open(procname, O_RDONLY);
+ if (!procfd) {
+ perror("opening /proc/ide/ide*/config");
+ return 1;
+ }
+ read_count = read(procfd, infoline, sizeof(infoline)-1);
+ close(procfd);
+
+ num_scanned = sscanf(infoline,
+ "pci bus %x device %x vid %*x did %*x channel %*x",
+ &b, &d);
+
+ if (num_scanned == 2) {
+ *bus = b;
+ *device = PCI_SLOT(d);
+ *function = PCI_FUNC(d);
+ }
+ return 0;
+}
+
+
+
+#if 0
+/* this is a list of devices */
+static int
+disk_get_md_parts(int fd)
+{
+ return 0;
+}
+#endif
+
+int
+disk_get_pci(int fd,
+ unsigned char *bus,
+ unsigned char *device,
+ unsigned char *function)
+{
+ int interface_type=interface_type_unknown;
+ unsigned int controllernum=0, disknum=0;
+ unsigned char part=0;
+
+ disk_info_from_fd(fd,
+ &interface_type,
+ &controllernum,
+ &disknum,
+ &part);
+ switch (interface_type) {
+ case ata:
+ return disk_get_ide_pci(fd, bus, device, function);
+ break;
+ case scsi:
+ return disk_get_scsi_pci(fd, bus, device, function);
+ break;
+ case i2o:
+ break;
+ case md:
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+int
+disk_get_size(int fd, long *size)
+{
+ return ioctl(fd, BLKGETSIZE, size);
+}
+
+/**
+ * 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 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, legacy_mbr *mbr,
+ uint32_t num,
+ uint64_t *start, uint64_t *size,
+ char *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 && !opts.write_signature) {
+
+ 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 (opts.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 == -1) {
+ perror("stat disk");
+ }
+
+ rc = gettimeofday(&tv, NULL);
+ if (rc == -1) {
+ perror("gettimeofday");
+ }
+
+ /* 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);
+ 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;
+ disk_get_size(fd, &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;
+}
+
+/************************************************************
+ * get_sector_size
+ * Requires:
+ * - filedes is an open file descriptor, suitable for reading
+ * Modifies: nothing
+ * Returns:
+ * sector size, or 512.
+ ************************************************************/
+int
+get_sector_size(int filedes)
+{
+ int rc, sector_size = 512;
+
+ rc = ioctl(filedes, BLKSSZGET, §or_size);
+ if (rc)
+ sector_size = 512;
+ return sector_size;
+}
+
+/**
+ * disk_get_partition_info()
+ * @fd - open file descriptor to disk
+ * @num - partition number (1 is first partition on the disk)
+ * @start - partition starting sector returned
+ * @size - partition size (in sectors) returned
+ * @signature - partition signature returned
+ * @mbr_type - partition type returned
+ * @signature_type - signature type returned
+ *
+ * Description: Finds partition table info for given partition on given disk.
+ * Both GPT and MSDOS partition tables are tested for.
+ * Returns 0 on success, non-zero on failure
+ */
+int
+disk_get_partition_info (int fd,
+ uint32_t num,
+ uint64_t *start, uint64_t *size,
+ char *signature,
+ uint8_t *mbr_type, uint8_t *signature_type)
+{
+ legacy_mbr *mbr;
+ void *mbr_unaligned;
+ off_t offset;
+ int this_bytes_read = 0;
+ int gpt_invalid=0, mbr_invalid=0;
+ int rc=0;
+ int sector_size = get_sector_size(fd);
+
+ if (sizeof(*mbr) != sector_size)
+ return 1;
+ mbr_unaligned = malloc(sizeof(*mbr)+sector_size-1);
+ mbr = (legacy_mbr *)
+ (((unsigned long)mbr_unaligned + sector_size - 1) &
+ ~(unsigned long)(sector_size-1));
+ memset(mbr, 0, sizeof(*mbr));
+ offset = lseek(fd, 0, SEEK_SET);
+ this_bytes_read = read(fd, mbr, sizeof(*mbr));
+ if (this_bytes_read < sizeof(*mbr)) {
+ rc=1;
+ goto error_free_mbr;
+ }
+ gpt_invalid = gpt_disk_get_partition_info(fd, num,
+ start, size,
+ signature,
+ mbr_type,
+ signature_type);
+ if (gpt_invalid) {
+ mbr_invalid = msdos_disk_get_partition_info(fd, mbr, num,
+ start, size,
+ signature,
+ mbr_type,
+ signature_type);
+ if (mbr_invalid) {
+ rc=1;
+ goto error_free_mbr;
+ }
+ }
+ error_free_mbr:
+ free(mbr_unaligned);
+ return rc;
+}
+
+#ifdef DISK_EXE
+int
+main (int argc, char *argv[])
+{
+ int fd, rc;
+ unsigned char bus=0,device=0,func=0;
+ if (argc <= 1) return 1;
+ fd = open(argv[1], O_RDONLY|O_DIRECT);
+ rc = disk_get_pci(fd, &bus, &device, &func);
+ if (!rc) {
+ printf("PCI %02x:%02x.%02x\n", bus, device, func);
+ }
+ return rc;
+}
+#endif
--- /dev/null
+/*
+ efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
+
+ Copyright (C) 2001,2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+ */
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+
+typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */
+typedef __uint32_t u32; /* ditto */
+typedef __uint16_t u16; /* ditto */
+typedef __uint8_t u8; /* ditto */
+
+#include <linux/ethtool.h>
+#include "efi.h"
+#include "efichar.h"
+#include "scsi_ioctls.h"
+#include "disk.h"
+#include "efibootmgr.h"
+
+EFI_DEVICE_PATH *
+load_option_path(EFI_LOAD_OPTION *option)
+{
+ char *p = (char *) option;
+ return (EFI_DEVICE_PATH *)
+ (p + sizeof(uint32_t) /* Attributes */
+ + sizeof(uint16_t) /* FilePathListLength*/
+ + efichar_strsize(option->description)); /* Description */
+}
+
+char *
+efi_guid_unparse(efi_guid_t *guid, char *out)
+{
+ sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ guid->b[3], guid->b[2], guid->b[1], guid->b[0],
+ guid->b[5], guid->b[4], guid->b[7], guid->b[6],
+ guid->b[8], guid->b[9], guid->b[10], guid->b[11],
+ guid->b[12], guid->b[13], guid->b[14], guid->b[15]);
+ return out;
+}
+
+
+efi_status_t
+read_variable(char *name, efi_variable_t *var)
+{
+ int newnamesize;
+ char *newname;
+ int fd;
+ size_t readsize;
+ if (!name || !var) return EFI_INVALID_PARAMETER;
+
+ newnamesize = strlen(PROC_DIR_EFI_VARS) + strlen(name) + 1;
+ newname = malloc(newnamesize);
+ if (!newname) return EFI_OUT_OF_RESOURCES;
+ sprintf(newname, "%s%s", PROC_DIR_EFI_VARS,name);
+ fd = open(newname, O_RDONLY);
+ if (fd == -1) {
+ free(newname);
+ return EFI_NOT_FOUND;
+ }
+ readsize = read(fd, var, sizeof(*var));
+ if (readsize != sizeof(*var)) {
+ free(newname);
+ close(fd);
+ return EFI_INVALID_PARAMETER;
+ }
+ close(fd);
+ free(newname);
+ return var->Status;
+}
+
+static efi_status_t
+write_variable_to_file(efi_variable_t *var)
+{
+ int fd, byteswritten;
+ if (!var || !opts.testfile) return EFI_INVALID_PARAMETER;
+
+ printf("Test mode: Writing to %s\n", opts.testfile);
+ fd = creat(opts.testfile, S_IRWXU);
+ if (fd == -1) {
+ perror("Couldn't write to testfile");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ byteswritten = write(fd, var, sizeof(*var));
+ if (byteswritten == -1) {
+ perror("Writing to testfile");
+
+ }
+ close(fd);
+ return EFI_SUCCESS;
+}
+/**
+ * select_variable_names()
+ * @d - dirent to compare against
+ *
+ * This ignores "." and ".." entries, and selects all others.
+ */
+
+static int
+select_variable_names(const struct dirent *d)
+{
+ if (!strcmp(d->d_name, ".") ||
+ !strcmp(d->d_name, ".."))
+ return 0;
+ return 1;
+}
+
+/**
+ * find_write_victim()
+ * @var - variable to be written
+ * @file - name of file to open for writing @var is returned.
+ *
+ * This ignores "." and ".." entries, and selects all others.
+ */
+static char *
+find_write_victim(efi_variable_t *var, char file[PATH_MAX])
+{
+ struct dirent **namelist = NULL;
+ int i, n, found=0;
+ char testname[PATH_MAX], *p;
+
+ memset(testname, 0, sizeof(testname));
+ n = scandir(PROC_DIR_EFI_VARS, &namelist,
+ select_variable_names, alphasort);
+ if (n < 0) {
+ perror("scandir " PROC_DIR_EFI_VARS);
+ fprintf(stderr, "You must 'modprobe efivars' first.\n");
+ return NULL;
+ }
+
+ p = testname;
+ efichar_to_char(p, var->VariableName, PATH_MAX);
+ p += strlen(p);
+ p += sprintf(p, "-");
+ efi_guid_unparse(&var->VendorGuid, p);
+
+ for (i=0; i<n; i++) {
+ if (namelist[i] &&
+ strncmp(testname, namelist[i]->d_name, sizeof(testname))) {
+ found++;
+ sprintf(file, "%s%s", PROC_DIR_EFI_VARS,
+ namelist[i]->d_name);
+ break;
+ }
+ }
+
+ while (n--) {
+ if (namelist[n]) {
+ free(namelist[n]);
+ namelist[n] = NULL;
+ }
+ }
+ free(namelist);
+
+ if (!found) return NULL;
+ return file;
+}
+
+
+efi_status_t
+write_variable(efi_variable_t *var)
+{
+ int fd;
+ size_t writesize;
+ char buffer[PATH_MAX], name[PATH_MAX], *p = NULL;
+
+ if (!var) return EFI_INVALID_PARAMETER;
+ if (opts.testfile) return write_variable_to_file(var);
+ memset(buffer, 0, sizeof(buffer));
+ memset(name, 0, sizeof(name));
+
+ p = find_write_victim(var, name);
+ if (!p) return EFI_INVALID_PARAMETER;
+
+ fd = open(name, O_WRONLY);
+ if (fd == -1) {
+ sprintf(buffer, "write_variable():open(%s)", name);
+ perror(buffer);
+ return EFI_INVALID_PARAMETER;
+ }
+ writesize = write(fd, var, sizeof(*var));
+ if (writesize != sizeof(*var)) {
+#if 0
+ sprintf(buffer, "write_variable():write(%s)", name);
+ perror(buffer);
+ dump_raw_data(var, sizeof(*var));
+#endif
+ close(fd);
+ return EFI_INVALID_PARAMETER;
+
+ }
+ close(fd);
+ return EFI_SUCCESS;
+}
+
+
+static int
+get_edd_version()
+{
+ efi_status_t status;
+ efi_variable_t var;
+ efi_guid_t guid = BLKX_UNKNOWN_GUID;
+ char name[80], text_guid[40];
+ ACPI_DEVICE_PATH *path = (ACPI_DEVICE_PATH *)&(var.Data);
+ int rc = 0;
+
+ /* Allow global user option override */
+
+ switch (opts.edd_version)
+ {
+ case 0: /* No EDD information */
+ return 0;
+ break;
+ case 1: /* EDD 1.0 */
+ return 1;
+ break;
+ case 3: /* EDD 3.0 */
+ return 3;
+ break;
+ default:
+ break;
+ }
+
+
+ memset(&var, 0, sizeof(efi_variable_t));
+ efi_guid_unparse(&guid, text_guid);
+ sprintf(name, "blk0-%s", text_guid);
+
+ status = read_variable(name, &var);
+ if (status != EFI_SUCCESS) {
+ return 0;
+ }
+ if (path->type == 2 && path->subtype == 1) rc = 3;
+ else rc = 1;
+ return rc;
+}
+
+/*
+ EFI_DEVICE_PATH, 0x01 (Hardware), 0x04 (Vendor), length 0x0018
+ This needs to know what EFI device has the boot device.
+*/
+static uint16_t
+make_edd10_device_path(void *dest, uint32_t hardware_device)
+{
+ VENDOR_DEVICE_PATH *hw;
+ char buffer[EDD10_HARDWARE_VENDOR_PATH_LENGTH];
+ efi_guid_t guid = EDD10_HARDWARE_VENDOR_PATH_GUID;
+ uint32_t *data;
+ memset(buffer, 0, sizeof(buffer));
+ hw = (VENDOR_DEVICE_PATH *)buffer;
+ data = (uint32_t *)hw->data;
+ hw->type = 0x01; /* Hardware Device Path */
+ hw->subtype = 0x04; /* Vendor */
+ hw->length = EDD10_HARDWARE_VENDOR_PATH_LENGTH;
+ memcpy(&(hw->vendor_guid), &guid, sizeof(guid));
+ *data = hardware_device;
+ memcpy(dest, buffer, hw->length);
+ return hw->length;
+}
+
+static uint16_t
+make_end_device_path(void *dest)
+{
+ END_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 0x7F; /* End of Hardware Device Path */
+ p.subtype = 0xFF; /* End Entire Device Path */
+ p.length = sizeof(p);
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_acpi_device_path(void *dest, uint32_t _HID, uint32_t _UID)
+{
+ ACPI_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 2;
+ p.subtype = 1;
+ p.length = sizeof(p);
+ p._HID = _HID;
+ p._UID = _UID;
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_mac_addr_device_path(void *dest, char *mac, uint8_t iftype)
+{
+
+ int i;
+ MAC_ADDR_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 3;
+ p.subtype = 11;
+ p.length = sizeof(p);
+ for (i=0; i < 14; i++) {
+ p.macaddr[i] = mac[i];
+ }
+ p.iftype = iftype;
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_pci_device_path(void *dest, uint8_t device, uint8_t function)
+{
+ PCI_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 1;
+ p.subtype = 1;
+ p.length = sizeof(p);
+ p.device = device;
+ p.function = function;
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_scsi_device_path(void *dest, uint16_t id, uint16_t lun)
+{
+ SCSI_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 3;
+ p.subtype = 2;
+ p.length = sizeof(p);
+ p.id = id;
+ p.lun = lun;
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_harddrive_device_path(void *dest, uint32_t num, uint64_t start, uint64_t size,
+ uint8_t *signature,
+ uint8_t mbr_type, uint8_t signature_type)
+{
+ HARDDRIVE_DEVICE_PATH p;
+ memset(&p, 0, sizeof(p));
+ p.type = 4;
+ p.subtype = 1;
+ p.length = sizeof(p);
+ p.part_num = num;
+ p.start = start;
+ p.size = size;
+ if (signature) memcpy(p.signature, signature, 16);
+ p.mbr_type = mbr_type;
+ p.signature_type = signature_type;
+ memcpy(dest, &p, p.length);
+ return p.length;
+}
+
+static uint16_t
+make_file_path_device_path(void *dest, efi_char16_t *name)
+{
+ FILE_PATH_DEVICE_PATH *p;
+ char buffer[1024];
+ int namelen = efichar_strlen(name, -1);
+ int namesize = efichar_strsize(name);
+
+ memset(buffer, 0, sizeof(buffer));
+ p = (FILE_PATH_DEVICE_PATH *)buffer;
+ p->type = 4;
+ p->subtype = 4;
+ p->length = 4 + namesize;
+ efichar_strncpy(p->path_name,
+ name, namelen);
+
+ memcpy(dest, buffer, p->length);
+ return p->length;
+
+}
+
+
+
+static long
+make_edd30_device_path(int fd, void *buffer)
+{
+ int rc=0;
+ unsigned char bus=0, device=0, function=0;
+ Scsi_Idlun idlun;
+ unsigned char host=0, channel=0, id=0, lun=0;
+ char *p = buffer;
+
+
+ rc = disk_get_pci(fd, &bus, &device, &function);
+ if (rc) return 0;
+
+ memset(&idlun, 0, sizeof(idlun));
+ rc = get_scsi_idlun(fd, &idlun);
+ if (rc) return 0;
+ idlun_to_components(&idlun, &host, &channel, &id, &lun);
+
+ p += make_acpi_device_path (p, EISAID_PNP0A03, bus);
+ p += make_pci_device_path (p, device, function);
+ p += make_scsi_device_path (p, id, lun);
+ return ((void *)p - buffer);
+}
+
+/**
+ * make_disk_load_option()
+ * @disk disk
+ *
+ * Returns 0 on error, length of load option created on success.
+ */
+char *make_disk_load_option(char *p, char *disk)
+{
+ int disk_fd=0;
+ char buffer[80];
+ char signature[16];
+ int rc, edd_version=0;
+ uint8_t mbr_type=0, signature_type=0;
+ uint64_t start=0, size=0;
+ efi_char16_t os_loader_path[40];
+
+ memset(signature, 0, sizeof(signature));
+
+ disk_fd = open(opts.disk, O_RDWR);
+ if (disk_fd == -1) {
+ sprintf(buffer, "Could not open disk %s", opts.disk);
+ perror(buffer);
+ return 0;
+ }
+
+ if (opts.edd_version) {
+ edd_version = get_edd_version();
+
+ if (edd_version == 3) {
+ p += make_edd30_device_path(disk_fd, p);
+ }
+ else if (edd_version == 1) {
+ p += make_edd10_device_path(p, opts.edd10_devicenum);
+ }
+ }
+
+ rc = disk_get_partition_info (disk_fd, opts.part,
+ &start, &size, signature,
+ &mbr_type, &signature_type);
+
+ close(disk_fd);
+
+ if (rc) {
+ fprintf(stderr, "Error: no partition information on disk %s.\n"
+ " Cowardly refusing to create a boot option.\n",
+ opts.disk);
+ return 0;
+ }
+
+ p += make_harddrive_device_path (p, opts.part,
+ start, size,
+ signature,
+ mbr_type, signature_type);
+
+ efichar_from_char(os_loader_path, opts.loader, sizeof(os_loader_path));
+ p += make_file_path_device_path (p, os_loader_path);
+ p += make_end_device_path (p);
+
+ return(p);
+}
+
+/**
+ * make_net_load_option()
+ * @data - load option returned
+ *
+ * Returns 0 on error, length of load option created on success.
+ */
+char *make_net_load_option(char *p, char *iface)
+{
+ /* copied pretty much verbatim from the ethtool source */
+ int fd = 0, err;
+ int bus, slot, func;
+ struct ifreq ifr;
+ struct ethtool_drvinfo drvinfo;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, iface);
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&drvinfo;
+ /* Open control socket */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot get control socket");
+ }
+ err = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ perror("Cannot get driver information");
+ }
+
+ err = sscanf(drvinfo.bus_info, "%2x:%2x.%x", &bus, &slot, &func);
+ if (err == 0) {
+ perror("Couldn't parse device location string.");
+ }
+
+ p += make_acpi_device_path(p, opts.acpi_hid, opts.acpi_uid);
+ p += make_pci_device_path(p, (uint8_t)slot, (uint8_t)func);
+
+ err = ioctl(fd, SIOCGIFHWADDR, &ifr);
+ if (err < 0) {
+ perror("Cannot get hardware address.");
+ }
+
+ p += make_mac_addr_device_path(p, ifr.ifr_ifru.ifru_hwaddr.sa_data, 0);
+ p += make_end_device_path (p);
+
+ return(p);
+}
+
+/**
+ * make_linux_load_option()
+ * @data - load option returned
+ *
+ * Returns 0 on error, length of load option created on success.
+ */
+static unsigned long
+make_linux_load_option(void *data)
+{
+ EFI_LOAD_OPTION *load_option = data;
+ char *p = data, *q;
+ efi_char16_t description[64];
+ unsigned long datasize=0;
+
+ /* Write Attributes */
+ if (opts.active) load_option->attributes = LOAD_OPTION_ACTIVE;
+ else load_option->attributes = 0;
+
+ p += sizeof(uint32_t);
+ /* skip writing file_path_list_length */
+ p += sizeof(uint16_t);
+ /* Write description. This is the text that appears on the screen for the load option. */
+ memset(description, 0, sizeof(description));
+ efichar_from_char(description, opts.label, sizeof(description));
+ efichar_strncpy(load_option->description, description, sizeof(description));
+ p += efichar_strsize(load_option->description);
+
+ q = p;
+
+ if (opts.iface) {
+ p = (char *)make_net_load_option(p, opts.iface);
+ }
+
+ else {
+ p = (char *)make_disk_load_option(p, opts.iface);
+ }
+
+ load_option->file_path_list_length = p - q;
+
+ datasize = (uint8_t *)p - (uint8_t *)data;
+ return datasize;
+}
+
+/*
+ * append_extra_args()
+ * appends all arguments from argv[] not snarfed by getopt
+ * as one long string onto data, up to maxchars. allow for nulls
+ */
+
+static unsigned long
+append_extra_args_ascii(void *data, unsigned long maxchars)
+{
+ char *p = data;
+ int i, appended=0;
+ unsigned long usedchars=0;
+ if (!data) return 0;
+
+
+ for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) {
+ p = strncpy(p, opts.argv[i], maxchars-usedchars-1);
+ p += strlen(p);
+ appended=1;
+
+ usedchars = p - (char *)data;
+
+ /* Put a space between args */
+ if (i < (opts.argc-1)) {
+
+ p = strncpy(p, " ", maxchars-usedchars-1);
+ p += strlen(p);
+ usedchars = p - (char *)data;
+ }
+
+ }
+ /* Remember the NULL */
+ if (appended) return strlen(data) + 1;
+ return 0;
+}
+
+static unsigned long
+append_extra_args_unicode(void *data, unsigned long maxchars)
+{
+ char *p = data;
+ int i, appended=0;
+ unsigned long usedchars=0;
+ if (!data) return 0;
+
+
+ for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) {
+ p += efichar_from_char((efi_char16_t *)p, opts.argv[i],
+ maxchars-usedchars);
+ usedchars = efichar_strsize(data) - sizeof(efi_char16_t);
+ appended=1;
+
+ /* Put a space between args */
+ if (i < (opts.argc-1)) {
+ p += efichar_from_char((efi_char16_t *)p, " ",
+ maxchars-usedchars);
+ usedchars = efichar_strsize(data) -
+ sizeof(efi_char16_t);
+ }
+ }
+
+ if (appended) return efichar_strsize( (efi_char16_t *)data );
+ return 0;
+}
+
+
+static unsigned long
+append_extra_args(void *data, unsigned long maxchars)
+{
+ if (opts.unicode)
+ return append_extra_args_unicode(data, maxchars);
+ else
+ return append_extra_args_ascii(data, maxchars);
+}
+
+
+
+int
+make_linux_efi_variable(efi_variable_t *var,
+ unsigned int free_number)
+{
+ efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+ char buffer[16];
+ unsigned char *optional_data=NULL;
+ unsigned long load_option_size = 0, opt_data_size=0;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /* VariableName needs to be BootXXXX */
+ sprintf(buffer, "Boot%04x", free_number);
+
+ efichar_from_char(var->VariableName, buffer, 1024);
+
+ memcpy(&(var->VendorGuid), &guid, sizeof(guid));
+ var->Attributes =
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+
+ /* Set Data[] and DataSize */
+
+ load_option_size = make_linux_load_option(var->Data);
+
+ if (!load_option_size) return 0;
+
+ /* Set OptionalData (passed as binary to the called app) */
+ optional_data = var->Data + load_option_size;
+ opt_data_size = append_extra_args(optional_data,
+ sizeof(var->Data) - load_option_size);
+ var->DataSize = load_option_size + opt_data_size;
+ return var->DataSize;
+}
--- /dev/null
+/*
+ efichar.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+
+ Best as I can tell, efi_char16_t characters are unicode characters,
+ but are encoded in little-endian UCS-2
+ http://www.cl.cam.ac.uk/~mgk25/unicode.html.
+ libunicode expects characters to be encoded in UTF-8, so I can't use that.
+ Therefore, we need a UCS-2 library.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "efi.h"
+#include "efichar.h"
+
+int
+efichar_char_strcmp(const char *s1, const efi_char16_t *s2)
+{
+ int i, rc;
+ char *buffer;
+ int s2_len = efichar_strlen(s2, -1);
+
+ buffer = malloc(s2_len+1);
+ if (!buffer) return -1;
+ memset(buffer, 0, s2_len+1);
+
+ for (i=0; i<(s2_len); i++) {
+ buffer[i] = s2[i] & 0xFF;
+ }
+ buffer[i] = '\0';
+ rc = strcmp(s1, buffer);
+ free(buffer);
+ return rc;
+}
+
+int
+efichar_strcmp(const efi_char16_t *s1, const efi_char16_t *s2)
+{
+ int i;
+ int s1_len = efichar_strlen(s1, -1);
+ int s2_len = efichar_strlen(s2, -1);
+
+
+ for (i=0; i < s1_len && i < s2_len; i++) {
+ if (s1[i] < s2[i]) return -1;
+ if (s1[i] > s2[i]) return 1;
+
+ }
+ /* Hit the end of one string */
+ if (i == s1_len && i != s2_len) return -1;
+ if (i != s1_len && i == s2_len) return 1;
+ return 0;
+}
+
+unsigned long
+efichar_from_char(efi_char16_t *dest, const char *src, size_t dest_len)
+{
+ int i, src_len = strlen(src);
+ for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
+ dest[i] = src[i];
+ }
+ dest[i] = 0;
+ return i * sizeof(*dest);
+}
+
+unsigned long
+efichar_to_char(char *dest, const efi_char16_t *src, size_t dest_len)
+{
+ int i, src_len = efichar_strlen(src, -1);
+ for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
+ dest[i] = src[i];
+ }
+ dest[i] = 0;
+ return i;
+}
+
+int
+efichar_strlen(const efi_char16_t *p, int max)
+{
+ int len=0;
+ const efi_char16_t *start = p;
+
+ if (!p || !*p) return 0;
+
+ while ((max < 0 || p - start < max) && *(p+len))
+ {
+ ++len;
+ }
+ return len;
+}
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+int
+efichar_strncpy(efi_char16_t *dest, const efi_char16_t *src, int max)
+{
+ int i;
+ int src_len = efichar_strlen(src, max);
+
+ for (i=0; i < MIN(max,src_len); i++)
+ {
+ dest[i] = src[i];
+ }
+ dest[i] = 0;
+ return i;
+}
+
+int
+efichar_strsize(const efi_char16_t *p)
+{
+ return (efichar_strlen(p, -1) + 1) * sizeof(efi_char16_t);
+}
--- /dev/null
+/*
+ gpt.[ch]
+
+ Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+*/
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <asm/byteorder.h>
+#include "crc32.h"
+#include "disk.h"
+#include "gpt.h"
+#include "efibootmgr.h"
+
+#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+#define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
+
+struct blkdev_ioctl_param {
+ unsigned int block;
+ size_t content_length;
+ char * block_contents;
+};
+
+/**
+ * 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 (parsed < 3) return 0;
+ if (major > 2) return 1;
+ if (major == 2 && minor > 5) return 1;
+ if (major == 2 && minor == 5 && patch >= 4) return 1;
+ if (major == 2 && minor == 4 && patch >= 18) return 1;
+ return 0;
+}
+
+
+/************************************************************
+ * _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) 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 *aligned;
+ void *unaligned;
+
+ if (bytes % sector_size)
+ return EINVAL;
+
+ unaligned = malloc(bytes+sector_size-1);
+ aligned = (void *)
+ (((unsigned long)unaligned + sector_size - 1) &
+ ~(unsigned long)(sector_size-1));
+ memset(aligned, 0, bytes);
+
+
+ lseek(fd, offset, SEEK_SET);
+ bytesread = read(fd, aligned, bytes);
+ memcpy(buffer, aligned, bytesread);
+
+ /* 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) {
+ /*
+ printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
+ __le64_to_cpu((*gpt)->signature), GUID_PT_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) {
+ // printf( "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) {
+ // printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", __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)) {
+ // printf("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 (__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",
+ __le64_to_cpu(pgpt->my_lba),
+ __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",
+ __le64_to_cpu(pgpt->alternate_lba),
+ __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",
+ __le64_to_cpu(pgpt->first_usable_lba),
+ __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",
+ __le64_to_cpu(pgpt->last_usable_lba),
+ __le64_to_cpu(agpt->last_usable_lba));
+ error_found++;
+ }
+ if (efi_guidcmp(pgpt->disk_guid, agpt->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",
+ __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",
+ __le64_to_cpu(agpt->my_lba), lastlba);
+ error_found++;
+ }
+
+ if (error_found)
+ fprintf(stderr,
+ "GPT: Use GNU Parted to correct GPT errors.\n");
+ return;
+}
+
+/**
+ * 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 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;
+ if (!gpt || !ptes)
+ return 0;
+
+ 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 && !opts.forcegpt) {
+ fprintf(stderr,
+ " Warning: Disk has a valid GPT signature "
+ "but invalid PMBR.\n"
+ " Assuming this disk is *not* a GPT disk anymore.\n"
+ " Use gpt kernel option to override. "
+ "Use GNU Parted to correct disk.\n");
+ goto fail;
+ }
+
+ /* Would fail due to bad PMBR, but force GPT anyhow */
+ if ((good_pgpt || good_agpt) && !good_pmbr && opts.forcegpt) {
+ 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 || opts.forcegpt)) {
+ *gpt = pgpt;
+ *ptes = pptes;
+ if (agpt) { free(agpt); agpt = NULL; }
+ if (aptes) { free(aptes); aptes = NULL; }
+ if (!good_agpt) {
+ fprintf(stderr,
+ "Alternate GPT is invalid, "
+ "using primary GPT.\n");
+ }
+ return 1;
+ }
+ else if (good_agpt && (good_pmbr || opts.forcegpt)) {
+ *gpt = agpt;
+ *ptes = aptes;
+ if (pgpt) { free(pgpt); pgpt = NULL; }
+ if (pptes) { free(pptes); pptes = NULL; }
+ fprintf(stderr,
+ "Primary GPT is invalid, using alternate GPT.\n");
+ return 1;
+ }
+
+ fail:
+ if (pgpt) { free(pgpt); pgpt=NULL; }
+ if (agpt) { free(agpt); agpt=NULL; }
+ if (pptes) { free(pptes); pptes=NULL; }
+ if (aptes) { free(aptes); aptes=NULL; }
+ *gpt = NULL;
+ *ptes = NULL;
+ return 0;
+}
+
+
+/************************************************************
+ * 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
+gpt_disk_get_partition_info(int fd,
+ uint32_t num,
+ uint64_t * start, uint64_t * size,
+ char *signature,
+ uint8_t * mbr_type, uint8_t * signature_type)
+{
+ gpt_header *gpt = NULL;
+ gpt_entry *ptes = NULL, *p;
+
+ if (!find_valid_gpt(fd, &gpt, &ptes))
+ return 1;
+
+ *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 {
+ *start = 0;
+ *size = last_lba(fd) + 1;
+ memcpy(signature, &gpt->disk_guid, sizeof (gpt->disk_guid));
+ }
+ return 0;
+}
+
+/*
+ * 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:
+ */
--- /dev/null
+CFLAGS += -Isrc/lib
+
+CLEANLIST += src/lib/*.o
--- /dev/null
+/*
+ scsi_ioctls.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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 <stdio.h>
+#include <sys/pci.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "scsi_ioctls.h"
+
+int
+idlun_to_components (Scsi_Idlun *idlun,
+ unsigned char *host,
+ unsigned char *channel,
+ unsigned char *id,
+ unsigned char *lun)
+{
+ if (!idlun || !host || !channel || !id || !lun) return 1;
+
+ *host = (idlun->dev_id >> 24) & 0xFF;
+ *channel = (idlun->dev_id >> 16) & 0xFF;
+ *id = (idlun->dev_id ) & 0xFF;
+ *lun = (idlun->dev_id >> 8) & 0xFF;
+ return 0;
+}
+
+
+inline int
+get_scsi_idlun(int fd, Scsi_Idlun *idlun)
+{
+ return ioctl(fd, SCSI_IOCTL_GET_IDLUN, idlun);
+}
+
+inline int
+get_scsi_pci(int fd, char *slot_name)
+{
+ return ioctl(fd, SCSI_IOCTL_GET_PCI, slot_name);
+}
+
+
+
+#ifdef SCSI_IOCTLS_EXE
+static void
+usage(char **argv)
+{
+ printf("Usage: %s /dev/sdX where sdX is a SCSI device node.\n",
+ argv[0]);
+}
+
+int main(int argc, char **argv)
+{
+ Scsi_Idlun idlun;
+ char slot_name[8];
+ int fd = 0, rc = 0;
+
+ memset(&idlun, 0, sizeof(idlun));
+
+ if (argc < 2) {usage(argv); exit(1);}
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror("Unable to open file");
+ exit(1);
+ }
+
+ rc = get_scsi_pci(fd, slot_name);
+ if (rc) {
+ perror("Unable to get_scsi_pci()");
+ }
+ rc = get_scsi_idlun(fd, &idlun);
+ if (rc) {
+ perror("Unable to get_scsi_idlun()");
+ }
+
+ printf("Device: %s\n", argv[1]);
+ printf("PCI: %s\n", slot_name);
+
+ printf("SCSI: host %d channel %d id %d lun %d, unique ID %x\n",
+ (idlun.dev_id >> 24) & 0xFF, // host
+ (idlun.dev_id >> 16) & 0xFF, // channel
+ idlun.dev_id & 0xFF, // id
+ (idlun.dev_id >> 8) & 0xFF, // lun
+ idlun.host_unique_id);
+
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ unparse_path.[ch]
+
+ Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+ 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
+ */
+
+/* For PRIx64 */
+#define __STDC_FORMAT_MACROS
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "efi.h"
+#include "unparse_path.h"
+#include "efichar.h"
+
+
+
+
+void
+dump_raw_data(void *data, uint64_t length)
+{
+ char buffer1[80], buffer2[80], *b1, *b2, c;
+ unsigned char *p = data;
+ unsigned long column=0;
+ uint64_t length_printed = 0;
+ const char maxcolumn = 16;
+ while (length_printed < length) {
+ b1 = buffer1;
+ b2 = buffer2;
+ for (column = 0;
+ column < maxcolumn && length_printed < length;
+ column ++) {
+ b1 += sprintf(b1, "%02x ",(unsigned int) *p);
+ if (*p < 32 || *p > 126) c = '.';
+ else c = *p;
+ b2 += sprintf(b2, "%c", c);
+ p++;
+ length_printed++;
+ }
+ /* pad out the line */
+ for (; column < maxcolumn; column++)
+ {
+ b1 += sprintf(b1, " ");
+ b2 += sprintf(b2, " ");
+ }
+
+ printf("%s\t%s\n", buffer1, buffer2);
+ }
+}
+
+
+
+unsigned long
+unparse_raw(char *buffer, uint8_t *p, uint64_t length)
+{
+ uint64_t i; unsigned char c;
+ char *q = buffer;
+ for (i=0; i<length; i++) {
+ c = p[i];
+ //if (c < 32 || c > 127) c = '.';
+ q += sprintf(q, "%02x", c);
+ }
+ return q - buffer;
+}
+
+unsigned long
+unparse_raw_text(char *buffer, uint8_t *p, uint64_t length)
+{
+ uint64_t i; unsigned char c;
+ char *q = buffer;
+ for (i=0; i<length; i++) {
+ c = p[i];
+ if (c < 32 || c > 127) c = '.';
+ q += sprintf(q, "%c", c);
+ }
+ return q - buffer;
+}
+
+static int
+unparse_ipv4_port(char *buffer, uint32_t ipaddr, uint16_t port)
+{
+ unsigned char *ip;
+// ipaddr = nltoh(ipaddr);
+// port = nstoh(port);
+ ip = (unsigned char *)&ipaddr;
+ return sprintf(buffer, "%hhu.%hhu.%hhu.%hhu:%hu",
+ ip[0], ip[1], ip[2], ip[3],
+ port);
+}
+
+
+static int
+unparse_acpi_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+ ACPI_DEVICE_PATH *acpi = (ACPI_DEVICE_PATH *)path;
+
+ switch (path->subtype) {
+ case 1:
+ return sprintf(buffer, "ACPI(%x,%x)", acpi->_HID, acpi->_UID);
+ break;
+ default:
+ return unparse_raw(buffer, (uint8_t *)path, path->length);
+ break;
+ }
+ return 0;
+}
+
+static int
+unparse_vendor_path(char *buffer, VENDOR_DEVICE_PATH *path)
+{
+ char text_guid[40], *p = buffer, *q = (uint8_t *)path + 20;
+ efi_guid_unparse(&path->vendor_guid, text_guid);
+ p += sprintf(p, "Vendor(%s,", text_guid);
+ p += unparse_raw(p, q, path->length - 20);
+ p += sprintf(p, ")");
+ return p - buffer;
+}
+
+static int
+unparse_hardware_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+ PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)path;
+ PCCARD_DEVICE_PATH *pccard = (PCCARD_DEVICE_PATH *)path;
+ MEMORY_MAPPED_DEVICE_PATH *mm = (MEMORY_MAPPED_DEVICE_PATH *)path;
+ CONTROLLER_DEVICE_PATH *ctlr = (CONTROLLER_DEVICE_PATH *)path;
+
+ switch (path->subtype) {
+ case 1:
+ return sprintf(buffer, "PCI(%x,%x)",
+ pci->device, pci->function);
+ break;
+ case 2:
+ return sprintf(buffer, "PCCARD(%x)", pccard->socket);
+ break;
+ case 3:
+ return sprintf(buffer, "MM(%x,%" PRIx64 ",%" PRIx64 ")",
+ mm->memory_type,
+ mm->start, mm->end);
+ break;
+ case 4:
+ return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
+ break;
+
+ case 5:
+ return sprintf(buffer, "Controller(%x)", ctlr->controller);
+ break;
+
+ default:
+ return unparse_raw(buffer, (uint8_t *)path, path->length);
+ }
+ return 0;
+}
+
+
+static int
+unparse_messaging_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+ ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)path;
+ SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)path;
+ FIBRE_CHANNEL_DEVICE_PATH *fc = (FIBRE_CHANNEL_DEVICE_PATH *)path;
+ I1394_DEVICE_PATH *i1394 = (I1394_DEVICE_PATH *)path;
+ USB_DEVICE_PATH *usb = (USB_DEVICE_PATH *)path;
+ MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)path;
+ USB_CLASS_DEVICE_PATH *usbclass = (USB_CLASS_DEVICE_PATH *)path;
+ I2O_DEVICE_PATH *i2o = (I2O_DEVICE_PATH *)path;
+ IPv4_DEVICE_PATH *ipv4 = (IPv4_DEVICE_PATH *)path;
+/* IPv6_DEVICE_PATH *ipv6 = (IPv6_DEVICE_PATH *)path; */
+ char *p = buffer;
+
+ switch (path->subtype) {
+ case 1:
+ return sprintf(buffer, "ATAPI(%x,%x,%x)",
+ atapi->primary_secondary,
+ atapi->slave_master, atapi->lun);
+ break;
+ case 2:
+ return sprintf(buffer, "SCSI(%x,%x)", scsi->id, scsi->lun);
+ break;
+
+ case 3:
+ return sprintf(buffer, "FC(%" PRIx64 ",%" PRIx64 ")", fc->wwn, fc->lun);
+ break;
+ case 4:
+ return sprintf(buffer, "1394(%" PRIx64 ")", i1394->guid);
+ break;
+ case 5:
+ return sprintf(buffer, "USB(%x,%x)", usb->port, usb->endpoint);
+ break;
+ case 6:
+ return sprintf(buffer, "I2O(%x)", i2o->tid);
+ break;
+ case 11:
+ p += sprintf(p, "MAC(");
+ p += unparse_raw(p, mac->macaddr, 6);
+ p += sprintf(p, ",%hhx)", mac->iftype);
+ return (int) (p - buffer);
+ break;
+ case 12:
+ p += sprintf(p, "IPv4(");
+ p += unparse_ipv4_port(p, ipv4->local_ip, ipv4->local_port);
+ p += sprintf(p, "<->");
+ p += unparse_ipv4_port(p, ipv4->remote_ip, ipv4->remote_port);
+ p += sprintf(p, ",%hx, %hhx", ipv4->protocol, ipv4->static_addr);
+ return (int) (p - buffer);
+ break;
+
+ case 15:
+ return sprintf(buffer, "USBClass(%hx,%hx,%hhx,%hhx,%hhx)",
+ usbclass->vendor, usbclass->product,
+ usbclass->class, usbclass->subclass,
+ usbclass->protocol);
+ break;
+ default:
+ return unparse_raw(buffer, (uint8_t *)path, path->length);
+ break;
+ }
+ return 0;
+}
+
+static int
+unparse_media_hard_drive_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+ HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *)path;
+ char text_uuid[40], *sig=text_uuid;
+
+ switch (hd->signature_type) {
+ case 0x00:
+ sprintf(sig, "None");
+ break;
+ case 0x01:
+ sprintf(sig, "%08x", *(uint32_t *)hd->signature);
+ break;
+ case 0x02: /* GPT */
+ efi_guid_unparse((efi_guid_t *)hd->signature, sig);
+ break;
+ default:
+ break;
+ }
+
+ return sprintf(buffer, "HD(%x,%" PRIx64 ",%" PRIx64 ",%s)",
+ hd->part_num, hd->start, hd->size, sig);
+}
+
+
+
+static int
+unparse_media_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+
+ CDROM_DEVICE_PATH *cdrom = (CDROM_DEVICE_PATH *)path;
+ MEDIA_PROTOCOL_DEVICE_PATH *media = (MEDIA_PROTOCOL_DEVICE_PATH *)path;
+ FILE_PATH_DEVICE_PATH *file = (FILE_PATH_DEVICE_PATH *)path;
+ char text_guid[40], *p = buffer;
+ char file_name[80];
+ memset(file_name, 0, sizeof(file_name));
+
+ switch (path->subtype) {
+ case 1:
+ return unparse_media_hard_drive_path(buffer, path);
+ break;
+ case 2:
+ return sprintf(buffer, "CD-ROM(%x,%" PRIx64 ",%" PRIx64 ")",
+ cdrom->boot_entry, cdrom->start, cdrom->size);
+ break;
+ case 3:
+ return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path);
+ break;
+ case 4:
+ efichar_to_char(file_name, file->path_name, 80);
+ return sprintf(p, "File(%s)", file_name);
+ break;
+ case 5:
+ efi_guid_unparse(&media->guid, text_guid);
+ return sprintf(buffer, "Media(%s)", text_guid);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+unparse_bios_path(char *buffer, EFI_DEVICE_PATH *path)
+{
+ BIOS_BOOT_SPEC_DEVICE_PATH *bios = (BIOS_BOOT_SPEC_DEVICE_PATH *)path;
+ char *p = buffer, *q = (uint8_t *)path + 8;
+ p += sprintf(p, "BIOS(%x,%x,",
+ bios->device_type, bios->status_flag);
+ p += unparse_raw(p, q, path->length - 8);
+ p += sprintf(p, ")");
+ return p - buffer;
+}
+
+
+uint64_t
+unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize)
+{
+ uint16_t parsed_length = 0;
+ char *p = buffer;
+ int exit_now = 0;
+
+ while (parsed_length < pathsize && !exit_now) {
+ switch (path->type) {
+ case 0x01:
+ p += unparse_hardware_path(p, path);
+ break;
+ case 0x02:
+ p += unparse_acpi_path(p, path);
+ break;
+ case 0x03:
+ p += unparse_messaging_path(p, path);
+ break;
+ case 0x04:
+ p += unparse_media_path(p, path);
+ break;
+ case 0x05:
+ p += unparse_bios_path(p, path);
+ break;
+ case 0x7F:
+ exit_now = 1;
+ break;
+ case 0xFF:
+ exit_now = 1;
+ break;
+ default:
+ printf("\nwierd path");
+ dump_raw_data(path, 4);
+ break;
+ }
+// p += sprintf(p, "\\");
+ parsed_length += path->length;
+ path = (EFI_DEVICE_PATH *) ((uint8_t *)path + path->length);
+ }
+
+ return p - buffer;
+}
+
+
+#if 0
+static void
+unparse_var(efi_variable_t *var)
+{
+ char buffer[1024];
+ memset(buffer, 0, sizeof(buffer));
+
+ unparse_path(buffer, (EFI_DEVICE_PATH *)var->Data, var->DataSize);
+ printf("%s\n", buffer);
+}
+
+static int
+compare_hardware_path_pci(EFI_DEVICE_PATH *path,
+ int device, int func)
+{
+ uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
+ uint8_t path_device, path_func;
+
+ switch (path->subtype) {
+ case 1:
+ /* PCI */
+ path_func = *(uint8_t *)p;
+ path_device = *(uint8_t *)(p+1);
+
+ return !(path_func == func && path_device == device);
+
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int
+compare_hardware_path_scsi(EFI_DEVICE_PATH *path, int id, int lun)
+{
+ uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
+ uint16_t path_id, path_lun;
+
+ switch (path->subtype) {
+ case 2:
+ /* SCSI */
+ path_id = *(uint16_t *)p;
+ path_lun = *(uint16_t *)(p+2);
+
+ return !(path_id == id && path_lun == lun);
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int
+compare_hardware_path_acpi(EFI_DEVICE_PATH *path, int bus)
+{
+ uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data);
+ uint32_t _HID, _UID;
+
+ switch (path->subtype) {
+ case 1:
+ /* ACPI */
+ _HID = *(uint32_t *)p;
+ _UID = *(uint32_t *)(p+4);
+
+ /* FIXME: Need to convert _HID and _UID to bus number */
+
+ return 0;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int
+compare_media_path_harddrive(EFI_DEVICE_PATH *path, uint32_t num,
+ uint64_t start, uint64_t size)
+{
+ HARDDRIVE_DEVICE_PATH *p = (HARDDRIVE_DEVICE_PATH *)path;
+
+
+ switch (path->subtype) {
+ case 1:
+ /* Hard Drive */
+ return !(p->part_num == num
+ && p->start == start
+ && p->size == size);
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+
+
+int
+compare_pci_scsi_disk_blk(efi_variable_t *var,
+ int bus, int device, int func,
+ int host, int channel, int id, int lun,
+ uint64_t start, uint64_t size)
+{
+
+ EFI_DEVICE_PATH *path = (EFI_DEVICE_PATH *) var->Data;
+ uint64_t parsed_length = 0;
+ int exit_now = 0;
+ int rc = 0;
+
+ while (parsed_length < var->DataSize && !exit_now && !rc) {
+ switch (path->type) {
+ case 0x01:
+ /* Hardware (PCI) */
+ rc = compare_hardware_path_pci(path, device, func);
+ break;
+ case 0x02:
+ /* ACPI */
+ rc = compare_hardware_path_acpi(path, bus);
+ break;
+ case 0x03:
+ /* Messaging (SCSI) */
+ rc = compare_messaging_path_scsi(path, id, lun);
+ break;
+ case 0x04:
+ /* Media (Hard Drive) */
+ rc = compare_media_path_harddrive(path, 0,
+ start, size);
+ break;
+ case 0x7F:
+ case 0xFF:
+ exit_now = 1;
+ break;
+ case 0x05: /* BIOS */
+ default:
+ break;
+ }
+ parsed_length += path->length;
+ path = var->Data + parsed_length;
+ }
+ return rc;
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef UNPARSE_PATH
+static void
+usage(void)
+{
+ printf("Usage: dumppath filename\n");
+ printf("\t where filename is a blkXXXX EFI variable from /proc/efi/vars\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd = 0;
+ ssize_t size;
+ efi_variable_t var;
+
+ if (argc == 1) {
+ usage();
+ exit(-1);
+ }
+
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror("Failed to open file.");
+ exit(-1);
+ }
+ size = read(fd, &var, sizeof(var));
+ if (size == -1 || size < sizeof(var)) {
+ perror("Failed to read file.");
+ close(fd);
+ exit(-1);
+ }
+ unparse_var(&var);
+
+
+ return 0;
+}
+#endif
--- /dev/null
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
+.\" Please send any bug reports, improvements, comments, patches,
+.\" etc. to Steve Cheng <steve@ggi-project.org>.
+.TH "EFIBOOTMGR" "8" "11 August 2003" "" ""
+.SH NAME
+efibootmgr \- manipulate the EFI Boot Manager
+.SH SYNOPSIS
+
+\fBefibootmgr\fR [ \fB-a\fR] [ \fB-A\fR] [ \fB-b \fIXXXX\fB\fR] [ \fB-B \fIXXXX\fB\fR] [ \fB-c\fR] [ \fB-d \fIDISK\fB\fR] [ \fB-e \fI1|3|-1\fB\fR] [ \fB-E \fINUM\fB\fR] [ \fB-g\fR] [ \fB-H \fIXXXX\fB\fR] [ \fB-i \fINAME\fB\fR] [ \fB-l \fINAME\fB\fR] [ \fB-L \fILABEL\fB\fR] [ \fB-n \fIXXXX\fB\fR] [ \fB-N\fR] [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR] [ \fB-O\fR] [ \fB-p \fIPART\fB\fR] [ \fB-q\fR] [ \fB-t\fR] [ \fB-u\fR] [ \fB-U \fIXXXX\fB\fR] [ \fB-v\fR] [ \fB-V\fR] [ \fB-w\fR]
+
+.SH "DESCRIPTION"
+.PP
+\fBefibootmgr\fR is a userspace application used to
+modify the Intel Extensible Firmware Interface (EFI) Boot Manager. This
+application can create and destroy boot entries, change the boot order,
+change the next running boot option, and more.
+.PP
+Details on the EFI Boot Manager are available from the EFI
+Specification, v1.02 or later, available from:
+ <URL:http://developer.intel.com>
+.sp
+.RS
+.B "Note:"
+efibootmgr requires that the kernel support access to EFI
+non-volatile variables (through \fI/proc/efi/vars\fR).
+\fBmodprobe efivars\fR should do the trick.
+.RE
+.SH "OPTIONS"
+.PP
+The following is a list of options accepted by efibootmgr:
+.TP
+\fB-a | --active\fR
+Sets bootnum active
+.TP
+\fB-A | --inactive\fR
+Sets bootnum inactive
+.TP
+\fB-b | --bootnum \fIXXXX\fB\fR
+Modify Boot\fIXXXX\fR (hex)
+.TP
+\fB-B | --delete-bootnum\fR
+Delete bootnum (hex)
+.TP
+\fB-c | --create\fR
+Create new variable bootnum and add to bootorder
+.TP
+\fB-d | --disk \fIDISK\fB\fR
+The disk containing the loader (defaults to
+\fI/dev/sda\fR)
+.TP
+\fB-e | --edd \fI1|3|-1\fB\fR
+Force EDD 1.0 or 3.0 creation variables, or guess.
+.TP
+\fB-E | --device \fINUM\fB\fR
+EDD 1.0 device number (defaults to 0x80)
+.TP
+\fB-g | --gpt\fR
+Force disk with invalid PMBR to be treated as GPT
+.TP
+\fB-H | --acpi_hid \fIXXXX\fB\fR
+set the ACPI HID (used with \fB-i\fR)
+.TP
+\fB-i | --iface \fINAME\fB\fR
+create a netboot entry for the named interface
+.TP
+\fB-l | --loader \fINAME\fB\fR
+Specify a loader (defaults to \fI\\\\elilo.efi\fR)
+.TP
+\fB-L | --label \fILABEL\fB\fR
+Boot manager display label (defaults to "Linux")
+.TP
+\fB-n | --bootnext \fIXXXX\fB\fR
+Set BootNext to XXXX (hex)
+.TP
+\fB-N | --delete-bootnext\fR
+Delete BootNext
+.TP
+\fB-o | --bootorder \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR
+Explicitly set BootOrder (hex)
+.TP
+\fB-O | --delete-bootorder\fR
+Delete BootOrder
+.TP
+\fB-p | --part \fIPART\fB\fR
+Partition number containing the bootloader (defaults to 1)
+.TP
+\fB-q | --quiet\fR
+Quiet mode - supresses output.
+.TP
+\fB-t | --test \fIfilename\fB\fR
+Don't write to NVRAM, write to \fIfilename\fR.
+.TP
+\fB-u | --unicode | --UCS-2 \fR
+pass extra command line arguments as UCS-2 (default is
+ASCII)
+.TP
+\fB-U | --acpi_uid \fIXXXX\fB\fR
+set the ACPI UID (used with \fB-i\fR)
+.TP
+\fB-v | --verbose\fR
+Verbose mode - prints additional information
+.TP
+\fB-V | --version\fR
+Just print version string and exit.
+.TP
+\fB-w | --write-signature\fR
+write unique signature to the MBR if needed
+.SH "EXAMPLES"
+.TP 1.
+.SS "DISPLAYING THE CURRENT SETTINGS (MUST BE ROOT)."
+.PP
+[root@localhost ~]# efibootmgr
+BootCurrent: 0004
+BootNext: 0003
+BootOrder: 0004,0000,0001,0002,0003
+Boot0000* Diskette Drive(device:0)
+Boot0001* CD-ROM Drive(device:FF)
+Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)
+Boot0003* PXE Boot: MAC(00D0B7C15D91)
+Boot0004* Linux
+.PP
+This shows:
+.RS
+.TP 0.2i
+\(bu
+BootCurrent - the boot entry used to start the currently
+running system
+.TP 0.2i
+\(bu
+BootOrder - the boot order as would appear in the boot manager.
+The boot manager tries to boot the first active entry in this
+list. If unsuccessful, it tries the next entry, and so on.
+.TP 0.2i
+\(bu
+BootNext - the boot entry which is scheduled to be run on next
+boot. This supercedes BootOrder for one boot only, and is
+deleted by the boot manager after first use. This allows you
+to change the next boot behavior without changing BootOrder.
+.TP 0.2i
+\(bu
+Five boot entries (0000 - 0004), along with the active/inactive
+flag (* means active) and the name displayed on the screen.
+.RE
+.TP 2.
+.SS "CREATING A NEW BOOT OPTION"
+.PP
+An OS installer would call \fBefibootmgr -c\fR.
+This assumes that \fI/boot/efi\fR is your EFI System
+Partition, and is mounted at \fI/dev/sda1\fR. This
+creates a new boot option, called "Linux", and puts it at the top of
+the boot order list. Options may be passed to modify the default
+behavior. The default OS Loader is \fIelilo.efi\fR.
+.TP 3.
+.SS "CHANGING THE BOOT ORDER"
+.PP
+Assuming the configuration in Example #1,
+\fBefibootmgr -o 3,4\fR could be called to specify
+PXE boot first, then Linux boot.
+.TP 4.
+.SS "CHANGING THE BOOT ORDER FOR THE NEXT BOOT ONLY"
+.PP
+Assuming the configuration in Example #1,
+\fBefibootmgr -n 4\fR could be called to specify
+that the Linux entry be taken on next boot.
+.TP 5.
+.SS "DELETING A BOOT OPTION"
+.PP
+Assuming the configuration in Example #1,
+\fBefibootmgr -b 4 -B\fR could be called to delete
+entry 4 and remove it from the BootOrder.
+.TP 6.
+.SS "CREATING NETWORK BOOT ENTRIES"
+.PP
+A system administrator wants to create a boot option to network
+boot (PXE). Unfortunately, this requires knowing a little more
+information about your system than can be easily found by
+efibootmgr, so you've got to pass additional information - the ACPI
+HID and UID values. These can generally be found by using the EFI
+Boot Manager (in the EFI environment) to create a network boot
+entry, then using efibootmgr to print it verbosely. Here's one example:
+Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \\
+ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0)
+In this case, the ACPI HID is "0A0341d0" and the UID is "0".
+For the zx2000 gigE, the HID is "222F" and the UID is "500".
+For the rx2000 gigE, the HID is "0002" and the UID is "100".
+You create the boot entry with:
+\fBefibootmgr -c -i eth0 -H 222F -U 500 -L netboot\fR
+.SH "BUGS"
+.PP
+Please direct any bugs, features, patches, etc. to Matt Domsch
+<Matt_Domsch@dell.com>.
+.SH "AUTHOR"
+.PP
+This man page was generated by dann frazier <dannf@debian.org> for the
+Debian GNU/Linux operating system, but may be used by others.
+.SH "SEE ALSO"
+.PP
+elilo(1)
--- /dev/null
+
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+
+<!-- This manpage was compiled by dann frazier <email>dannf@debian.org</email>,
+ and was based on an example constructed by Colin Watson
+ <email>cjwatson@debian.org</email>, which was based on a man page template
+ provided by Tom Christiansen <email>tchrist@jhereg.perl.com</email>
+ and a DocBook man page example by Craig Small
+ <email>csmall@debian.org</email>.
+
+ The content was mostly taken from the efibootmgr README file in the
+ Debian package, which was written by Matt Domsch
+ <email>Matt_Domsch@dell.com</email>.
+ -->
+
+ <!-- Fill in the various UPPER CASE things here. -->
+ <!ENTITY manfirstname "<firstname>dann</firstname>">
+ <!ENTITY mansurname "<surname>frazier</surname>">
+ <!-- Please adjust the date whenever revising the manpage. -->
+ <!ENTITY mandate "<date>2003-08-11</date>">
+ <!-- SECTION should be 1-8, maybe with subsection. Other parameters are
+ allowed: see man(7), man(1). -->
+ <!ENTITY mansection "<manvolnum>8</manvolnum>">
+ <!ENTITY manemail "<email>dannf@debian.org</email>">
+ <!ENTITY manusername "dann frazier">
+ <!ENTITY manucpackage "<refentrytitle>EFIBOOTMGR</refentrytitle>">
+ <!ENTITY manpackage "efibootmgr">
+]>
+
+<refentry>
+ <refentryinfo>
+ <address>
+ &manemail;
+ </address>
+ <author>
+ &manfirstname;
+ &mansurname;
+ </author>
+ <copyright>
+ <year>2002, 2003</year>
+ <holder>&manusername;</holder>
+ </copyright>
+ &mandate;
+ </refentryinfo>
+ <refmeta>
+ &manucpackage;
+
+ &mansection;
+ </refmeta>
+ <refnamediv>
+ <refname>&manpackage;</refname>
+
+ <refpurpose>manipulate the EFI Boot Manager</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>&manpackage;</command>
+
+ <arg>-a</arg>
+ <arg>-A</arg>
+ <arg>-b <replaceable>XXXX</replaceable></arg>
+ <arg>-B <replaceable>XXXX</replaceable></arg>
+ <arg>-c</arg>
+ <arg>-d <replaceable>DISK</replaceable></arg>
+ <arg>-e <replaceable>1|3|-1</replaceable></arg>
+ <arg>-E <replaceable>NUM</replaceable></arg>
+ <arg>-g</arg>
+ <arg>-H <replaceable>XXXX</replaceable></arg>
+ <arg>-i <replaceable>NAME</replaceable></arg>
+ <arg>-l <replaceable>NAME</replaceable></arg>
+ <arg>-L <replaceable>LABEL</replaceable></arg>
+ <arg>-n <replaceable>XXXX</replaceable></arg>
+ <arg>-N</arg>
+ <arg rep="repeat">-o <replaceable>XXXX</replaceable>,<replaceable>YYYY</replaceable>,<replaceable>ZZZZ</replaceable></arg>
+ <arg>-O</arg>
+ <arg>-p <replaceable>PART</replaceable></arg>
+ <arg>-q</arg>
+ <arg>-t</arg>
+ <arg>-u</arg>
+ <arg>-U <replaceable>XXXX</replaceable></arg>
+ <arg>-v</arg>
+ <arg>-V</arg>
+ <arg>-w</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><command>&manpackage;</command> is a userspace application used to
+ modify the Intel Extensible Firmware Interface (EFI) Boot Manager. This
+ application can create and destroy boot entries, change the boot order,
+ change the next running boot option, and more.</para>
+
+ <para>
+ Details on the EFI Boot Manager are available from the EFI
+ Specification, v1.02 or later, available from:
+ <ulink url="http://developer.intel.com"></ulink>
+ </para>
+
+ <note>
+ <para>
+ &manpackage; requires that the kernel support access to EFI
+ non-volatile variables (through <filename>/proc/efi/vars</filename>).
+ <command>modprobe efivars</command> should do the trick.
+ </para>
+ </note>
+ </refsect1>
+ <refsect1>
+ <title>OPTIONS</title>
+
+ <para>The following is a list of options accepted by &manpackage;:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-a</option> | <option>--active</option></term>
+ <listitem>
+ <para>Sets bootnum active</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-A</option> | <option>--inactive</option></term>
+ <listitem>
+ <para>Sets bootnum inactive</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-b</option> | <option>--bootnum</option> <replaceable>XXXX</replaceable></term>
+ <listitem>
+ <para>Modify Boot<replaceable>XXXX</replaceable> (hex)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-B</option> | <option>--delete-bootnum</option></term>
+ <listitem>
+ <para>Delete bootnum (hex)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-c</option> | <option>--create</option></term>
+ <listitem>
+ <para>Create new variable bootnum and add to bootorder</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-d</option> | <option>--disk</option> <replaceable>DISK</replaceable></term>
+ <listitem>
+ <para>The disk containing the loader (defaults to
+ <filename>/dev/sda</filename>)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-e</option> | <option>--edd</option> <replaceable>1|3|-1</replaceable></term>
+ <listitem>
+ <para>Force EDD 1.0 or 3.0 creation variables, or guess.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-E</option> | <option>--device</option> <replaceable>NUM</replaceable></term>
+ <listitem>
+ <para>EDD 1.0 device number (defaults to 0x80)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-g</option> | <option>--gpt</option></term>
+ <listitem>
+ <para>Force disk with invalid PMBR to be treated as GPT</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-H</option> | <option>--acpi_hid</option> <replaceable>XXXX</replaceable></term>
+ <listitem>
+ <para>set the ACPI HID (used with <option>-i</option>)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-i</option> | <option>--iface</option> <replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>create a netboot entry for the named interface</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-l</option> | <option>--loader</option> <replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Specify a loader (defaults to <filename>\\elilo.efi</filename>)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-L</option> | <option>--label</option> <replaceable>LABEL</replaceable></term>
+ <listitem>
+ <para>Boot manager display label (defaults to "Linux")</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-n</option> | <option>--bootnext</option> <replaceable>XXXX</replaceable></term>
+ <listitem>
+ <para>Set BootNext to XXXX (hex)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-N</option> | <option>--delete-bootnext</option></term>
+ <listitem>
+ <para>Delete BootNext</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-o</option> | <option>--bootorder</option> <replaceable>XXXX</replaceable>,<replaceable>YYYY</replaceable>,<replaceable>ZZZZ</replaceable></term>
+ <listitem>
+ <para>Explicitly set BootOrder (hex)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-O</option> | <option>--delete-bootorder</option></term>
+ <listitem>
+ <para>Delete BootOrder</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-p</option> | <option>--part</option> <replaceable>PART</replaceable></term>
+ <listitem>
+ <para>Partition number containing the bootloader (defaults to 1)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-q</option> | <option>--quiet</option></term>
+ <listitem>
+ <para>Quiet mode - supresses output.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-t</option> | <option>--test</option> <replaceable>filename</replaceable></term>
+ <listitem>
+ <para>Don't write to NVRAM, write to <replaceable>filename</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-u</option> | <option>--unicode</option> | <option>--UCS-2</option> </term>
+ <listitem>
+ <para>pass extra command line arguments as UCS-2 (default is
+ ASCII)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-U</option> | <option>--acpi_uid</option> <replaceable>XXXX</replaceable></term>
+ <listitem>
+ <para>set the ACPI UID (used with <option>-i</option>)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-v</option> | <option>--verbose</option></term>
+ <listitem>
+ <para>Verbose mode - prints additional information</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-V</option> | <option>--version</option></term>
+ <listitem>
+ <para>Just print version string and exit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-w</option> | <option>--write-signature</option></term>
+ <listitem>
+ <para>write unique signature to the MBR if needed</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>EXAMPLES</title>
+ <orderedlist>
+ <listitem>
+ <example>
+ <title>Displaying the current settings (must be root).</title>
+
+ <para>
+ <computeroutput>
+ [root@localhost ~]# efibootmgr
+ BootCurrent: 0004
+ BootNext: 0003
+ BootOrder: 0004,0000,0001,0002,0003
+ Boot0000* Diskette Drive(device:0)
+ Boot0001* CD-ROM Drive(device:FF)
+ Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)
+ Boot0003* PXE Boot: MAC(00D0B7C15D91)
+ Boot0004* Linux
+ </computeroutput>
+ </para>
+ <para>This shows:</para>
+ <itemizedlist>
+ <listitem>
+ <para>BootCurrent - the boot entry used to start the currently
+ running system</para>
+ </listitem>
+ <listitem>
+ <para>
+ BootOrder - the boot order as would appear in the boot manager.
+ The boot manager tries to boot the first active entry in this
+ list. If unsuccessful, it tries the next entry, and so on.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ BootNext - the boot entry which is scheduled to be run on next
+ boot. This supercedes BootOrder for one boot only, and is
+ deleted by the boot manager after first use. This allows you
+ to change the next boot behavior without changing BootOrder.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Five boot entries (0000 - 0004), along with the active/inactive
+ flag (* means active) and the name displayed on the screen.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </example>
+ </listitem>
+ <listitem>
+ <example>
+ <title>Creating a new boot option</title>
+ <para>
+ An OS installer would call <command>&manpackage; -c</command>.
+ This assumes that <filename>/boot/efi</filename> is your EFI System
+ Partition, and is mounted at <filename>/dev/sda1</filename>. This
+ creates a new boot option, called "Linux", and puts it at the top of
+ the boot order list. Options may be passed to modify the default
+ behavior. The default OS Loader is <filename>elilo.efi</filename>.
+ </para>
+ </example>
+ </listitem>
+ <listitem>
+ <example>
+ <title>Changing the Boot Order</title>
+ <para>
+ Assuming the configuration in Example #1,
+ <command>&manpackage; -o 3,4</command> could be called to specify
+ PXE boot first, then Linux boot.
+ </para>
+ </example>
+ </listitem>
+ <listitem>
+ <example>
+ <title>Changing the Boot Order for the Next Boot Only</title>
+ <para>
+ Assuming the configuration in Example #1,
+ <command>&manpackage; -n 4</command> could be called to specify
+ that the Linux entry be taken on next boot.
+ </para>
+ </example>
+ </listitem>
+ <listitem>
+ <example>
+ <title>Deleting a boot option</title>
+ <para>
+ Assuming the configuration in Example #1,
+ <command>&manpackage; -b 4 -B</command> could be called to delete
+ entry 4 and remove it from the BootOrder.
+ </para>
+ </example>
+ </listitem>
+ <listitem>
+ <example>
+ <title>Creating network boot entries</title>
+ <para>
+ A system administrator wants to create a boot option to network
+ boot (PXE). Unfortunately, this requires knowing a little more
+ information about your system than can be easily found by
+ efibootmgr, so you've got to pass additional information - the ACPI
+ HID and UID values. These can generally be found by using the EFI
+ Boot Manager (in the EFI environment) to create a network boot
+ entry, then using efibootmgr to print it verbosely. Here's one example:
+ <computeroutput>
+ Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \
+ ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0)
+
+ In this case, the ACPI HID is "0A0341d0" and the UID is "0".
+ For the zx2000 gigE, the HID is "222F" and the UID is "500".
+ For the rx2000 gigE, the HID is "0002" and the UID is "100".
+ </computeroutput>
+ You create the boot entry with:
+ <command>efibootmgr -c -i eth0 -H 222F -U 500 -L netboot</command>
+ </para>
+ </example>
+ </listitem>
+ </orderedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>BUGS</title>
+
+ <para>Please direct any bugs, features, patches, etc. to Matt Domsch
+ <email>Matt_Domsch@dell.com</email>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>AUTHOR</title>
+ <para>This man page was generated by dann frazier &manemail; for the
+ Debian GNU/Linux operating system, but may be used by others.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>SEE ALSO</title>
+
+ <para>elilo(1)</para>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
--- /dev/null
+#add our stuff first... our children need to wait for us to finish
+INSTALLDEPS += bindir_LIST
+
+ MODULES := src/efibootmgr src/lib src/include
+ include $(patsubst %,%/module.mk,$(MODULES))
+
+
+# Common stuff to copy into the common directories
+# Note that the stuff below bindir_LIST is all on one line...
+bindir_LIST:
+ @if [ ! -z "$(bindir_TARGETS)" ]; then \
+ echo "R-M-: %attr(0755,root,root) $(BINDIR)" ;\
+ for file in $(bindir_TARGETS) ;\
+ do \
+ echo "-C--: $(BUILDDIR)/$$file $(BINDIR)/" ;\
+ echo "R---: %attr(0755,root,root) $(BINDIR)/`basename $$file`" ;\
+ done ;\
+ echo ;\
+ fi
+
+
--- /dev/null
+#!/usr/bin/perl -w
+
+#Pragmas
+ use strict;
+
+#Parse command line...
+ my ($copy, $link);
+ my $type = shift @ARGV;
+ if( $type =~ /^copy$/i ) {
+ $copy = 1;
+ }
+ if( $type =~ /^link$/i ) {
+ $link = 1;
+ }
+
+#Main program loop
+ open (RPMOUT, "> filelist-rpm") or die;
+
+ while( <> ){
+ chomp;
+ s/^\s*//;
+ s/\s*$//;
+ s/\s*#.*$//;
+ next if m/^$/;
+
+ my $line = $_;
+ ($line =~ m/^R...:(.*)/) && print RPMOUT $1 . "\n";
+ ($line =~ m/^..M.:(.*)/) && MakeDir( $1 );
+ ($line =~ m/^.C..:(.*)/) && ($copy) && CopyFile( $1 );
+ ($line =~ m/^.C..:(.*)/) && ($link) && LinkFile( $1 );
+ ($line =~ m/^R...:(.*)/) && ChangeAttrs( $1 );
+ }
+
+sub CopyFile {
+ my ($src, $dst) = ParseCLine( shift );
+
+ if( -d $dst ) {
+ $src =~ m|^.*/(.*)$|;
+ my $file = $1;
+ $dst .= "/" if ! ($dst=~m|/$|);
+ $dst .= $file;
+ }
+ if( -e $dst ) {
+ unlink $dst;
+ }
+
+ open INPUT, "<", $src or goto out1;
+ open OUTPUT, ">", $dst or goto out2;
+ while(<INPUT>){ print OUTPUT $_ }
+ close OUTPUT;
+
+ print "Installed File: $dst\n";
+out2:
+ close INPUT;
+out1:
+ return;
+}
+
+sub LinkFile {
+ my ($src, $dst) = ParseCLine( shift );
+ if( -d $dst ) {
+ $src =~ m|^.*/(.*)$|;
+ my $file = $1;
+ $dst .= "/" if ! ($dst=~m|/$|);
+ $dst .= $file;
+ }
+ if( -e $dst ) {
+ unlink $dst;
+ }
+ symlink $src, $dst
+ or warn "Linking $src to $dst failed $!\n";
+ print "Installed File: $dst\n";
+}
+
+sub ParseCLine {
+ my $line = shift;
+ $line =~ s/^\s*//;
+ $line =~ s/\s*$//;
+ $line =~ m/^(.*?)\s+(.*?)$/;
+ return ($1, $2);
+}
+
+sub ParseRLine {
+ my $line = shift;
+ my @directives;
+ my @retval;
+ $line =~ s/^\s*//;
+ $line =~ s/\s*$//;
+ my @words = split( /\s+/, $line );
+ foreach my $word (@words) {
+ if( $word =~ /^\%(.*)/ ) {
+ push @directives, $word;
+ } else {
+ push @retval, $word;
+ }
+ }
+ return \@retval, \@directives;
+}
+
+sub MakeDir {
+ #R-M-: %attr(0755,root,ali) /opt/ali
+ my $line = shift;
+
+ #$line =~ m/\%attr\((.{1,5}),(\w+),(\w+)\)\s+(.*)/;
+ my ($file_ref, $directive_ref) = ParseRLine( $line );
+
+ my $dir = $file_ref->[0];
+
+ if( ! -d $dir ) {
+ mkdir $dir
+ or warn "Make Dir: -->$dir<-- failed $!\n";
+ }
+ print "Made Dir: $dir\n";
+}
+
+sub GetUID {
+ my $name = shift;
+ my (undef, undef, $uid, undef) = getpwnam( $name ) ;
+ $uid = defined($uid) ? $uid : -1;
+ return $uid;
+}
+
+sub GetGID {
+ my $name = shift;
+ my (undef, undef, $gid, undef) = getgrnam( $name ) ;
+ $gid = defined($gid) ? $gid : -1;
+ return $gid;
+}
+
+sub ChangeAttrs {
+ my $line = shift;
+
+ my ($file_ref, $directive_ref) = ParseRLine( $line );
+ my ($attr) = grep { /^\%attr/ } @$directive_ref;
+ $attr =~ m/\%attr\((.{1,5}),(\w+),(\w+)\)/;
+ my $perms = $1;
+ my $owner = $2;
+ my $group = $3;
+ my $file = $file_ref->[0];
+
+ my $uid = GetUID($owner);
+ my $gid = GetGID($group);
+
+ chown $uid, $gid, $file;
+ chmod oct($perms), $file;
+}
+
+
+
+
+
+
+
+
+
+