Browse Source

Import upstream version 8

Nathaniel McCallum 6 years ago
commit
5fef5770e8
30 changed files with 45840 additions and 0 deletions
  1. 502 0
      COPYING
  2. 32 0
      Makefile.am
  3. 1499 0
      Makefile.in
  4. 10528 0
      aclocal.m4
  5. 348 0
      compile
  6. 1476 0
      config.guess
  7. 1836 0
      config.sub
  8. 14482 0
      configure
  9. 37 0
      configure.ac
  10. 82 0
      crc32c.c
  11. 26 0
      crc32c.h
  12. 791 0
      depcomp
  13. 501 0
      install-sh
  14. 503 0
      libluksmeta.c
  15. 11147 0
      ltmain.sh
  16. 232 0
      luksmeta.8
  17. 527 0
      luksmeta.c
  18. 131 0
      luksmeta.h
  19. 11 0
      luksmeta.pc.in
  20. 215 0
      missing
  21. 29 0
      test-crc32c.c
  22. 148 0
      test-driver
  23. 37 0
      test-lm-assumptions.c
  24. 138 0
      test-lm-big.c
  25. 116 0
      test-lm-init.c
  26. 79 0
      test-lm-one.c
  27. 110 0
      test-lm-two.c
  28. 52 0
      test-luksmeta
  29. 176 0
      test.c
  30. 49 0
      test.h

+ 502 - 0
COPYING

@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU Lesser General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU Lesser General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU Lesser General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU Lesser General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!

+ 32 - 0
Makefile.am

@@ -0,0 +1,32 @@
+AM_CFLAGS = @LUKSMETA_CFLAGS@ @cryptsetup_CFLAGS@
+
+noinst_LTLIBRARIES = libcrc32c.la
+libcrc32c_la_SOURCES = crc32c.c crc32c.h
+
+include_HEADERS = luksmeta.h
+lib_LTLIBRARIES = libluksmeta.la
+libluksmeta_la_LDFLAGS = -export-symbols-regex '^luksmeta_'
+libluksmeta_la_LIBADD = libcrc32c.la @cryptsetup_LIBS@
+
+bin_PROGRAMS = luksmeta
+luksmeta_LDADD = libluksmeta.la @cryptsetup_LIBS@
+
+man8_MANS = luksmeta.8
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = luksmeta.pc
+
+check_LTLIBRARIES = libtest.la
+libtest_la_SOURCES = test.c test.h
+
+check_PROGRAMS = test-crc32c test-lm-assumptions test-lm-init test-lm-one test-lm-two test-lm-big
+test_crc32c_LDADD = libcrc32c.la
+test_lm_assumptions_LDADD = libtest.la libluksmeta.la @cryptsetup_LIBS@
+test_lm_init_LDADD = libtest.la libluksmeta.la @cryptsetup_LIBS@
+test_lm_one_LDADD = libtest.la libluksmeta.la @cryptsetup_LIBS@
+test_lm_two_LDADD = libtest.la libluksmeta.la @cryptsetup_LIBS@
+test_lm_big_LDADD = libtest.la libluksmeta.la @cryptsetup_LIBS@
+
+EXTRA_DIST = $(man8_MANS) test-luksmeta
+TESTS = $(check_PROGRAMS) test-luksmeta
+

File diff suppressed because it is too large
+ 1499 - 0
Makefile.in


File diff suppressed because it is too large
+ 10528 - 0
aclocal.m4


+ 348 - 0
compile

@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+  icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:

File diff suppressed because it is too large
+ 1476 - 0
config.guess


File diff suppressed because it is too large
+ 1836 - 0
config.sub


File diff suppressed because it is too large
+ 14482 - 0
configure


+ 37 - 0
configure.ac

@@ -0,0 +1,37 @@
+AC_PREREQ(2.59)
+AC_INIT(luksmeta, 8)
+AC_CANONICAL_SYSTEM
+AC_PROG_CC_C99
+
+AM_INIT_AUTOMAKE([subdir-objects foreign no-dist-gzip dist-bzip2 parallel-tests])
+AM_SILENT_RULES([yes])
+AM_PROG_CC_C_O
+
+LT_INIT([disable-static])
+
+PKG_PROG_PKG_CONFIG([0.25])
+PKG_CHECK_MODULES([cryptsetup], [libcryptsetup >= 1.5.1])
+
+LUKSMETA_CFLAGS="\
+-Wall \
+-Wextra \
+-Werror \
+-Wstrict-aliasing \
+-Wchar-subscripts \
+-Wformat-security \
+-Wmissing-declarations \
+-Wmissing-prototypes \
+-Wnested-externs \
+-Wpointer-arith \
+-Wshadow \
+-Wsign-compare \
+-Wstrict-prototypes \
+-Wtype-limits \
+-Wunused-function \
+-Wno-missing-field-initializers \
+-Wno-unused-parameter \
+"
+AC_SUBST([LUKSMETA_CFLAGS])
+
+AC_CONFIG_FILES([luksmeta.pc Makefile])
+AC_OUTPUT

+ 82 - 0
crc32c.c

@@ -0,0 +1,82 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "crc32c.h"
+
+static const uint32_t table[] = {
+    0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,
+    0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+    0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,
+    0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+    0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,
+    0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+    0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,
+    0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+    0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,
+    0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+    0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,
+    0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+    0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,
+    0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+    0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,
+    0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+    0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,
+    0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+    0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,
+    0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+    0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,
+    0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+    0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,
+    0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+    0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,
+    0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+    0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,
+    0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+    0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,
+    0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+    0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,
+    0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+    0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,
+    0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+    0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,
+    0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+    0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,
+    0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+    0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,
+    0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+    0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,
+    0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+    0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
+};
+
+uint32_t
+crc32c(uint32_t crc, const void *buf, size_t len)
+{
+    const uint8_t *tmp = buf;
+
+    crc ^= 0xffffffffUL;
+
+    while (len--)
+        crc = table[(crc ^ *tmp++) & 0xff] ^ (crc >> 8);
+
+    crc ^= 0xffffffffUL;
+
+    return crc;
+}
+

+ 26 - 0
crc32c.h

@@ -0,0 +1,26 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint32_t
+crc32c(uint32_t crc, const void *buf, size_t len);

+ 791 - 0
depcomp

@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:

+ 501 - 0
install-sh

