Imported Upstream version 0.4.2 upstream/0.4.2
authorBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:06:16 +0000 (23:06 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:06:16 +0000 (23:06 -0600)
36 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
doc/ChangeLog [new file with mode: 0644]
doc/TODO [new file with mode: 0644]
efibootmgr.spec [new file with mode: 0644]
filelist-rpm [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/efibootmgr/Makefile [new file with mode: 0644]
src/efibootmgr/efibootmgr.c [new file with mode: 0644]
src/efibootmgr/module.mk [new file with mode: 0644]
src/include/crc32.h [new file with mode: 0644]
src/include/disk.h [new file with mode: 0644]
src/include/efi.h [new file with mode: 0644]
src/include/efibootmgr.h [new file with mode: 0644]
src/include/efichar.h [new file with mode: 0644]
src/include/gpt.h [new file with mode: 0644]
src/include/list.h [new file with mode: 0644]
src/include/module.mk [new file with mode: 0644]
src/include/scsi_ioctls.h [new file with mode: 0644]
src/include/unparse_path.h [new file with mode: 0644]
src/lib/Makefile [new file with mode: 0644]
src/lib/crc32.c [new file with mode: 0644]
src/lib/disk.c [new file with mode: 0644]
src/lib/efi.c [new file with mode: 0644]
src/lib/efichar.c [new file with mode: 0644]
src/lib/gpt.c [new file with mode: 0644]
src/lib/module.mk [new file with mode: 0644]
src/lib/scsi_ioctls.c [new file with mode: 0644]
src/lib/unparse_path.c [new file with mode: 0644]
src/man/man8/efibootmgr.8 [new file with mode: 0644]
src/man/man8/efibootmgr.8.docbook [new file with mode: 0644]
src/module.mk [new file with mode: 0644]
tools/install.pl [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..3059aa5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,15 @@
+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
+
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   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.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..d61b0be
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,5 @@
+Running 'make' builds the file src/efibootmgr/efibootmgr.
+efibootmgr should be placed into /usr/sbin/.
+
+
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..67d275a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,78 @@
+  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
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1fb38fd
--- /dev/null
+++ b/README
@@ -0,0 +1,112 @@
+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>.
+
+
+
+
+
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644 (file)
index 0000000..5daad8f
--- /dev/null
@@ -0,0 +1,165 @@
+* 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
diff --git a/doc/TODO b/doc/TODO
new file mode 100644 (file)
index 0000000..0c8d016
--- /dev/null
+++ b/doc/TODO
@@ -0,0 +1 @@
+* MS-DOS style extended partitions
diff --git a/efibootmgr.spec b/efibootmgr.spec
new file mode 100644 (file)
index 0000000..45627e9
--- /dev/null
@@ -0,0 +1,36 @@
+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
diff --git a/filelist-rpm b/filelist-rpm
new file mode 100644 (file)
index 0000000..07cd431
--- /dev/null
@@ -0,0 +1,3 @@
+ %attr(0755,root,root) /usr/sbin
+ %attr(0755,root,root) /usr/sbin/efibootmgr
+ %attr(0444,root,root) /usr/share/man/man8/efibootmgr.8
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..6615d46
--- /dev/null
@@ -0,0 +1,2 @@
+%:
+       +make -C ../ $*
diff --git a/src/efibootmgr/Makefile b/src/efibootmgr/Makefile
new file mode 100644 (file)
index 0000000..6615d46
--- /dev/null
@@ -0,0 +1,2 @@
+%:
+       +make -C ../ $*
diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c
new file mode 100644 (file)
index 0000000..4184143
--- /dev/null
@@ -0,0 +1,1052 @@
+/*
+  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;
+}
+
diff --git a/src/efibootmgr/module.mk b/src/efibootmgr/module.mk
new file mode 100644 (file)
index 0000000..7764641
--- /dev/null
@@ -0,0 +1,22 @@
+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)
diff --git a/src/include/crc32.h b/src/include/crc32.h
new file mode 100644 (file)
index 0000000..f35f9e4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    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 */
diff --git a/src/include/disk.h b/src/include/disk.h
new file mode 100644 (file)
index 0000000..eb93d10
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  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
diff --git a/src/include/efi.h b/src/include/efi.h
new file mode 100644 (file)
index 0000000..b53187e
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+  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 */
diff --git a/src/include/efibootmgr.h b/src/include/efibootmgr.h
new file mode 100644 (file)
index 0000000..163793f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  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
diff --git a/src/include/efichar.h b/src/include/efichar.h
new file mode 100644 (file)
index 0000000..9962707
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  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
diff --git a/src/include/gpt.h b/src/include/gpt.h
new file mode 100644 (file)
index 0000000..8944885
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+    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:
+ */
diff --git a/src/include/list.h b/src/include/list.h
new file mode 100644 (file)
index 0000000..a306043
--- /dev/null
@@ -0,0 +1,169 @@
+/* 
+   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
diff --git a/src/include/module.mk b/src/include/module.mk
new file mode 100644 (file)
index 0000000..071d6df
--- /dev/null
@@ -0,0 +1 @@
+CFLAGS += -Isrc/include
diff --git a/src/include/scsi_ioctls.h b/src/include/scsi_ioctls.h
new file mode 100644 (file)
index 0000000..558824f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  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
diff --git a/src/include/unparse_path.h b/src/include/unparse_path.h
new file mode 100644 (file)
index 0000000..0324bfe
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  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
diff --git a/src/lib/Makefile b/src/lib/Makefile
new file mode 100644 (file)
index 0000000..6615d46
--- /dev/null
@@ -0,0 +1,2 @@
+%:
+       +make -C ../ $*
diff --git a/src/lib/crc32.c b/src/lib/crc32.c
new file mode 100644 (file)
index 0000000..e9086b1
--- /dev/null
@@ -0,0 +1,124 @@
+/* 
+ * 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;
+}
diff --git a/src/lib/disk.c b/src/lib/disk.c
new file mode 100644 (file)
index 0000000..6581040
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+  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, &sector_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
diff --git a/src/lib/efi.c b/src/lib/efi.c
new file mode 100644 (file)
index 0000000..0ab0339
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+  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;
+}
diff --git a/src/lib/efichar.c b/src/lib/efichar.c
new file mode 100644 (file)
index 0000000..831c759
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+  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);
+}
diff --git a/src/lib/gpt.c b/src/lib/gpt.c
new file mode 100644 (file)
index 0000000..e4985d1
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+    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, &sectors);
+        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:
+ */
diff --git a/src/lib/module.mk b/src/lib/module.mk
new file mode 100644 (file)
index 0000000..a0c62b7
--- /dev/null
@@ -0,0 +1,3 @@
+CFLAGS += -Isrc/lib
+
+CLEANLIST += src/lib/*.o
diff --git a/src/lib/scsi_ioctls.c b/src/lib/scsi_ioctls.c
new file mode 100644 (file)
index 0000000..c19cef3
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+  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
diff --git a/src/lib/unparse_path.c b/src/lib/unparse_path.c
new file mode 100644 (file)
index 0000000..3c28f1c
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+  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
diff --git a/src/man/man8/efibootmgr.8 b/src/man/man8/efibootmgr.8
new file mode 100644 (file)
index 0000000..a2f6d49
--- /dev/null
@@ -0,0 +1,200 @@
+.\" 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)
diff --git a/src/man/man8/efibootmgr.8.docbook b/src/man/man8/efibootmgr.8.docbook
new file mode 100644 (file)
index 0000000..81c65b9
--- /dev/null
@@ -0,0 +1,426 @@
+
+<!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:
+-->
diff --git a/src/module.mk b/src/module.mk
new file mode 100644 (file)
index 0000000..f56f5b4
--- /dev/null
@@ -0,0 +1,21 @@
+#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
+
+
diff --git a/tools/install.pl b/tools/install.pl
new file mode 100755 (executable)
index 0000000..57c7c00
--- /dev/null
@@ -0,0 +1,156 @@
+#!/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;
+}
+
+
+
+
+
+
+
+
+
+