@@ -0,0 +1,501 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2016-01-11.22; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab='	'
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
+
+    -o) chowncmd="$chownprog $2"
+        shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
+
+    -T) is_target_a_directory=never;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --) shift
+        break;;
+
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      dstdir=`dirname "$dst"`
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            if (umask $mkdir_umask &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/d" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
+      esac
+
+      oIFS=$IFS
+      IFS=/
+      set -f
+      set fnord $dstdir
+      shift
+      set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       set +f &&
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:

+ 503 - 0
libluksmeta.c

@@ -0,0 +1,503 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "crc32c.h"
+#include "luksmeta.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ALIGN(s, up) (((s) + (up ? 4095 : 0)) & ~4095ULL)
+#define LUKS_NSLOTS 8
+#define LM_VERSION 1
+
+static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
+
+typedef struct __attribute__((packed)) {
+    luksmeta_uuid_t uuid;
+    uint32_t offset;   /* Bytes from the start of the hole */
+    uint32_t length;   /* Bytes */
+    uint32_t crc32c;
+    uint32_t _reserved; /* Reserved */
+} lm_slot_t;
+
+typedef struct __attribute__((packed)) {
+    uint8_t magic[sizeof(LM_MAGIC)];
+    uint32_t version;
+    uint32_t crc32c;
+    lm_slot_t slots[LUKS_NSLOTS];
+} lm_t;
+
+static bool
+uuid_is_zero(const luksmeta_uuid_t uuid)
+{
+    for (size_t i = 0; i < sizeof(luksmeta_uuid_t); i++) {
+        if (uuid[i] != 0)
+            return false;
+    }
+
+    return true;
+}
+
+static inline uint32_t
+checksum(lm_t lm)
+{
+    lm.crc32c = 0;
+    return crc32c(0, &lm, sizeof(lm_t));
+}
+
+static inline bool
+overlap(const lm_t *lm, uint32_t start, size_t end)
+{
+    for (int i = 0; i < LUKS_NSLOTS; i++) {
+        const lm_slot_t *s = &lm->slots[i];
+        uint32_t e = s->offset + s->length;
+
+        if (start <= s->offset && s->offset < end)
+            return true;
+
+        if (start < e && e <= end)
+            return true;
+    }
+
+    return false;
+}
+
+static inline uint32_t
+find_gap(const lm_t *lm, uint32_t length, size_t size)
+{
+    size = ALIGN(size, true);
+
+    for (uint32_t off = ALIGN(1, true); off < length; off += ALIGN(1, true)) {
+        if (!overlap(lm, off, off + size))
+            return off;
+    }
+
+    return 0;
+}
+
+static int
+find_unused_slot(struct crypt_device *cd, const lm_t *lm)
+{
+    for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
+        if (crypt_keyslot_status(cd, slot) == CRYPT_SLOT_INACTIVE &&
+            uuid_is_zero(lm->slots[slot].uuid))
+            return slot;
+    }
+
+    return -1;
+}
+
+static inline ssize_t
+readall(int fd, void *data, size_t size)
+{
+    uint8_t *tmp = data;
+
+    for (ssize_t r, t = 0; t < (ssize_t) size; t += r) {
+        r = read(fd, &tmp[t], size - t);
+        if (r < 0 && errno != EAGAIN)
+            return -errno;
+    }
+
+    return size;
+}
+
+static inline ssize_t
+writeall(int fd, const void *buf, size_t size)
+{
+    const uint8_t *tmp = buf;
+
+    for (ssize_t r, t = 0; t < (ssize_t) size; t += r) {
+        r = write(fd, &tmp[t], size - t);
+        if (r < 0) {
+            if (errno != EAGAIN)
+                return -errno;
+            r = 0;
+        }
+    }
+
+    return size;
+}
+
+/**
+ * Opens the device with the specified flags.
+ *
+ * The length parameter is set to the amount of space in the gap between the
+ * end of the last slot and the start of the encrypted data.
+ *
+ * The function returns either the file descriptor positioned to the start of
+ * the hole or a negative errno.
+ */
+static int
+open_hole(struct crypt_device *cd, int flags, uint32_t *length)
+{
+    const char *name = NULL;
+    const char *type = NULL;
+    uint64_t hole = 0;
+    uint64_t data = 0;
+    int fd = 0;
+    int r = 0;
+
+    type = crypt_get_type(cd);
+    if (!type || strcmp(CRYPT_LUKS1, type) != 0)
+        return -ENOTSUP;
+
+    data = crypt_get_data_offset(cd) * 512;
+    if (data < 4096)
+        return -ENOSPC;
+
+    for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
+        uint64_t off = 0;
+        uint64_t len = 0;
+
+        r = crypt_keyslot_area(cd, slot, &off, &len);
+        if (r < 0)
+            return r;
+
+        if (hole < off + len)
+            hole = ALIGN(off + len, true);
+    }
+
+    if (hole == 0)
+        return -ENOTSUP;
+
+    if (hole >= data)
+        return -ENOSPC;
+
+    name = crypt_get_device_name(cd);
+    if (!name)
+        return -ENOTSUP;
+
+    fd = open(name, flags);
+    if (fd < 0)
+        return -errno;
+
+    if (lseek(fd, hole, SEEK_SET) == -1) {
+        close(fd);
+        return -errno;
+    }
+
+    *length = ALIGN(data - hole, false);
+    return fd;
+}
+
+static int
+read_header(struct crypt_device *cd, int flags, uint32_t *length, lm_t *lm)
+{
+    uint32_t maxlen;
+    int fd = -1;
+    int r = 0;
+
+    fd = open_hole(cd, flags, length);
+    if (fd < 0)
+        return fd;
+
+    r = *length >= sizeof(lm_t) ? 0 : -ENOENT;
+    if (r < 0)
+        goto error;
+
+    r = readall(fd, lm, sizeof(lm_t));
+    if (r < 0)
+        goto error;
+
+    r = memcmp(LM_MAGIC, lm->magic, sizeof(LM_MAGIC)) == 0 ? 0 : -ENOENT;
+    if (r < 0)
+        goto error;
+
+    r = lm->version == htobe32(LM_VERSION) ? 0 : -ENOTSUP;
+    if (r < 0)
+        goto error;
+
+    lm->crc32c = be32toh(lm->crc32c);
+    r = checksum(*lm) == lm->crc32c ? 0 : -EINVAL;
+    if (r < 0)
+        goto error;
+
+    lm->version = be32toh(lm->version);
+
+    maxlen = *length - ALIGN(sizeof(lm_t), true);
+    for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
+        lm_slot_t *s = &lm->slots[slot];
+
+        s->offset = be32toh(s->offset);
+        s->length = be32toh(s->length);
+        s->crc32c = be32toh(s->crc32c);
+
+        if (!uuid_is_zero(s->uuid)) {
+            r = s->offset > sizeof(lm_t) ? 0 : -EINVAL;
+            if (r < 0)
+                goto error;
+
+            r = s->length <= maxlen ? 0 : -EINVAL;
+            if (r < 0)
+                goto error;
+        }
+    }
+
+    return fd;
+
+error:
+    close(fd);
+    return r;
+}
+
+static int
+write_header(int fd, lm_t lm)
+{
+    for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
+        lm.slots[slot].offset = htobe32(lm.slots[slot].offset);
+        lm.slots[slot].length = htobe32(lm.slots[slot].length);
+        lm.slots[slot].crc32c = htobe32(lm.slots[slot].crc32c);
+    }
+
+    memcpy(lm.magic, LM_MAGIC, sizeof(LM_MAGIC));
+    lm.version = htobe32(LM_VERSION);
+    lm.crc32c = htobe32(checksum(lm));
+    return writeall(fd, &lm, sizeof(lm));
+}
+
+int
+luksmeta_test(struct crypt_device *cd)
+{
+    int fd = -1;
+
+    fd = read_header(cd, O_RDONLY, &(uint32_t) {0}, &(lm_t) {});
+    if (fd >= 0) {
+        close(fd);
+        return 0;
+    }
+
+    return fd;
+}
+
+int
+luksmeta_nuke(struct crypt_device *cd)
+{
+    uint8_t zero[ALIGN(1, true)] = {};
+    uint32_t length = 0;
+    int fd = -1;
+    int r = 0;
+
+    fd = open_hole(cd, O_RDWR | O_SYNC, &length);
+    if (fd < 0)
+        return fd;
+
+    for (size_t i = 0; r >= 0 && i < length; i += sizeof(zero))
+        r = writeall(fd, zero, sizeof(zero));
+
+    close(fd);
+    return r < 0 ? r : 0;
+}
+
+int
+luksmeta_init(struct crypt_device *cd)
+{
+    uint32_t length = 0;
+    int fd = -1;
+    int r = 0;
+
+    r = luksmeta_test(cd);
+    if (r == 0)
+        return -EALREADY;
+    else if (r != -ENOENT && r != -EINVAL)
+        return r;
+
+    fd = open_hole(cd, O_RDWR | O_SYNC, &length);
+    if (fd < 0)
+        return fd;
+
+    if (length < ALIGN(sizeof(lm_t), true)) {
+        close(fd);
+        return -ENOSPC;
+    }
+
+    r = write_header(fd, (lm_t) {});
+    close(fd);
+    return r > 0 ? 0 : r;
+}
+
+int
+luksmeta_load(struct crypt_device *cd, int slot,
+              luksmeta_uuid_t uuid, void *buf, size_t size)
+{
+    uint32_t length = 0;
+    lm_slot_t *s = NULL;
+    lm_t lm = {};
+    int fd = -1;
+    int r = 0;
+
+    if (slot < 0 || slot >= LUKS_NSLOTS)
+        return -EBADSLT;
+    s = &lm.slots[slot];
+
+    fd = read_header(cd, O_RDONLY, &length, &lm);
+    if (fd < 0)
+        return fd;
+
+    r = uuid_is_zero(s->uuid) ? -ENODATA : 0;
+    if (r < 0)
+        goto error;
+
+    if (buf) {
+        r = size >= s->length ? 0 : -E2BIG;
+        if (r < 0)
+            goto error;
+
+        r = lseek(fd, s->offset - sizeof(lm), SEEK_CUR) == -1 ? -errno : 0;
+        if (r < 0)
+            goto error;
+
+        r = readall(fd, buf, s->length);
+        if (r < 0)
+            goto error;
+
+        r = crc32c(0, buf, s->length) == s->crc32c ? 0 : -EINVAL;
+        if (r < 0)
+            goto error;
+    }
+
+    memcpy(uuid, s->uuid, sizeof(luksmeta_uuid_t));
+    close(fd);
+    return s->length;
+
+error:
+    close(fd);
+    return r;
+}
+
+int
+luksmeta_save(struct crypt_device *cd, int slot,
+              const luksmeta_uuid_t uuid, const void *buf, size_t size)
+{
+    uint32_t length = 0;
+    lm_slot_t *s = NULL;
+    lm_t lm = {};
+    int fd = -1;
+    int r = 0;
+    off_t off;
+
+    if (uuid_is_zero(uuid))
+        return -EKEYREJECTED;
+
+    fd = read_header(cd, O_RDWR | O_SYNC, &length, &lm);
+    if (fd < 0)
+        return fd;
+
+    if (slot == CRYPT_ANY_SLOT)
+        slot = find_unused_slot(cd, &lm);
+
+    r = slot >= 0 && slot < LUKS_NSLOTS ? 0 : -EBADSLT;
+    if (r < 0)
+        goto error;
+    s = &lm.slots[slot];
+
+    r = uuid_is_zero(s->uuid) ? 0 : -EALREADY;
+    if (r < 0)
+        goto error;
+
+    s->offset = find_gap(&lm, length, size);
+    r = s->offset >= ALIGN(sizeof(lm), true) ? 0 : -ENOSPC;
+    if (r < 0)
+        goto error;
+
+    memcpy(s->uuid, uuid, sizeof(luksmeta_uuid_t));
+    s->length = size;
+    s->crc32c = crc32c(0, buf, size);
+
+    off = s->offset - sizeof(lm);
+    r = lseek(fd, off, SEEK_CUR) == -1 ? -errno : 0;
+    if (r < 0)
+        goto error;
+
+    r = writeall(fd, buf, size);
+    if (r < 0)
+        goto error;
+
+    off = s->offset + s->length;
+    r = lseek(fd, -off, SEEK_CUR) == -1 ? -errno : 0;
+    if (r < 0)
+        goto error;
+
+    r = write_header(fd, lm);
+
+error:
+    close(fd);
+    return r < 0 ? r : slot;
+}
+
+int
+luksmeta_wipe(struct crypt_device *cd, int slot, const luksmeta_uuid_t uuid)
+{
+    uint8_t *zero = NULL;
+    uint32_t length = 0;
+    lm_slot_t *s = NULL;
+    lm_t lm = {};
+    int fd = -1;
+    int r = 0;
+    off_t off;
+
+    if (slot < 0 || slot >= LUKS_NSLOTS)
+        return -EBADSLT;
+    s = &lm.slots[slot];
+
+    fd = read_header(cd, O_RDWR | O_SYNC, &length, &lm);
+    if (fd < 0)
+        return fd;
+
+    r = uuid_is_zero(s->uuid) ? -EALREADY : 0;
+    if (r < 0)
+        goto error;
+
+    if (uuid && memcmp(uuid, s->uuid, sizeof(luksmeta_uuid_t)) != 0) {
+        r = -EKEYREJECTED;
+        goto error;
+    }
+
+    off = s->offset - sizeof(lm_t);
+    r = lseek(fd, off, SEEK_CUR) == -1 ? -errno : 0;
+    if (r < 0)
+        goto error;
+
+    r = (zero = calloc(1, s->length)) ? 0 : -errno;
+    if (r < 0)
+        goto error;
+
+    r = writeall(fd, zero, s->length);
+    free(zero);
+    if (r < 0)
+        goto error;
+
+    off = s->offset + s->length;
+    r = lseek(fd, -off, SEEK_CUR) == -1 ? -errno : 0;
+    if (r < 0)
+        goto error;
+
+    memset(s, 0, sizeof(lm_slot_t));
+    r = write_header(fd, lm);
+
+error:
+    close(fd);
+    return r < 0 ? r : 0;
+}

File diff suppressed because it is too large
+ 11147 - 0
ltmain.sh


File diff suppressed because it is too large
+ 232 - 0
luksmeta.8


+ 527 - 0
luksmeta.c

@@ -0,0 +1,527 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "luksmeta.h"
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#define UUID_TMPL \
+    "%02hhx%02hhx%02hhx%02hhx-" \
+    "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-" \
+    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+
+#define UUID_ARGS(u) \
+    u[0x0], u[0x1], u[0x2], u[0x3], u[0x4], u[0x5], u[0x6], u[0x7], \
+    u[0x8], u[0x9], u[0xa], u[0xb], u[0xc], u[0xd], u[0xe], u[0xf]
+
+struct options {
+    const char *device;
+    luksmeta_uuid_t uuid;
+    bool have_uuid;
+    bool force;
+    bool nuke;
+    int slot;
+};
+
+static int
+cmd_test(const struct options *opts, struct crypt_device *cd)
+{
+    return luksmeta_test(cd) == 0 ? EX_OK : EX_OSFILE;
+}
+
+static int
+cmd_nuke(const struct options *opts, struct crypt_device *cd)
+{
+    int r = 0;
+
+    if (!opts->force) {
+        int c = 'X';
+
+        fprintf(stderr,
+                "You are about to erase all data in the LUKSMeta storage area.\n"
+                "A backup is advised before erasure is performed.\n\n");
+
+        while (!strchr("YyNn", c)) {
+            fprintf(stderr, "Do you wish to nuke %s? [yn] ",
+                    crypt_get_device_name(cd));
+            c = getc(stdin);
+        }
+
+        if (strchr("Nn", c))
+            return EX_NOPERM;
+    }
+
+    r = luksmeta_nuke(cd);
+    switch (r) {
+    case 0:
+        return EX_OK;
+
+    default:
+        fprintf(stderr, "Error while erasing device (%s): %s\n",
+                opts->device, strerror(-r));
+        return EX_OSERR;
+    }
+}
+
+static int
+cmd_init(const struct options *opts, struct crypt_device *cd)
+{
+    int r = 0;
+
+    if (!opts->force) {
+        int c = 'X';
+
+        fprintf(stderr,
+            "You are about to initialize a LUKS device for metadata storage.\n"
+            "Attempting to initialize it may result in data loss if data was\n"
+            "already written into the LUKS header gap in a different format.\n"
+            "A backup is advised before initialization is performed.\n\n");
+
+        while (!strchr("YyNn", c)) {
+            fprintf(stderr, "Do you wish to initialize %s? [yn] ",
+                    crypt_get_device_name(cd));
+            c = getc(stdin);
+        }
+
+        if (strchr("Nn", c))
+            return EX_NOPERM;
+    }
+
+    if (opts->nuke) {
+        struct options o = { .force = true, .device = opts->device };
+        r = cmd_nuke(&o, cd);
+        if (r != EX_OK)
+            return r;
+    }
+
+    r = luksmeta_init(cd);
+    switch (r) {
+    case 0: /* fallthrough */
+    case -EALREADY:
+        return EX_OK;
+
+    case -ENOSPC:
+        fprintf(stderr, "Insufficient space in the LUKS header (%s)\n",
+                opts->device);
+        return EX_CANTCREAT;
+
+    default:
+        fprintf(stderr, "Error while initializing device (%s): %s\n",
+                opts->device, strerror(-r));
+        return EX_OSERR;
+    }
+
+    return EX_OK;
+}
+
+static const char *
+status(struct crypt_device *cd, int keyslot)
+{
+    switch (crypt_keyslot_status(cd, keyslot)) {
+    case CRYPT_SLOT_INVALID: return "invalid";
+    case CRYPT_SLOT_INACTIVE: return "inactive";
+    case CRYPT_SLOT_ACTIVE: return "active";
+    case CRYPT_SLOT_ACTIVE_LAST: return "active";
+    default: return "unknown";
+    }
+}
+
+static int
+cmd_show(const struct options *opts, struct crypt_device *cd)
+{
+    luksmeta_uuid_t uuid = {};
+
+    for (int i = 0, r = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
+        if (opts->slot >= 0 && i != opts->slot)
+            continue;
+
+        r = luksmeta_load(cd, i, uuid, NULL, 0);
+        switch (r) {
+        case -EBADSLT:
+            fprintf(stderr, "Invalid slot (%d)\n", opts->slot);
+            return EX_USAGE;
+
+        case -ENOENT:
+            fprintf(stderr, "Device is not initialized (%s)\n",
+                    opts->device);
+            return EX_OSFILE;
+
+        case -EINVAL:
+            fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n",
+                    opts->device);
+            return EX_OSFILE;
+
+        case -ENODATA:
+            if (opts->slot < 0)
+                fprintf(stdout, "%d %8s %s\n", i, status(cd, i), "empty");
+            break;
+
+        default:
+            if (r < 0) {
+                fprintf(stderr, "%d %8s %s\n",
+                        i, status(cd, i), "unknown error");
+            } else {
+                if (opts->slot < 0)
+                    fprintf(stdout, "%d %8s ", i, status(cd, i));
+
+                fprintf(stdout, UUID_TMPL "\n", UUID_ARGS(uuid));
+            }
+            break;
+        }
+    }
+
+    return EX_OK;
+}
+
+static int
+cmd_save(const struct options *opts, struct crypt_device *cd)
+{
+    uint8_t *in = NULL;
+    size_t inl = 0;
+    int r = 0;
+
+    if (!opts->have_uuid) {
+        fprintf(stderr, "UUID required\n");
+        return EX_USAGE;
+    }
+
+    while (!feof(stdin)) {
+        uint8_t *tmp = NULL;
+
+        tmp = realloc(in, inl + 4096);
+        if (!tmp) {
+            fprintf(stderr, "Out of memory\n");
+            free(in);
+            return EX_OSERR;
+        }
+
+        in = tmp;
+        r = fread(&in[inl], 1, 4096, stdin);
+        inl += r;
+        if (r < 4096 && (ferror(stdin) || inl == 0)) {
+            fprintf(stderr, "Error reading from standard input\n");
+            free(in);
+            return EX_NOINPUT;
+        }
+    }
+
+    if (!in) {
+        fprintf(stderr, "No data on standard input\n");
+        return EX_NOINPUT;
+    }
+
+    r = luksmeta_save(cd, opts->slot, opts->uuid, in, inl);
+    memset(in, 0, inl);
+    free(in);
+    switch (r) {
+    case -ENOENT:
+        fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EINVAL:
+        fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EBADSLT:
+        fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
+        return EX_USAGE;
+
+    case -EKEYREJECTED:
+        fprintf(stderr, "The specified UUID is reserved (" UUID_TMPL ")\n",
+                UUID_ARGS(opts->uuid));
+        return EX_USAGE;
+
+    case -EALREADY:
+        fprintf(stderr, "Will not overwrite existing slot (%d)\n", opts->slot);
+        return EX_UNAVAILABLE;
+
+    case -ENOSPC:
+        fprintf(stderr, "Insufficient space in the LUKS header (%s)\n",
+                opts->device);
+        return EX_CANTCREAT;
+
+    default:
+        if (r < 0)
+            fprintf(stderr, "An unknown error occurred\n");
+        else if (opts->slot < 0)
+            fprintf(stdout, "%d\n", r);
+
+        return r < 0 ? EX_OSERR : EX_OK;
+    }
+}
+
+static int
+cmd_load(const struct options *opts, struct crypt_device *cd)
+{
+    luksmeta_uuid_t uuid = {};
+    int r = 0;
+
+    if (opts->slot < 0) {
+        fprintf(stderr, "Slot required\n");
+        return EX_USAGE;
+    }
+
+    r = luksmeta_load(cd, opts->slot, uuid, NULL, 0);
+    if (r >= 0) {
+        uint8_t *out = NULL;
+
+        if (opts->have_uuid && memcmp(opts->uuid, uuid, sizeof(uuid)) != 0) {
+            fprintf(stderr,
+                    "The given UUID does not match the slot UUID:\n"
+                    "UUID: " UUID_TMPL "\n"
+                    "SLOT: " UUID_TMPL "\n",
+                    UUID_ARGS(opts->uuid),
+                    UUID_ARGS(uuid));
+            return EX_DATAERR;
+        }
+
+        out = malloc(r);
+        if (!out) {
+            fprintf(stderr, "Out of memory!\n");
+            return EX_OSERR;
+        }
+
+        r = luksmeta_load(cd, opts->slot, uuid, out, r);
+        if (r >= 0) {
+            fwrite(out, 1, r, stdout);
+            memset(out, 0, r);
+        }
+
+        free(out);
+    }
+
+    switch (r) {
+    case -ENOENT:
+        fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EINVAL:
+        fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EBADSLT:
+        fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
+        return EX_USAGE;
+
+    case -ENODATA:
+        fprintf(stderr, "The specified slot is empty (%d)\n", opts->slot);
+        return EX_UNAVAILABLE;
+
+    default:
+        if (r < 0)
+            fprintf(stderr, "An unknown error occurred\n");
+
+        return r < 0 ? EX_OSERR : EX_OK;
+    }
+}
+
+static int
+cmd_wipe(const struct options *opts, struct crypt_device *cd)
+{
+    luksmeta_uuid_t uuid = {};
+    int r = 0;
+
+    if (opts->slot < 0) {
+        fprintf(stderr, "Slot required\n");
+        return EX_USAGE;
+    }
+
+    if (!opts->force) {
+        int c = 'X';
+
+        fprintf(stderr,
+            "You are about to wipe a slot. This operation is unrecoverable.\n"
+            "A backup is advised before proceeding.\n\n");
+
+        while (!strchr("YyNn", c)) {
+            fprintf(stderr, "Do you wish to erase slot %d on %s? [yn] ",
+                    opts->slot, crypt_get_device_name(cd));
+            c = getc(stdin);
+        }
+
+        if (strchr("Nn", c))
+            return EX_NOPERM;
+    }
+
+    r = luksmeta_wipe(cd, opts->slot, opts->have_uuid ? opts->uuid : NULL);
+    switch (r) {
+    case -EALREADY:
+        return EX_OK;
+
+    case -ENOENT:
+        fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EINVAL:
+        fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
+        return EX_OSFILE;
+
+    case -EBADSLT:
+        fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
+        return EX_USAGE;
+
+    case -EKEYREJECTED:
+        r = luksmeta_load(cd, opts->slot, uuid, NULL, 0);
+        if (r >= 0) {
+            fprintf(stderr,
+                    "The given UUID does not match the slot UUID:\n"
+                    "UUID: " UUID_TMPL "\n"
+                    "SLOT: " UUID_TMPL "\n",
+                    UUID_ARGS(opts->uuid),
+                    UUID_ARGS(uuid));
+        } else {
+            fprintf(stderr,
+                    "The given UUID does not match the slot UUID:\n"
+                    "UUID: " UUID_TMPL "\n"
+                    "SLOT: UNKNOWN\n",
+                    UUID_ARGS(opts->uuid));
+        }
+        return EX_DATAERR;
+
+    default:
+        if (r < 0)
+            fprintf(stderr, "An unknown error occurred\n");
+
+        return r < 0 ? EX_OSERR : EX_OK;
+    }
+}
+
+static const char *sopts = "hfnd:u:s:";
+static const struct option lopts[] = {
+    { "help",                      .val = 'h' },
+    { "nuke",   no_argument,       .val = 'n' },
+    { "force",  no_argument,       .val = 'f' },
+    { "device", required_argument, .val = 'd' },
+    { "uuid",   required_argument, .val = 'u' },
+    { "slot",   required_argument, .val = 's' },
+    {}
+};
+
+static const struct {
+    int (*func)(const struct options *opts, struct crypt_device *cd);
+    const char *name;
+} commands[] = {
+    { cmd_test, "test", },
+    { cmd_nuke, "nuke", },
+    { cmd_init, "init", },
+    { cmd_show, "show", },
+    { cmd_save, "save", },
+    { cmd_load, "load", },
+    { cmd_wipe, "wipe", },
+    {}
+};
+
+int
+main(int argc, char *argv[])
+{
+    struct options o = { .slot = CRYPT_ANY_SLOT };
+
+    for (int c; (c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1; ) {
+        switch (c) {
+        case 'h': goto usage;
+        case 'd': o.device = optarg; break;
+        case 'n': o.nuke = true; break;
+        case 'f': o.force = true; break;
+        case 'u':
+            if (sscanf(optarg, UUID_TMPL, UUID_ARGS(&o.uuid)) != 16) {
+                fprintf(stderr, "Invalid UUID (%s)\n", optarg);
+                return EX_USAGE;
+            }
+
+            o.have_uuid = true;
+            break;
+        case 's':
+            if (sscanf(optarg, "%d", &o.slot) != 1 || o.slot < 0 ||
+                o.slot >= crypt_keyslot_max(CRYPT_LUKS1)) {
+                fprintf(stderr, "Invalid slot (%s)\n", optarg);
+                return EX_USAGE;
+            }
+            break;
+        }
+    }
+
+    if (argc > 1 && !o.device) {
+        fprintf(stderr, "Device must be specified\n\n");
+        goto usage;
+    }
+
+    if (optind != argc - 1)
+        goto usage;
+
+    for (size_t i = 0; argc > 1 && commands[i].name; i++) {
+        struct crypt_device *cd = NULL;
+        const char *type = NULL;
+        int r = 0;
+
+        if (strcmp(argv[optind], commands[i].name) != 0)
+            continue;
+
+        r = crypt_init(&cd, o.device);
+        if (r != 0) {
+            fprintf(stderr, "Unable to open device (%s): %s\n",
+                    o.device, strerror(-r));
+            return EX_IOERR;
+        }
+
+        r = crypt_load(cd, NULL, NULL);
+        if (r != 0) {
+            fprintf(stderr, "Unable to read LUKSv1 header (%s): %s\n",
+                    o.device, strerror(-r));
+            crypt_free(cd);
+            return EX_IOERR;
+        }
+
+        type = crypt_get_type(cd);
+        if (type == NULL) {
+            fprintf(stderr, "Unable to determine device type for %s\n",
+                    o.device);
+            crypt_free(cd);
+            return EX_OSFILE;
+        }
+
+        if (strcmp(type, CRYPT_LUKS1) != 0) {
+            fprintf(stderr, "%s (%s) is not a LUKSv1 device\n", o.device, type);
+            crypt_free(cd);
+            return EX_OSFILE;
+        }
+
+        r = commands[i].func(&o, cd);
+        crypt_free(cd);
+        return r;
+    }
+
+    fprintf(stderr, "Invalid command\n\n");
+
+usage:
+    fprintf(stderr,
+            "Usage: luksmeta test -d DEVICE\n"
+            "   or: luksmeta nuke -d DEVICE [-f]\n"
+            "   or: luksmeta init -d DEVICE [-f] [-n]\n"
+            "   or: luksmeta show -d DEVICE [-s SLOT]\n"
+            "   or: luksmeta save -d DEVICE [-s SLOT]  -u UUID  < DATA\n"
+            "   or: luksmeta load -d DEVICE  -s SLOT  [-u UUID] > DATA\n"
+            "   or: luksmeta wipe -d DEVICE  -s SLOT  [-u UUID] [-f]\n");
+    return EX_USAGE;
+}

+ 131 - 0
luksmeta.h

@@ -0,0 +1,131 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <libcryptsetup.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint8_t luksmeta_uuid_t[16];
+
+/**
+ * Checks for the existence of a valid LUKSMeta header on a LUKSv1 device
+ *
+ * @param cd crypt device handle
+ * @return Zero on success or negative errno value otherwise.
+ *
+ * @note This function returns -ENOENT if the device has no luksmeta header.
+ * @note This function returns -EINVAL if the header or slot data is corrupted.
+ */
+int
+luksmeta_test(struct crypt_device *cd);
+
+/**
+ * Zeroes the entire LUKSMeta storage space.
+ *
+ * @param cd crypt device handle
+ * @return Zero on success or negative errno value otherwise.
+ */
+int
+luksmeta_nuke(struct crypt_device *cd);
+
+/**
+ * Initializes metadata storage on a LUKSv1 device
+ *
+ * @param cd crypt device handle
+ * @return Zero on success or negative errno value otherwise.
+ *
+ * @note This function returns -EALREADY if a valid header already exists.
+ * @note This function returns -ENOSPC if there is insufficient space.
+ */
+int
+luksmeta_init(struct crypt_device *cd);
+
+/**
+ * Gets metadata from the specified slot
+ *
+ * If buf is NULL, this function returns the size of the buffer needed and
+ * the uuid.
+ *
+ * @param cd crypt device handle
+ * @param slot requested metadata slot
+ * @param uuid the UUID of the metadata (output)
+ * @param buf output buffer for metadata (output)
+ * @param size size of buf
+ * @return The number of bytes in the metadata or negative errno value.
+ *
+ * @note This function returns -ENOENT if the device has no luksmeta header.
+ * @note This function returns -EINVAL if the header or slot data is corrupted.
+ * @note This function returns -EBADSLT if the specified slot is invalid.
+ * @note This function returns -ENODATA if the specified slot is empty.
+ * @note This function returns -E2BIG if the output buffer is too small.
+ */
+int
+luksmeta_load(struct crypt_device *cd, int slot,
+              luksmeta_uuid_t uuid, void *buf, size_t size);
+
+/**
+ * Sets metadata to the specified slot
+ *
+ * The slot parameter may be CRYPT_ANY_SLOT.
+ *
+ * @param cd crypt device handle
+ * @param slot requested metadata slot
+ * @param uuid UUID of the metadata
+ * @param buf input buffer for metadata
+ * @param size size of buf
+ * @return The slot number to which data was written or negative errno value.
+ *
+ * @note This function returns -ENOENT if the device has no luksmeta header.
+ * @note This function returns -EINVAL if the header is corrupted.
+ * @note This function returns -EBADSLT if the specified slot is invalid.
+ * @note This function returns -EKEYREJECTED if the uuid is invalid/reserved.
+ * @note This function returns -EALREADY if the specified slot is not empty.
+ * @note This function returns -ENOSPC if there is insufficient space.
+ */
+int
+luksmeta_save(struct crypt_device *cd, int slot,
+              const luksmeta_uuid_t uuid, const void *buf, size_t size);
+
+/**
+ * Deletes metadata from the specified slot
+ *
+ * If uuid is not NULL, this function will confirm that the specified slot
+ * has a matching UUID before deletion.
+ *
+ * @param cd crypt device handle
+ * @param slot requested metadata slot
+ * @param uuid expected UUID (optional)
+ * @return Zero on success or negative errno value otherwise.
+ *
+ * @note This function returns -ENOENT if the device has no luksmeta header.
+ * @note This function returns -EINVAL if the header is corrupted.
+ * @note This function returns -EBADSLT if the specified slot is invalid.
+ * @note This function returns -EKEYREJECTED if the uuid doesn't match.
+ * @note This function returns -EALREADY if the specified slot is empty.
+ */
+int
+luksmeta_wipe(struct crypt_device *cd, int slot, const luksmeta_uuid_t uuid);
+
+#ifdef __cplusplus
+}
+#endif

+ 11 - 0
luksmeta.pc.in

@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=${prefix}/include
+
+Name: LUKS Meta
+Description: Library for storing metadata in the LUKS header
+Version: @VERSION@
+Requires: libcryptsetup
+Libs: -L${libdir} -lluksmeta
+Cflags: -I${includedir}

+ 215 - 0
missing

@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:

+ 29 - 0
test-crc32c.c

@@ -0,0 +1,29 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "crc32c.h"
+
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+    char test[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+    return crc32c(0, test, sizeof(test)) == 0xe3069283 ? 0 : 1;
+}

+ 148 - 0
test-driver

@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:

+ 37 - 0
test-lm-assumptions.c

@@ -0,0 +1,37 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include <assert.h>
+
+int
+main(int argc, char *argv[])
+{
+    crypt_free(test_format());
+
+    /* Test the layout state. */
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                    /* LUKS header */
+        END(1024),                    /* Rest of the file */
+    }));
+
+    unlink(filename);
+    return 0;
+}
+

+ 138 - 0
test-lm-big.c

@@ -0,0 +1,138 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const luksmeta_uuid_t UUID = {
+    0xd3, 0xd5, 0xf1, 0xe0, 0xa4, 0x6c, 0xbd, 0xf4,
+    0xca, 0x20, 0x30, 0x1f, 0xdd, 0xa0, 0xf7, 0xa8
+};
+
+static const uint8_t DATA[] = "DATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA"
+      "DATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATADATA";
+
+int
+main(int argc, char *argv[])
+{
+    uint8_t data[sizeof(DATA)] = {};
+    struct crypt_device *cd = NULL;
+    luksmeta_uuid_t uuid = {};
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    int r;
+
+    crypt_free(test_format());
+    cd = test_init();
+    test_hole(cd, &offset, &length);
+
+    /* Set the data. */
+    r = luksmeta_save(cd, CRYPT_ANY_SLOT, UUID, DATA, sizeof(DATA));
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "luksmeta_save()");
+
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        { offset + 4096, 4096 },       /* luksmeta slot 0 */
+        { offset + 8192, 4096 },       /* luksmeta slot 0 (cont) */
+        END(offset + 12288),           /* Rest of the file */
+    }));
+
+    assert(luksmeta_load(cd, r, uuid, data, sizeof(data)) == sizeof(data));
+    assert(memcmp(uuid, UUID, sizeof(UUID)) == 0);
+    assert(memcmp(data, DATA, sizeof(DATA)) == 0);
+
+    /* Delete the data. */
+    assert(luksmeta_wipe(cd, r, UUID) == 0);
+
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        END(offset + 4096),            /* Rest of the file */
+    }));
+
+    crypt_free(cd);
+    unlink(filename);
+    return 0;
+}

+ 116 - 0
test-lm-init.c

@@ -0,0 +1,116 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const luksmeta_uuid_t UUID = {
+    0xfb, 0x06, 0x8c, 0x1f, 0x68, 0x04, 0x87, 0x9f,
+    0xf4, 0xcd, 0x32, 0x25, 0xb2, 0x1a, 0x7e, 0xf8
+};
+
+int
+main(int argc, char *argv[])
+{
+    uint8_t data[sizeof(UUID)] = {};
+    struct crypt_device *cd = NULL;
+    luksmeta_uuid_t uuid = {};
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    int fd;
+
+    /* Test for -ENOENT when there is no luksmeta header. */
+    cd = test_format();
+    for (int slot = 0; slot < crypt_keyslot_max(CRYPT_LUKS1); slot++) {
+        assert(luksmeta_save(cd, slot, UUID, UUID, sizeof(UUID)) == -ENOENT);
+        assert(luksmeta_load(cd, slot, uuid, data, sizeof(data)) == -ENOENT);
+        assert(luksmeta_wipe(cd, slot, UUID) == -ENOENT);
+        assert(luksmeta_test(cd) == -ENOENT);
+    }
+    crypt_free(cd);
+
+    cd = test_init();
+    test_hole(cd, &offset, &length);
+
+    /* Test the layout state. */
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        END(offset + 4096),            /* Rest of the file */
+    }));
+
+    /* Test error codes for a valid luksmeta header but no slot. */
+    for (int slot = 0; slot < crypt_keyslot_max(CRYPT_LUKS1); slot++) {
+        assert(luksmeta_load(cd, slot, uuid, data, sizeof(data)) == -ENODATA);
+        assert(luksmeta_wipe(cd, slot, UUID) == -EALREADY);
+    }
+
+    /* Test for -EALREADY when a valid header is present. */
+    assert(luksmeta_init(cd) == -EALREADY);
+    assert(luksmeta_test(cd) == 0);
+
+    /* Test for -EBADSLT when an invalid slot is used. */
+    assert(luksmeta_save(cd, 10, UUID, UUID, sizeof(UUID)) == -EBADSLT);
+    assert(luksmeta_load(cd, 10, uuid, data, sizeof(data)) == -EBADSLT);
+    assert(luksmeta_wipe(cd, 10, UUID) == -EBADSLT);
+    assert(luksmeta_save(cd, -10, UUID, UUID, sizeof(UUID)) == -EBADSLT);
+    assert(luksmeta_load(cd, -10, uuid, data, sizeof(data)) == -EBADSLT);
+    assert(luksmeta_wipe(cd, -10, UUID) == -EBADSLT);
+    assert(luksmeta_load(cd, -1, uuid, data, sizeof(data)) == -EBADSLT);
+    assert(luksmeta_wipe(cd, -1, UUID) == -EBADSLT);
+
+    /* Test for -EKEYREJECTED when a reserved UUID is used. */
+    assert(luksmeta_save(cd, CRYPT_ANY_SLOT, (luksmeta_uuid_t) {},
+                        UUID, sizeof(UUID)) == -EKEYREJECTED);
+
+    /* Test to make sure that data corruption is picked up correctly. */
+    fd = open(filename, O_RDWR | O_SYNC);
+    if (fd < 0)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+    if (lseek(fd, offset + 16, SEEK_SET) == -1)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+    if (write(fd, &(char) { 17 }, 1) != 1)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+    close(fd);
+    assert(luksmeta_save(cd, 2, UUID, UUID, sizeof(UUID)) == -EINVAL);
+    assert(luksmeta_load(cd, 2, uuid, data, sizeof(data)) == -EINVAL);
+    assert(luksmeta_wipe(cd, 2, UUID) == -EINVAL);
+
+    /* Test nuking */
+    assert(luksmeta_init(cd) == 0);
+    assert(luksmeta_test(cd) == 0);
+    assert(luksmeta_nuke(cd) == 0);
+    assert(luksmeta_test(cd) == -ENOENT);
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        END(offset),                   /* Rest of the file */
+    }));
+
+    crypt_free(cd);
+    unlink(filename);
+    return 0;
+}

+ 79 - 0
test-lm-one.c

@@ -0,0 +1,79 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include <error.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const luksmeta_uuid_t UUID = {
+    0xb0, 0xcc, 0xe0, 0x48, 0x89, 0x32, 0x90, 0x7e,
+    0x10, 0xd9, 0x62, 0xa2, 0x09, 0x3c, 0x05, 0x7d
+};
+
+int
+main(int argc, char *argv[])
+{
+    uint8_t data[sizeof(UUID)] = {};
+    struct crypt_device *cd = NULL;
+    luksmeta_uuid_t uuid = {};
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    int r;
+
+    crypt_free(test_format());
+    cd = test_init();
+    test_hole(cd, &offset, &length);
+
+    r = luksmeta_save(cd, CRYPT_ANY_SLOT, UUID, UUID, sizeof(UUID));
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    /* Test the layout state. */
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        { offset + 4096, 4096 },       /* luksmeta slot 0 */
+        END(offset + 8192),            /* Rest of the file */
+    }));
+
+    assert(luksmeta_load(cd, r, uuid, data, sizeof(data)) == sizeof(data));
+    assert(memcmp(uuid, UUID, sizeof(UUID)) == 0);
+    assert(memcmp(data, UUID, sizeof(UUID)) == 0);
+    assert(luksmeta_save(cd, r, UUID, UUID, sizeof(UUID)) == -EALREADY);
+    assert(luksmeta_wipe(cd, r, (luksmeta_uuid_t) {}) == -EKEYREJECTED);
+    assert(luksmeta_wipe(cd, r, (luksmeta_uuid_t) { 1 }) == -EKEYREJECTED);
+    assert(luksmeta_wipe(cd, r, UUID) == 0);
+    assert(luksmeta_wipe(cd, r, UUID) == -EALREADY);
+    assert(luksmeta_wipe(cd, r, (luksmeta_uuid_t) {}) == -EALREADY);
+
+    /* Test the layout state. */
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        END(offset + 4096),            /* Rest of the file */
+    }));
+
+    crypt_free(cd);
+    unlink(filename);
+    return 0;
+}

+ 110 - 0
test-lm-two.c

@@ -0,0 +1,110 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const luksmeta_uuid_t UUID0 = {
+    0x35, 0x08, 0x50, 0xc3, 0x25, 0xc9, 0x85, 0xea,
+    0x1b, 0x55, 0x93, 0x56, 0x36, 0x2a, 0xd9, 0x85
+};
+
+static const luksmeta_uuid_t UUID1 = {
+    0xb4, 0xcb, 0x8c, 0x1c, 0x34, 0xea, 0xcc, 0x21,
+    0x0b, 0x9c, 0xc3, 0x9c, 0x9a, 0x09, 0xc0, 0x0f
+};
+
+int
+main(int argc, char *argv[])
+{
+    uint8_t data[sizeof(UUID0)] = {};
+    struct crypt_device *cd = NULL;
+    luksmeta_uuid_t uuid = {};
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    int r;
+
+    crypt_free(test_format());
+    cd = test_init();
+    test_hole(cd, &offset, &length);
+
+    /* Add one metadata. */
+    r = luksmeta_save(cd, 0, UUID0, UUID0, sizeof(UUID0));
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "luksmeta_save()");
+
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        { offset + 4096, 4096 },       /* luksmeta slot 0 */
+        END(offset + 8192),            /* Rest of the file */
+    }));
+
+    assert(luksmeta_load(cd, 0, uuid, data, sizeof(data)) == sizeof(data));
+    assert(memcmp(uuid, UUID0, sizeof(UUID0)) == 0);
+    assert(memcmp(data, UUID0, sizeof(UUID0)) == 0);
+
+    /* Add a second metadata. */
+    r = luksmeta_save(cd, 1, UUID1, UUID1, sizeof(UUID1));
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "luksmeta_save()");
+
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        { offset + 4096, 4096 },       /* luksmeta slot 0 */
+        { offset + 8192, 4096 },       /* luksmeta slot 1 */
+        END(offset + 12288),           /* Rest of the file */
+    }));
+
+    assert(luksmeta_load(cd, 0, uuid, data, sizeof(data)) == sizeof(data));
+    assert(memcmp(uuid, UUID0, sizeof(UUID0)) == 0);
+    assert(memcmp(data, UUID0, sizeof(UUID0)) == 0);
+    assert(luksmeta_load(cd, 1, uuid, data, sizeof(data)) == sizeof(data));
+    assert(memcmp(uuid, UUID1, sizeof(UUID1)) == 0);
+    assert(memcmp(data, UUID1, sizeof(UUID1)) == 0);
+
+    /* Delete the first metadata. */
+    assert(luksmeta_wipe(cd, 0, UUID0) == 0);
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        { offset + 4096, 4096, true }, /* luksmeta slot 0 */
+        { offset + 8192, 4096 },       /* luksmeta slot 1 */
+        END(offset + 12288),           /* Rest of the file */
+    }));
+
+    /* Delete the second metadata. */
+    assert(luksmeta_wipe(cd, 1, UUID1) == 0);
+    assert(test_layout((range_t[]) {
+        { 0, 1024 },                   /* LUKS header */
+        { 1024, offset - 1024, true }, /* Keyslot Area */
+        { offset, 4096 },              /* luksmeta header */
+        END(offset + 4096),            /* Rest of the file */
+    }));
+
+    crypt_free(cd);
+    unlink(filename);
+    return 0;
+}

+ 52 - 0
test-luksmeta

@@ -0,0 +1,52 @@
+#!/bin/bash -x
+
+trap 'exit' ERR
+
+export tmp=`mktemp /tmp/luksmeta.XXXXXXXXXX`
+
+function onexit() {
+    rm -f $tmp
+}
+
+trap 'onexit' EXIT
+
+truncate -s 4M $tmp
+echo -n foo | cryptsetup luksFormat $tmp -
+
+! ./luksmeta test -d $tmp
+
+./luksmeta init -f -d $tmp
+./luksmeta test -d $tmp
+./luksmeta init -f -d $tmp
+
+for slot in `seq 0 7`; do
+    test "`./luksmeta show -s $slot -d $tmp`" == ""
+
+    echo hi | ./luksmeta save -s $slot -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp
+    test "`./luksmeta show -s $slot -d $tmp`" == "23149359-1b61-4803-b818-774ab730fbec"
+
+    test "`./luksmeta load -s $slot -d $tmp`" == "hi"
+    test "`./luksmeta load -s $slot -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp`" == "hi"
+    ! ./luksmeta load -s $slot -u 23149359-1b61-4803-b818-774ab730fbed -d $tmp
+
+    ! ./luksmeta wipe -f -s $slot -u 23149359-1b61-4803-b818-774ab730fbed -d $tmp
+    ./luksmeta wipe -f -s $slot -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp
+    ! ./luksmeta load -s $slot -d $tmp
+
+    echo hi | ./luksmeta save -s $slot -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp
+    ./luksmeta wipe -f -s $slot -d $tmp
+    ! ./luksmeta load -s $slot -d $tmp
+done
+
+# Test nuking
+./luksmeta test -d $tmp
+./luksmeta init -f -d $tmp
+./luksmeta nuke -f -d $tmp
+! ./luksmeta test -d $tmp
+
+# Test implicit nuking
+./luksmeta init -f -d $tmp
+echo hi | ./luksmeta save -s 0 -u 23149359-1b61-4803-b818-774ab730fbec -d $tmp
+test "`./luksmeta load -s 0 -d $tmp`" == "hi"
+./luksmeta init -n -f -d $tmp
+! ./luksmeta load -s 0 -d $tmp

+ 176 - 0
test.c

@@ -0,0 +1,176 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "test.h"
+
+char filename[] = "/tmp/luksmetaXXXXXX";
+
+static size_t
+first_nonzero(FILE *file, size_t start, size_t length)
+{
+    uint8_t *buffer;
+
+    buffer = malloc(length);
+    if (!buffer)
+        return false;
+
+    if (fseek(file, start, SEEK_SET) != 0) {
+        free(buffer);
+        return false;
+    }
+
+    if (fread(buffer, length, 1, file) != 1) {
+        free(buffer);
+        return false;
+    }
+
+    for (size_t i = 0; i < length; i++) {
+        if (buffer[i] != 0) {
+            free(buffer);
+            return i;
+        }
+    }
+
+    free(buffer);
+    return length;
+}
+
+bool
+test_layout(range_t *ranges)
+{
+    bool valid = false;
+    FILE *file = NULL;
+
+    file = fopen(filename, "r");
+    if (!file)
+        return false;
+
+    for (size_t i = 0; ranges[i].length != 0; i++) {
+        size_t nonzero;
+
+        fprintf(stderr, "%08zu:%08zu (%c= 0)\n",
+                ranges[i].start, ranges[i].start + ranges[i].length,
+                ranges[i].zero ? '=' : '!');
+
+        nonzero = first_nonzero(file, ranges[i].start, ranges[i].length);
+        if (ranges[i].zero && nonzero < ranges[i].length) {
+            fprintf(stderr, "unexpected nonzero: %zu\n", nonzero);
+            goto egress;
+        } else if (!ranges[i].zero && nonzero == ranges[i].length) {
+            fprintf(stderr, "unexpected zero: %zu-%zu\n",
+                    ranges[i].start, ranges[i].start + ranges[i].length);
+            goto egress;
+        }
+    }
+
+    valid = true;
+
+egress:
+    fclose(file);
+    return valid;
+
+}
+
+void
+test_hole(struct crypt_device *cd, uint32_t *offset, uint32_t *length)
+{
+    uint64_t payload_offset = 0;
+    uint64_t keyarea_end = 0;
+    int r = 0;
+
+    payload_offset = crypt_get_data_offset(cd) * 512;
+    if (payload_offset < ALIGN(1, true))
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    for (int slot = 0; slot < crypt_keyslot_max(CRYPT_LUKS1); slot++) {
+        uint64_t off = 0;
+        uint64_t len = 0;
+
+        r = crypt_keyslot_area(cd, slot, &off, &len);
+        if (r < 0)
+            error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+        if (off + len > keyarea_end)
+            keyarea_end = off + len;
+    }
+
+    *offset = ALIGN(keyarea_end, true);
+    *length = ALIGN(payload_offset, false) - *offset;
+}
+
+struct crypt_device *
+test_format(void)
+{
+    struct crypt_device *cd = NULL;
+    int fd;
+    int r;
+
+    fd = mkstemp(filename);
+    if (fd < 0)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+
+    /* Create a 4MB sparse file. */
+    if (lseek(fd, 4194303, SEEK_SET) == -1)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+    if (write(fd, "", 1) != 1)
+        error(EXIT_FAILURE, errno, "%s:%d", __FILE__, __LINE__);
+    close(fd);
+
+    r = crypt_init(&cd, filename);
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    r = crypt_format(cd, CRYPT_LUKS1, "aes", "xts-plain64",
+                     NULL, NULL, 32, NULL);
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    return cd;
+}
+
+struct crypt_device *
+test_init(void)
+{
+    struct crypt_device *cd = NULL;
+    int r;
+
+    r = crypt_init(&cd, filename);
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    r = crypt_load(cd, CRYPT_LUKS1, NULL);
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    r = luksmeta_init(cd);
+    if (r < 0)
+        error(EXIT_FAILURE, -r, "%s:%d", __FILE__, __LINE__);
+
+    return cd;
+}
+

+ 49 - 0
test.h

@@ -0,0 +1,49 @@
+/* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
+/*
+ * Copyright (c) 2016 Red Hat, Inc.
+ * Author: Nathaniel McCallum <npmccallum@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "luksmeta.h"
+#include <stdbool.h>
+
+#include <assert.h> /* All tests need assert() */
+#include <unistd.h> /* All tests need unlink() */
+
+#define FILESIZE 4194304
+#define END(s) { (s), FILESIZE - (s), true }, { 0, 0 }
+#define ALIGN(s, up) (((s) + (up ? 4095 : 0)) & ~4095ULL)
+
+typedef struct {
+    size_t start;
+    size_t length;
+    bool zero;
+} range_t;
+
+extern char filename[];
+
+bool
+test_layout(range_t *ranges);
+
+void
+test_hole(struct crypt_device *cd, uint32_t *offset, uint32_t *length);
+
+struct crypt_device *
+test_format(void);
+
+struct crypt_device *
+test_init(void);
+